mirror of
https://github.com/ant-design/ant-design.git
synced 2026-02-09 10:59:19 +08:00
Compare commits
278 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef8ea979b4 | ||
|
|
26f9d63d85 | ||
|
|
322098487f | ||
|
|
ff1b5c279d | ||
|
|
ab6a4ec1c0 | ||
|
|
8d9d86c433 | ||
|
|
8ea1e52d4d | ||
|
|
16075f85b4 | ||
|
|
09f8df94b4 | ||
|
|
60103e12a3 | ||
|
|
c28d0f85ad | ||
|
|
261018053f | ||
|
|
e234a71ecd | ||
|
|
ea251a50fa | ||
|
|
d4fd8f2698 | ||
|
|
1113867378 | ||
|
|
c72ee71d6f | ||
|
|
fb9d2e6738 | ||
|
|
274871b50c | ||
|
|
b4e748c28a | ||
|
|
77e7eceb91 | ||
|
|
179ee276c9 | ||
|
|
acc2e03ddf | ||
|
|
3770b3f423 | ||
|
|
0b592203b2 | ||
|
|
1c38e68a0f | ||
|
|
771352c5ca | ||
|
|
bd25b9f667 | ||
|
|
8f1cfd2062 | ||
|
|
0a3af0b2e2 | ||
|
|
e883e4ba40 | ||
|
|
43e2651b9c | ||
|
|
d3bf6eef94 | ||
|
|
50d8c38f2c | ||
|
|
6bdd7c1b66 | ||
|
|
2beb594b71 | ||
|
|
f6769e3e94 | ||
|
|
c7e51aba13 | ||
|
|
ea48827e06 | ||
|
|
3ef6ea3ead | ||
|
|
a04d13c0b9 | ||
|
|
4bcac2d986 | ||
|
|
6288f0a86e | ||
|
|
b896556823 | ||
|
|
0051e5d883 | ||
|
|
e1509b0402 | ||
|
|
e465f3e890 | ||
|
|
88fde9f9f7 | ||
|
|
5e4a79a0f0 | ||
|
|
7004afe3ba | ||
|
|
18c4b085ba | ||
|
|
f487d8dba8 | ||
|
|
f0f39895b5 | ||
|
|
852b28c235 | ||
|
|
b64d02fda9 | ||
|
|
1f0d074caa | ||
|
|
41d520ab82 | ||
|
|
1a4f5f7909 | ||
|
|
02fc6b1646 | ||
|
|
de447ea758 | ||
|
|
679f0529fa | ||
|
|
3a7273b5da | ||
|
|
340a0a913a | ||
|
|
94cab40b04 | ||
|
|
5db8813c64 | ||
|
|
2d676fb528 | ||
|
|
0fec3aa602 | ||
|
|
5909a4dae5 | ||
|
|
4bf062c2a8 | ||
|
|
2ed5a1e9d1 | ||
|
|
68a1b18232 | ||
|
|
138b953afd | ||
|
|
60e35181fc | ||
|
|
dfbe4b701c | ||
|
|
f28f56d096 | ||
|
|
4107c83234 | ||
|
|
a711a4172d | ||
|
|
7662160880 | ||
|
|
dcd97ca46e | ||
|
|
f812855122 | ||
|
|
5f2588ffd1 | ||
|
|
b173b5b8f5 | ||
|
|
df8c53d145 | ||
|
|
b651178685 | ||
|
|
2eec689d74 | ||
|
|
a2a4fa302d | ||
|
|
f3f5b66957 | ||
|
|
820aa04a96 | ||
|
|
f1c75c5ef6 | ||
|
|
20efc58a8a | ||
|
|
fa3c00ce1a | ||
|
|
514cc062be | ||
|
|
1a594a467e | ||
|
|
f07613a9c2 | ||
|
|
08ca032550 | ||
|
|
ef3aabdf7d | ||
|
|
88fc56fde8 | ||
|
|
9cd432e52e | ||
|
|
1aee1670cf | ||
|
|
bd62870258 | ||
|
|
4f177ddc96 | ||
|
|
76a85ca14e | ||
|
|
0ddd367b51 | ||
|
|
39cf26f4fb | ||
|
|
26c5c6e533 | ||
|
|
cf717225d1 | ||
|
|
93a8605236 | ||
|
|
0e4360038e | ||
|
|
442c146e3c | ||
|
|
f6c2ffcc8f | ||
|
|
e5eb7de417 | ||
|
|
01d757b660 | ||
|
|
493d1b148d | ||
|
|
20f04e428f | ||
|
|
3d5f9b0ac5 | ||
|
|
78b7c01048 | ||
|
|
ab33429bf6 | ||
|
|
46bbad77c4 | ||
|
|
c7d376001a | ||
|
|
14ef846eb7 | ||
|
|
cc37f7d189 | ||
|
|
006abe5e92 | ||
|
|
0a3369c0eb | ||
|
|
40c8fb8363 | ||
|
|
aac1d4e434 | ||
|
|
80d36fb0ae | ||
|
|
2775049345 | ||
|
|
1e176ed841 | ||
|
|
5e0352200b | ||
|
|
efc304c55a | ||
|
|
8e14a9ce9c | ||
|
|
f2766df2e1 | ||
|
|
a733885b50 | ||
|
|
7b1327fa1e | ||
|
|
b696579cd4 | ||
|
|
358c7fa4c4 | ||
|
|
fc5e0a9155 | ||
|
|
7f2bdb7569 | ||
|
|
8315262804 | ||
|
|
93f2988585 | ||
|
|
fe6a6b0481 | ||
|
|
c979850a5b | ||
|
|
2aef2dbe26 | ||
|
|
b131c23fb6 | ||
|
|
dcdb8f5587 | ||
|
|
3ab71222ef | ||
|
|
b04d97cde2 | ||
|
|
40cee55141 | ||
|
|
ea3629deed | ||
|
|
83ddfb807e | ||
|
|
2e4cbba8d7 | ||
|
|
659a2d7701 | ||
|
|
e5e3be6dda | ||
|
|
a48e2a474f | ||
|
|
a8f9572944 | ||
|
|
ae466b9eea | ||
|
|
87059cd795 | ||
|
|
f0cefa57cd | ||
|
|
4d098e7803 | ||
|
|
f2a8712139 | ||
|
|
954bd94b63 | ||
|
|
e849c94b48 | ||
|
|
6882fa9498 | ||
|
|
d5954af85e | ||
|
|
05e05c59f6 | ||
|
|
3d9c4cf971 | ||
|
|
c592714c88 | ||
|
|
935773a0d0 | ||
|
|
2f736441af | ||
|
|
dfb3279949 | ||
|
|
90cfb0d25f | ||
|
|
5b5518acfb | ||
|
|
b08b759ff4 | ||
|
|
1da6016cc2 | ||
|
|
7f7fe176e1 | ||
|
|
fec45cb6fe | ||
|
|
8bff5917dc | ||
|
|
a9953640f9 | ||
|
|
bb11f82ed2 | ||
|
|
56fb794862 | ||
|
|
2980444bd6 | ||
|
|
cc6d2f2157 | ||
|
|
4a86b75c74 | ||
|
|
068d2bc902 | ||
|
|
780ada065b | ||
|
|
cefb877ab9 | ||
|
|
481fd209e2 | ||
|
|
0de1358924 | ||
|
|
e09040f3af | ||
|
|
704899415e | ||
|
|
ca18e8cd87 | ||
|
|
0067b923b9 | ||
|
|
bf910cb3a9 | ||
|
|
1e9aded2dd | ||
|
|
58a57224a8 | ||
|
|
8e84c739bf | ||
|
|
6a06104708 | ||
|
|
ab3d0ea8de | ||
|
|
737bd60f23 | ||
|
|
58a69bc02c | ||
|
|
aab9c135fb | ||
|
|
ad22d88550 | ||
|
|
add02767f0 | ||
|
|
1faabb219d | ||
|
|
ea19589619 | ||
|
|
5507641331 | ||
|
|
4270fc7e12 | ||
|
|
0472da5a40 | ||
|
|
75f50f9d17 | ||
|
|
faa534c1c0 | ||
|
|
bef89ce686 | ||
|
|
ce4dd06469 | ||
|
|
39b40b573d | ||
|
|
d98981b279 | ||
|
|
4fff7ec171 | ||
|
|
ca46793593 | ||
|
|
0b4563579b | ||
|
|
6fc11830d6 | ||
|
|
ad180b8dcf | ||
|
|
8ab74cbe0e | ||
|
|
498d48c6b1 | ||
|
|
37f6a2086a | ||
|
|
c58135fd46 | ||
|
|
b713f457f0 | ||
|
|
8ab8862907 | ||
|
|
c1d216be3d | ||
|
|
e745e24677 | ||
|
|
d5497dd47b | ||
|
|
eb46b026fe | ||
|
|
ce6d89e93a | ||
|
|
a26517f9ab | ||
|
|
7041af92fb | ||
|
|
e9d3ee6928 | ||
|
|
44f733ae23 | ||
|
|
e678582012 | ||
|
|
79b681d27c | ||
|
|
bf45c4c1b0 | ||
|
|
a46c5ce19b | ||
|
|
c630a6de69 | ||
|
|
b4c0978068 | ||
|
|
b2cd6c164a | ||
|
|
10f05d8358 | ||
|
|
7b55f112ce | ||
|
|
5baa4530cc | ||
|
|
a8dea916b2 | ||
|
|
a12a7ef2d8 | ||
|
|
16251d1de9 | ||
|
|
f0f22bb726 | ||
|
|
7e209f0a51 | ||
|
|
9663b24216 | ||
|
|
34887ca249 | ||
|
|
6d2854264a | ||
|
|
b0c70ab348 | ||
|
|
25f2bd66c8 | ||
|
|
a409f3126f | ||
|
|
0c521962e7 | ||
|
|
09e19b765d | ||
|
|
e5fe9b90df | ||
|
|
ff22827cb3 | ||
|
|
7a0320d978 | ||
|
|
a204040a07 | ||
|
|
05fc90c605 | ||
|
|
34d5112132 | ||
|
|
0097d34d01 | ||
|
|
b5d9580565 | ||
|
|
bc950d9a24 | ||
|
|
e2dda85c90 | ||
|
|
c88fd34e9a | ||
|
|
4976fef1b1 | ||
|
|
fdc36b6a69 | ||
|
|
97f7a972bf | ||
|
|
4a4b97c197 | ||
|
|
71f726afb1 | ||
|
|
f68c743448 | ||
|
|
2d46fb72ec | ||
|
|
9101f3666a | ||
|
|
a8b4e3c2e5 | ||
|
|
0874992243 |
11
.eslintrc.js
11
.eslintrc.js
@@ -113,11 +113,22 @@ module.exports = {
|
||||
|
||||
'jest/no-test-callback': 0,
|
||||
'jest/expect-expect': 0,
|
||||
'jest/no-done-callback': 0,
|
||||
'jest/valid-title': 0,
|
||||
'jest/no-conditional-expect': 0,
|
||||
|
||||
'unicorn/better-regex': 2,
|
||||
'unicorn/prefer-trim-start-end': 2,
|
||||
'unicorn/expiring-todo-comments': 2,
|
||||
'unicorn/no-abusive-eslint-disable': 2,
|
||||
|
||||
// https://github.com/typescript-eslint/typescript-eslint/issues/2540#issuecomment-692866111
|
||||
'no-use-before-define': 0,
|
||||
'@typescript-eslint/no-use-before-define': 2,
|
||||
'no-shadow': 0,
|
||||
'@typescript-eslint/no-shadow': [2, { ignoreTypeValueShadow: true }],
|
||||
// https://github.com/typescript-eslint/typescript-eslint/issues/2528#issuecomment-689369395
|
||||
'no-undef': 0,
|
||||
},
|
||||
globals: {
|
||||
gtag: true,
|
||||
|
||||
16
.github/workflows/auto-close.yml
vendored
Normal file
16
.github/workflows/auto-close.yml
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
name: 🧐 Auto Closer
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [labeled]
|
||||
|
||||
jobs:
|
||||
close-by-label:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.label.name == '3.x'
|
||||
steps:
|
||||
- name: Comment on issue
|
||||
uses: peter-evans/close-issue@v1
|
||||
with:
|
||||
comment: "Hi @${{ github.event.issue.user.login }},<br />Current branch is off the maintenance period. We may not accept pull request or fix bug with it anymore. This topic will be auto closed.<br /><br />你好 @${{ github.event.issue.user.login }},<br />当前分支已经过了维护期。我们不会再接受对其的相关 PR 与 issue。当前 topic 会被自动关闭。"
|
||||
|
||||
480
AUTHORS.txt
480
AUTHORS.txt
File diff suppressed because it is too large
Load Diff
@@ -15,6 +15,159 @@ timeline: true
|
||||
|
||||
---
|
||||
|
||||
## 4.7.2
|
||||
|
||||
`2020-10-19`
|
||||
|
||||
- 💄 Fix Layout.Sider `light` theme lost styles. [#27227](https://github.com/ant-design/ant-design/pull/27227) [@lingjieee](https://github.com/lingjieee)
|
||||
- 💄 Fix TextArea wrapped with additional div when `showCount` is `false`, and pass `className` and `style` to outer wrapper when `showCount` is `true`. [#27216](https://github.com/ant-design/ant-design/pull/27216)
|
||||
- 🐞 Fix Checkbox.Group TS2559 error. [#27231](https://github.com/ant-design/ant-design/pull/27231)
|
||||
|
||||
## 4.7.1
|
||||
|
||||
`2020-10-18`
|
||||
|
||||
- DatePicker
|
||||
- 🐞 Fix DatePicker don't work correctly when `showTime` is `true` and `format` is function. [#27156](https://github.com/ant-design/ant-design/pull/27156)
|
||||
- 💄 Fix DatePicker wrong animation direction when auto overflow. [#27101](https://github.com/ant-design/ant-design/pull/27101)
|
||||
- Typography
|
||||
- 💄 Fix Typography miss `pre` and `blockquote` style. [#27150](https://github.com/ant-design/ant-design/pull/27150)
|
||||
- 🐞 Fix Typography.Link hover color. [#27119](https://github.com/ant-design/ant-design/pull/27119)
|
||||
- 🐞 Fix Typography.Link hover color when type is danger. [#27104](https://github.com/ant-design/ant-design/pull/27104)
|
||||
- 💄 Fix Descriptions `ant-descriptions-item-content` and add style `word-break:break-word;`. [#27195](https://github.com/ant-design/ant-design/pull/27195) [@WLyKan](https://github.com/WLyKan)
|
||||
- 🐞 Fix clear Password value attribute in controlled mode. [#27191](https://github.com/ant-design/ant-design/pull/27191)
|
||||
- 🐞 Optimize Notification width in small screen. [#27189](https://github.com/ant-design/ant-design/pull/27189)
|
||||
- 🐞 Fix Cascader className duplicate. [#27187](https://github.com/ant-design/ant-design/pull/27187) [@huntdream](https://github.com/huntdream)
|
||||
- 🐞 Fix the issue that the Drawer will trigger form submit. [#27175](https://github.com/ant-design/ant-design/pull/27175)
|
||||
- 🐞 Fix Dropdown icon missing margin. [#27165](https://github.com/ant-design/ant-design/pull/27165)
|
||||
- 💄 Fix Layout.Sider `collapsedWidth` cannot work without modifying `@menu-collapsed-width`. [#27154](https://github.com/ant-design/ant-design/pull/27154)
|
||||
- 🐞 Fix Tabs `animated={true}` not working for panels. [#27145](https://github.com/ant-design/ant-design/pull/27145)
|
||||
- 🐞 Fix Divider color when contains text. [#27134](https://github.com/ant-design/ant-design/pull/27134)
|
||||
- 💄 Fix the cursor style when the Radio option is selected and disabled. [#27125](https://github.com/ant-design/ant-design/pull/27125)
|
||||
- 🇪🇸 Add missing translations in es_ES. [#27079](https://github.com/ant-design/ant-design/pull/27079) [@gersongams](https://github.com/gersongams)
|
||||
- RTL
|
||||
- 💄 Optimize the style of Input.TextArea character count in RTL mode. [#27098](https://github.com/ant-design/ant-design/pull/27098)
|
||||
- TypeScript
|
||||
- 🤖 Button shape remove undeclared doc type. [#27159](https://github.com/ant-design/ant-design/pull/27159)
|
||||
- 🤖 Add optional `rules` property into `FormListProps`. [#27164](https://github.com/ant-design/ant-design/pull/27164) [@huntdream](https://github.com/huntdream)
|
||||
|
||||
## 4.7.0
|
||||
|
||||
`2020-10-10`
|
||||
|
||||
- 🔥 Input.TextArea support word count. [#26952](https://github.com/ant-design/ant-design/pull/26952) [@zhangchen915](https://github.com/zhangchen915)
|
||||
- DatePicker
|
||||
- 🔥 DatePicker support custom `format` by passing a function. [#26845](https://github.com/ant-design/ant-design/pull/26845)
|
||||
- 🐞 Fix RangePicker initial date of end panel cannot selected. [#23167](https://github.com/ant-design/ant-design/issues/23167)
|
||||
- Form
|
||||
- 🔥 Form.Item support `tooltip` to customize tooltip. [#26780](https://github.com/ant-design/ant-design/pull/26780)
|
||||
- 🆕 Form.List support `rules` validation and add Form.ErrorList to show the errors. [#26676](https://github.com/ant-design/ant-design/pull/26676)
|
||||
- 🆕 Form.Item support `messageVariables` prop. [#26597](https://github.com/ant-design/ant-design/pull/26597)
|
||||
- 🐞 Fix Form `onValuesChange` second param return fully `store` values instead of validate fields. [#26808](https://github.com/ant-design/ant-design/pull/26808)
|
||||
- Upload
|
||||
- 🔥 Upload can custom the item of file list by `itemRender` now. [#26333](https://github.com/ant-design/ant-design/pull/26333)
|
||||
- 🆕 Upload custom action icons now supports callback functions. [#26684](https://github.com/ant-design/ant-design/pull/26684) [@mwaddell](https://github.com/mwaddell)
|
||||
- Table
|
||||
- 🆕 Table `sticky` now support `getContainer`. [#26973](https://github.com/ant-design/ant-design/pull/26973)
|
||||
- 🐞 Fix Table should not render dropdown filter icon when filterDropdown is `undefined`. [#27002](https://github.com/ant-design/ant-design/pull/27002) [@shangyilim](https://github.com/shangyilim)
|
||||
- Modal
|
||||
- 🛠 Refactor Modal animation code so that it will remove all dom element by `destroyOnClose` when closed. [#26940](https://github.com/ant-design/ant-design/pull/26940)
|
||||
- 🆕 Modal add `modalRender` prop which can be used for draggable dialog. [#26507](https://github.com/ant-design/ant-design/pull/26507) [@jhoneybee](https://github.com/jhoneybee)
|
||||
- 🆕 Space add `split` prop. [#26948](https://github.com/ant-design/ant-design/pull/26948)
|
||||
- 🆕 Image `preview` prop now support `visible` and `onVisibleChange`. [#26915](https://github.com/ant-design/ant-design/pull/26915)
|
||||
- 🆕 InputNumber will trigger `onStep` prop when click up/down buttons. [#27075](https://github.com/ant-design/ant-design/pull/27075)
|
||||
- 🆕 Avatar `size` support responsive config. [#26244](https://github.com/ant-design/ant-design/pull/26244) [@willamesoares](https://github.com/willamesoares)
|
||||
- 🐞 Fix Radio.Button children cannot apply Tooltip. [#27050](https://github.com/ant-design/ant-design/pull/27050)
|
||||
- RTL
|
||||
- ⬅️ Fix List action button position in RTL mode. [#26964](https://github.com/ant-design/ant-design/pull/26964)
|
||||
- ⬅️ Fix Transfer pagination style in RTL mode. [#26960](https://github.com/ant-design/ant-design/pull/26960)
|
||||
- ⬅️ Fix Upload style in RTL mode. [#26961](https://github.com/ant-design/ant-design/pull/26961)
|
||||
- ⬅️ Optimize Tag style to avoid the interaction between theme and RTL mode. [#26955](https://github.com/ant-design/ant-design/pull/26955)
|
||||
- ⬅️ Optimize Cascader and Tree style of the data expansion loading icon in RTL mode. [#27010](https://github.com/ant-design/ant-design/pull/27010)
|
||||
- TypeScript
|
||||
- 🤖 Fix typo `TimeLineItemProps` to `TimelineItemProps`. [#27001](https://github.com/ant-design/ant-design/pull/27001) [@mgcrea](https://github.com/mgcrea)
|
||||
- 🤖 Fix Slider missing `autoFocus` prop. [#26995](https://github.com/ant-design/ant-design/pull/26995) [@shangyilim](https://github.com/shangyilim)
|
||||
- 🤖 Fix Slider `step` prop not accepting `null` value. [#26984](https://github.com/ant-design/ant-design/pull/26984) [@shangyilim](https://github.com/shangyilim)
|
||||
- 🤖 Fix Slider.Range `trackStyle` and `handleStyle` should be array. [#27033](https://github.com/ant-design/ant-design/pull/27033)
|
||||
- 🤖 Optimize Tag `onClose` TypeScript definition. [#26932](https://github.com/ant-design/ant-design/pull/26932)
|
||||
- 🤖 Improve Form TypeScript definition to support `getFieldsValue` return generic type without `namePath` argument. [#26791](https://github.com/ant-design/ant-design/pull/26791)
|
||||
- Locale
|
||||
- 🇧🇾 Add Belarusian locale. [#27028](https://github.com/ant-design/ant-design/pull/27028) [@StIvan8](https://github.com/StIvan8)
|
||||
- 🇯🇵 Fix Japanese locale. [#27043](https://github.com/ant-design/ant-design/pull/27043) [@iorikingdom](https://github.com/iorikingdom)
|
||||
- 🇹🇭 Add Thai locale for Pickers. [#26993](https://github.com/ant-design/ant-design/pull/26993) [@anawinwz](https://github.com/anawinwz)
|
||||
- 🇹🇷 Add Turkish locale of Form optional text. [#27017](https://github.com/ant-design/ant-design/pull/27017) [@alperTunca](https://github.com/alperTunca)
|
||||
- 🇵🇱 Add Polish locale of Table. [#26913](https://github.com/ant-design/ant-design/pull/26913) [@daczczcz1](https://github.com/daczczcz1)
|
||||
|
||||
## 4.6.6
|
||||
|
||||
`2020-09-27`
|
||||
|
||||
- 🐞 Fix Steps first item shifts in small screen. [#26894](https://github.com/ant-design/ant-design/pull/26894)
|
||||
- 💄 Fix Divider border style not work when text is provided. [#26863](https://github.com/ant-design/ant-design/pull/26863)
|
||||
- 🐞 Fix Radio.Button validation error highlight. [#26849](https://github.com/ant-design/ant-design/pull/26849) [@dhorelik](https://github.com/dhorelik)
|
||||
- 💄 Fix Typography link-decoration style. [#26854](https://github.com/ant-design/ant-design/pull/26854) [@vineetvk01](https://github.com/vineetvk01)
|
||||
- Locale
|
||||
- 🌐 Add Thai locale support. [#26906](https://github.com/ant-design/ant-design/pull/26906) [@anawinwz](https://github.com/anawinwz)
|
||||
- TypeScript
|
||||
- 🤖 Fix message.destroy parameter type. [#26864](https://github.com/ant-design/ant-design/pull/26864) [@lihqi](https://github.com/lihqi)
|
||||
- 🤖 Optimize Slider type definition. [#26884](https://github.com/ant-design/ant-design/pull/26884)
|
||||
- 🤖 Form properly export `FormListProps` type. [#26831](https://github.com/ant-design/ant-design/pull/26831) [@mgcrea](https://github.com/mgcrea)
|
||||
|
||||
## 4.6.5
|
||||
|
||||
`2020-09-20`
|
||||
|
||||
- 💄 Fix Descriptions item long text ellipsis issue. [#26820](https://github.com/ant-design/ant-design/pull/26820)
|
||||
- 🐞 Fix Menu unexpected scrollbar when show and hide. [#26817](https://github.com/ant-design/ant-design/pull/26817)
|
||||
- 🐞 Fix `@layout-sider-background` cannot set to linear gradient color. [#26810](https://github.com/ant-design/ant-design/pull/26810)
|
||||
- 🐞 Fix Select compositing status lost when input first letter in Chinese. [#26796](https://github.com/ant-design/ant-design/pull/26796)
|
||||
- 🐞 Fix Table `@table-sticky-zindex` less compile error issue. [#26800](https://github.com/ant-design/ant-design/pull/26800) [@chimp1nski](https://github.com/chimp1nski)
|
||||
- Button
|
||||
- 💄 Fix Button align issue when has icon only. [#26785](https://github.com/ant-design/ant-design/pull/26785)
|
||||
- 🐞 Fix Button warning `Invalid value for prop navigate` when using with react-router. [#26740](https://github.com/ant-design/ant-design/pull/26740) [@knobo](https://github.com/knobo)
|
||||
- 💄 Fix TimePicker column align issue, add `@picker-time-panel-column-width` and `@picker-time-panel-column-height` less variables. [#26784](https://github.com/ant-design/ant-design/pull/26784)
|
||||
- 🐞 Fix AutoComplete warning when using `placeholder` and `allowClear`. [#26765](https://github.com/ant-design/ant-design/pull/26765)
|
||||
- 🐞 Fix Space show items when it's render empty dom. [#26721](https://github.com/ant-design/ant-design/pull/26721) [@knobo](https://github.com/knobo)
|
||||
- 🛠 Dedupe `rc-trigger` version to reduce package size. [#26803](https://github.com/ant-design/ant-design/pull/26803)
|
||||
- TypeScript
|
||||
- 🤖 Cascader add `name` and `id` props definition. [#26660](https://github.com/ant-design/ant-design/pull/26660) [@alwaysloseall](https://github.com/alwaysloseall)
|
||||
|
||||
## 4.6.4
|
||||
|
||||
`2020-09-13`
|
||||
|
||||
- 💄 style: Card card image has extra 1px border. [#26659](https://github.com/ant-design/ant-design/pull/26659)
|
||||
- 💄 Fix Select `placeholder` color not same as Input. [#26651](https://github.com/ant-design/ant-design/pull/26651) [@wangcch](https://github.com/wangcch)
|
||||
- 🐞 Fix Menu not support React.Fragment inside. [#26656](https://github.com/ant-design/ant-design/pull/26656)
|
||||
- 🐞 Fix TextArea different behavior with Input when set `value` to `undefined`. [#26652](https://github.com/ant-design/ant-design/pull/26652)
|
||||
- 🐞 Fix Motion related issue like Upload align flash and Form.Item with `help` ssr issue. [#26628](https://github.com/ant-design/ant-design/pull/26628)
|
||||
- 🐞 Fix Typography.Link warning `Invalid value for prop navigate` when using with react-router. [#26623](https://github.com/ant-design/ant-design/pull/26623)
|
||||
- 🐞 Fix Table pagination missing when is above table. [#26618](https://github.com/ant-design/ant-design/pull/26618)
|
||||
- 🐞 Fix Upload in control miss file when upload multiple file in same time. [#26612](https://github.com/ant-design/ant-design/pull/26612)
|
||||
- TypeScript
|
||||
- 🤖 Fix Table that sorter `compare` and `multiple` should be optional. [#26686](https://github.com/ant-design/ant-design/pull/26686)
|
||||
|
||||
## 4.6.3
|
||||
|
||||
`2020-09-06`
|
||||
|
||||
- 🛎 Sort props `className` to the end. [#26602](https://github.com/ant-design/ant-design/pull/26602)
|
||||
- Table
|
||||
- 💄 Fix Table nested table styles affects all sub-level tables. [#26568](https://github.com/ant-design/ant-design/pull/26568) [@willc001](https://github.com/willc001)
|
||||
- 🐞 Fix elements above Table was not clickable elements which has `float: right;` style. [#26599](https://github.com/ant-design/ant-design/pull/26599)
|
||||
- 🐞 Fix Modal closing cause scroll position jump up. [#26538](https://github.com/ant-design/ant-design/pull/26538)
|
||||
- 🐞 Fix the type declaration of onError in `customRequest` options of Upload. [#26601](https://github.com/ant-design/ant-design/pull/26601) [@yingpengsha](https://github.com/yingpengsha)
|
||||
- 🐞 Shutdown Select/TreeSelect autocomplete list in Chrome. [#26590](https://github.com/ant-design/ant-design/pull/26590)
|
||||
- 🐞 Fix Cascader value overwritten when filtering. [#26569](https://github.com/ant-design/ant-design/pull/26569) [@lich-yoo](https://github.com/lich-yoo)
|
||||
- 🐞 Fix Modal jump out of screen in some situations. [#25765](https://github.com/ant-design/ant-design/pull/25765) [@tanmoyopenroot](https://github.com/tanmoyopenroot)
|
||||
- 🐞 Fix Radio.Group not working properly, when is used in legacy Form. [#26555](https://github.com/ant-design/ant-design/pull/26555) [@willc001](https://github.com/willc001)
|
||||
- 🐞 Fix Pagination align issue in windows. [#26549](https://github.com/ant-design/ant-design/pull/26549)
|
||||
- 🐞 Fix Form with `help` make ssr un-sync issue. [#26542](https://github.com/ant-design/ant-design/pull/26542)
|
||||
- 🐞 Fix Avatar doesn't scale fallback text well when display is none. [#26522](https://github.com/ant-design/ant-design/pull/26522) [@zhangyu1818](https://github.com/zhangyu1818)
|
||||
- TypeScript
|
||||
- 🤖 Col Add `flex` type to `ColSize` interface. [#26578](https://github.com/ant-design/ant-design/pull/26578) [@blaiz](https://github.com/blaiz)
|
||||
- 🤖 Fix Tooltip/Popover `children` tsd to accept ReactNode. [#26534](https://github.com/ant-design/ant-design/pull/26534)
|
||||
|
||||
## 4.6.2
|
||||
|
||||
`2020-08-31`
|
||||
@@ -52,6 +205,7 @@ timeline: true
|
||||
- 💄 Darker `@text-color` for WCAG 2.0 on contrast ratio. [#25630](https://github.com/ant-design/ant-design/pull/25630)
|
||||
- 🔥 New Image component. [#26296](https://github.com/ant-design/ant-design/pull/26296)
|
||||
- 🔥 Table support `sticky` prop to sticky header and scroll bar. [#25939](https://github.com/ant-design/ant-design/pull/25939)
|
||||
- 🛠 Refactor Upload via hooks. [#26196](https://github.com/ant-design/ant-design/pull/26196)
|
||||
- Form
|
||||
- 🆕 Form support style of required mark with `requiredMark` and deprecate `hideRequiredMark` prop. [#26309](https://github.com/ant-design/ant-design/pull/26309)
|
||||
- 🆕 Form.List support the second `index` param in `add`. [#26081](https://github.com/ant-design/ant-design/pull/26081)
|
||||
|
||||
@@ -15,6 +15,159 @@ timeline: true
|
||||
|
||||
---
|
||||
|
||||
## 4.7.2
|
||||
|
||||
`2020-10-19`
|
||||
|
||||
- 💄 修复 Layout.Sider `light` 主题失效问题。[#27227](https://github.com/ant-design/ant-design/pull/27227) [@lingjieee](https://github.com/lingjieee)
|
||||
- 💄 修复 TextArea 没有设置 `showCount` 时仍然会包裹 div 的问题,同时解决 `showCount` 下 `className` 和 `style` 没有传递给最外层节点的问题。[#27216](https://github.com/ant-design/ant-design/pull/27216)
|
||||
- 🐞 修复 Checkbox.Group TS2559 错误。[#27231](https://github.com/ant-design/ant-design/pull/27231)
|
||||
|
||||
## 4.7.1
|
||||
|
||||
`2020-10-18`
|
||||
|
||||
- DatePicker
|
||||
- 🐞 修复 DatePicker `showTime` 为 `true` 并且 `format` 为一个函数时报错的问题。[#27156](https://github.com/ant-design/ant-design/pull/27156)
|
||||
- 💄 修复 DatePicker 在下拉空间不足时的动画方向问题。[#27101](https://github.com/ant-design/ant-design/pull/27101)
|
||||
- Typography
|
||||
- 💄 修复 Typography 没有 `pre` 和 `blockquote` 样式的问题。[#27150](https://github.com/ant-design/ant-design/pull/27150)
|
||||
- 🐞 修复 Typography.Link 悬浮颜色错误的问题。[#27119](https://github.com/ant-design/ant-design/pull/27119)
|
||||
- 🐞 修复 Typography.Link 危险类型的悬浮颜色问题。[#27104](https://github.com/ant-design/ant-design/pull/27104)
|
||||
- 💄 修复 Descriptions 组件的内容含有超长数字时无法换行的问题。[#27195](https://github.com/ant-design/ant-design/pull/27195) [@WLyKan](https://github.com/WLyKan)
|
||||
- 🐞 修复 Password 在受控模式下未清除 `value` 属性的问题。[#27191](https://github.com/ant-design/ant-design/pull/27191)
|
||||
- 🐞 修复 Notification 在小尺寸屏幕下的宽度问题。[#27189](https://github.com/ant-design/ant-design/pull/27189)
|
||||
- 🐞 修复 Cascader 类名重复的问题。[#27187](https://github.com/ant-design/ant-design/pull/27187) [@huntdream](https://github.com/huntdream)
|
||||
- 🐞 修复 Drawer 会触发 Form 提交事件的问题。[#27175](https://github.com/ant-design/ant-design/pull/27175)
|
||||
- 🐞 修复 Dropdown 下拉菜单图标间距丢失的问题。[#27165](https://github.com/ant-design/ant-design/pull/27165)
|
||||
- 💄 修复 Layout.Sider 指定 `collapsedWidth` 后侧边菜单部分宽度不对的问题。[#27154](https://github.com/ant-design/ant-design/pull/27154)
|
||||
- 🐞 修复 Tabs `animated` 属性为 `true` 时未开启内容切换动画的问题。[#27145](https://github.com/ant-design/ant-design/pull/27145)
|
||||
- 🐞 修复 Divider 带标题时的分割线颜色。[#27134](https://github.com/ant-design/ant-design/pull/27134)
|
||||
- 💄 修复 Radio 选项选中并禁用时的鼠标样式。[#27125](https://github.com/ant-design/ant-design/pull/27125)
|
||||
- 🇪🇸 为西班牙语 es_ES 中添加缺少的翻译。[#27079](https://github.com/ant-design/ant-design/pull/27079) [@gerongams](https://github.com/gersongams)
|
||||
- RTL
|
||||
- 💄 优化 Input.TextArea 字数提示在 RTL 模式下的样式。[#27098](https://github.com/ant-design/ant-design/pull/27098)
|
||||
- TypeScript
|
||||
- 🤖 Button `shape` 移除文档中未声明的类型。[#27159](https://github.com/ant-design/ant-design/pull/27159)
|
||||
- 🤖 修复 Form.List `rules` 属性缺失的问题。[#27164](https://github.com/ant-design/ant-design/pull/27164) [@huntdream](https://github.com/huntdream)
|
||||
|
||||
## 4.7.0
|
||||
|
||||
`2020-10-10`
|
||||
|
||||
- 🔥 Input.TextArea 支持字数统计功能。[#26952](https://github.com/ant-design/ant-design/pull/26952) [@zhangchen915](https://github.com/zhangchen915)
|
||||
- DatePicker
|
||||
- 🔥 DatePicker `format` 支持传入一个函数以自定义显示内容。[#26845](https://github.com/ant-design/ant-design/pull/26845)
|
||||
- 🐞 修复 RangePicker 结束日期初始值无法选择的问题。[#23167](https://github.com/ant-design/ant-design/issues/23167)
|
||||
- Form
|
||||
- 🔥 Form.Item 支持 `tooltip` 属性自定义提示信息。[#26780](https://github.com/ant-design/ant-design/pull/26780)
|
||||
- 🆕 Form.List 支持 `rules` 校验并添加 Form.ErrorList 组件用于展示。[#26676](https://github.com/ant-design/ant-design/pull/26676)
|
||||
- 🆕 Form.Item 支持 `messageVariables` 属性。[#26597](https://github.com/ant-design/ant-design/pull/26597)
|
||||
- 🐞 修复 Form `onValuesChange` 第二个参数返回整个 `store` 的值而不是有效字段值的问题。[#26808](https://github.com/ant-design/ant-design/pull/26808)
|
||||
- Upload
|
||||
- 🔥 Upload 添加 `itemRender` 用于自定义文件列表项。[#26333](https://github.com/ant-design/ant-design/pull/26333)
|
||||
- 🆕 Upload `removeIcon` 和 `downloadIcon` 现在支持传入一个函数。[#26684](https://github.com/ant-design/ant-design/pull/26684) [@mwaddell](https://github.com/mwaddell)
|
||||
- Table
|
||||
- 🆕 Table `sticky` 支持 `getContainer` 以指定滚动容器。[#26973](https://github.com/ant-design/ant-design/pull/26973)
|
||||
- 🐞 修复 Table `column.filterDropdown` 为 `undefined` 时依旧会展示筛选菜单的问题。[#27002](https://github.com/ant-design/ant-design/pull/27002) [@shangyilim](https://github.com/shangyilim)
|
||||
- Modal
|
||||
- 🛠 重构 Modal 组件动画,现在 `destroyOnClose` 关闭时将完全清理相关 Dom 节点。[#26940](https://github.com/ant-design/ant-design/pull/26940)
|
||||
- 🆕 Modal 新增 `modalRender` 属性,支持可拖拽的对话框。[#26507](https://github.com/ant-design/ant-design/pull/26507) [@jhoneybee](https://github.com/jhoneybee)
|
||||
- 🆕 Space 增加 `split` 属性以支持分隔符间隔。[#26948](https://github.com/ant-design/ant-design/pull/26948)
|
||||
- 🆕 Image `preview` 属性扩展支持 `visible` 和 `onVisibleChange`。[#26915](https://github.com/ant-design/ant-design/pull/26915)
|
||||
- 🆕 InputNumber 点击上下按钮时将触发 `onStep`。[#27075](https://github.com/ant-design/ant-design/pull/27075)
|
||||
- 🆕 Avatar `size` 可以进行响应式的大小配置。[#26244](https://github.com/ant-design/ant-design/pull/26244) [@willamesoares](https://github.com/willamesoares)
|
||||
- 🐞 修复 Radio.Button 内无法使用 Tooltip 的问题。[#27050](https://github.com/ant-design/ant-design/pull/27050)
|
||||
- RTL
|
||||
- ⬅️ 修复 List 按钮在 RTL 模式下的样式。[#26964](https://github.com/ant-design/ant-design/pull/26964)
|
||||
- ⬅️ 优化 Transfer 分页在 RTL 模式下的样式。[#26960](https://github.com/ant-design/ant-design/pull/26960)
|
||||
- ⬅️ 修复 Upload RTL 模式下样式。[#26961](https://github.com/ant-design/ant-design/pull/26961)
|
||||
- ⬅️ 优化 Tag 样式避免主题和 RTL 模式互相影响。[#26955](https://github.com/ant-design/ant-design/pull/26955)
|
||||
- ⬅️ 优化 Cascader/Tree 组件中数据扩展 `loading` 按钮在 RTL 模式下的样式。[#27010](https://github.com/ant-design/ant-design/pull/27010)
|
||||
- TypeScript
|
||||
- 🤖 修复 `TimeLineItemProps` 为 `TimelineItemProps`。[#27001](https://github.com/ant-design/ant-design/pull/27001) [@mgcrea](https://github.com/mgcrea)
|
||||
- 🤖 修复 Slider `autoFocus` 属性定义。[#26995](https://github.com/ant-design/ant-design/pull/26995) [@shangyilim](https://github.com/shangyilim)
|
||||
- 🤖 修复 Slider `step` 属性不接收 `null` 的问题。[#26984](https://github.com/ant-design/ant-design/pull/26984) [@shangyilim](https://github.com/shangyilim)
|
||||
- 🤖 修复 Slider.Range `trackStyle` 和 `handleStyle` 应该接受数组的问题。[#27033](https://github.com/ant-design/ant-design/pull/27033)
|
||||
- 🤖 优化 Tag `onClose` TypeScript 定义。[#26932](https://github.com/ant-design/ant-design/pull/26932)
|
||||
- 🤖 调整 Form 定义,现在当 `getFieldsValue` 不配置 `namePath` 时返回类型为 FormValue 的泛型定义。[#26791](https://github.com/ant-design/ant-design/pull/26791)
|
||||
- 国际化
|
||||
- 🇧🇾 新增白俄罗斯语支持。[#27028](https://github.com/ant-design/ant-design/pull/27028) [@StIvan8](https://github.com/StIvan8)
|
||||
- 🇯🇵 调整日语国际化文案。[#27043](https://github.com/ant-design/ant-design/pull/27043) [@iorikingdom](https://github.com/iorikingdom)
|
||||
- 🇵🇱 补充 Table 波兰语国际化文案。[#26913](https://github.com/ant-design/ant-design/pull/26913) [@daczczcz1](https://github.com/daczczcz1)
|
||||
- 🇹🇷 补充土耳其语可选文案。[#27017](https://github.com/ant-design/ant-design/pull/27017) [@alperTunca](https://github.com/alperTunca)
|
||||
- 🇹🇭 补充 DatePicker 的泰语国际化文案。[#26993](https://github.com/ant-design/ant-design/pull/26993) [@anawinwz](https://github.com/anawinwz)
|
||||
|
||||
## 4.6.6
|
||||
|
||||
`2020-09-27`
|
||||
|
||||
- 🐞 修复 Steps 在小屏幕下第一项偏移的问题。[#26894](https://github.com/ant-design/ant-design/pull/26894)
|
||||
- 💄 修复 Divider 在有文字时,设置边框颜色无效的问题。[#26863](https://github.com/ant-design/ant-design/pull/26863)
|
||||
- 🐞 修复 Radio.Button 错误校验高亮样式的问题。[#26849](https://github.com/ant-design/ant-design/pull/26849) [@dhorelik](https://github.com/dhorelik)
|
||||
- 💄 修复 Typography 链接下划线样式。[#26854](https://github.com/ant-design/ant-design/pull/26854) [@vineetvk01](https://github.com/vineetvk01)
|
||||
- 国际化
|
||||
- 🌐 添加泰语支持。[#26906](https://github.com/ant-design/ant-design/pull/26906) [@anawinwz](https://github.com/anawinwz)
|
||||
- TypeScript
|
||||
- 🤖 修复 message.destroy 参数类型错误。[#26864](https://github.com/ant-design/ant-design/pull/26864) [@lihqi](https://github.com/lihqi)
|
||||
- 🤖 优化 Slider 类型定义。[#26884](https://github.com/ant-design/ant-design/pull/26884)
|
||||
- 🤖 导出 Form 中的 `FormListProps` 类型。[#26831](https://github.com/ant-design/ant-design/pull/26831) [@mgcrea](https://github.com/mgcrea)
|
||||
|
||||
## 4.6.5
|
||||
|
||||
`2020-09-20`
|
||||
|
||||
- 💄 修复 Descriptions 长文本溢出的样式问题。[#26820](https://github.com/ant-design/ant-design/pull/26820)
|
||||
- 🐞 修复 Menu 子菜单展开/收起时会出现滚动条的问题。[#26817](https://github.com/ant-design/ant-design/pull/26817)
|
||||
- 🐞 修复 `@layout-sider-background` 变量不能设置为渐变色的问题。[#26810](https://github.com/ant-design/ant-design/pull/26810)
|
||||
- 🐞 修复 Select 搜索时输入第一个字符后中文输入法状态丢失的问题。[#26796](https://github.com/ant-design/ant-design/pull/26796)
|
||||
- 🐞 修复 Table `@table-sticky-zindex` less 报错问题。[#26800](https://github.com/ant-design/ant-design/pull/26800) [@chimp1nski](https://github.com/chimp1nski)
|
||||
- Button
|
||||
- 💄 修复 Button 只有图标时的对齐问题。[#26785](https://github.com/ant-design/ant-design/pull/26785)
|
||||
- 🐞 修复 Button 和 react-router 一起使用时抛出 `Invalid value for prop navigate` 的问题。[#26740](https://github.com/ant-design/ant-design/pull/26740) [@knobo](https://github.com/knobo)
|
||||
- 💄 修复 TimePicker 选择框 hover 时文字内容左移的问题,并新增 `@picker-time-panel-column-width` 和 `@picker-time-panel-column-height` less 变量。[#26784](https://github.com/ant-design/ant-design/pull/26784)
|
||||
- 🐞 修复 AutoComplete 使用 `placeholder` 和 `allowClear` 时抛出警告的问题。[#26765](https://github.com/ant-design/ant-design/pull/26765)
|
||||
- 🐞 修复 Space 空条目会占据一格的样式问题。[#26721](https://github.com/ant-design/ant-design/pull/26721) [@knobo](https://github.com/knobo)
|
||||
- 🛠 去重多版本 `rc-trigger` 以降低打包尺寸。[#26803](https://github.com/ant-design/ant-design/pull/26803)
|
||||
- TypeScript
|
||||
- 🤖 Cascader 增加 `name` 和 `id` 属性。[#26660](https://github.com/ant-design/ant-design/pull/26660) [@alwaysloseall](https://github.com/alwaysloseall)
|
||||
|
||||
## 4.6.4
|
||||
|
||||
`2020-09-13`
|
||||
|
||||
- 💄 修复 Card 封面图片上有 1px 白边的问题。[#26659](https://github.com/ant-design/ant-design/pull/26659)
|
||||
- 💄 修复 Select 的 `placeholder` 颜色与 Input 不一致的问题。[#26651](https://github.com/ant-design/ant-design/pull/26651) [@wangcch](https://github.com/wangcch)
|
||||
- 🐞 修复 Menu 不支持 React.Fragment 的问题。[#26656](https://github.com/ant-design/ant-design/pull/26656)
|
||||
- 🐞 修复 TextArea 设置 `value` 为 `undefined` 时和 Input 行为不一致的问题。[#26652](https://github.com/ant-design/ant-design/pull/26652)
|
||||
- 🐞 修复 Motion 相关问题例如 Upload 对齐闪烁与 Form.Item 配置 `help` 的 ssr 问题。[#26628](https://github.com/ant-design/ant-design/pull/26628)
|
||||
- 🐞 修复 Typography.Link 和 react-router 一起使用时抛出 `Invalid value for prop navigate` 的问题。[#26623](https://github.com/ant-design/ant-design/pull/26623)
|
||||
- 🐞 修复 Table 分页器在表格上方消失的问题。[#26618](https://github.com/ant-design/ant-design/pull/26618)
|
||||
- 🐞 修复 Upload 受控时同时上传多份文件会丢失部分文件的问题。[#26612](https://github.com/ant-design/ant-design/pull/26612)
|
||||
- TypeScript
|
||||
- 🤖 修复 Table sorter 的 `compare` 和 `multiple` 不是可选的问题。[#26686](https://github.com/ant-design/ant-design/pull/26686)
|
||||
|
||||
## 4.6.3
|
||||
|
||||
`2020-09-06`
|
||||
|
||||
- 🛎 移动 props 中的 `className` 到最后。[#26602](https://github.com/ant-design/ant-design/pull/26602)
|
||||
- Table
|
||||
- 💄 修复 Table 嵌套表格样式会影响所有子层级表格的问题。[#26568](https://github.com/ant-design/ant-design/pull/26568) [@willc001](https://github.com/willc001)
|
||||
- 🐞 修复 Table 上方元素 `float: right;` 后无法交互的问题。[#26599](https://github.com/ant-design/ant-design/pull/26599)
|
||||
- 🐞 修复 Modal 关闭时导致滚动条向上跳动的问题。[#26538](https://github.com/ant-design/ant-design/pull/26538)
|
||||
- 🐞 修复 Upload 组件中 `customRequest` 的 `onError` 的类型定义。[#26601](https://github.com/ant-design/ant-design/pull/26601) [@yingpengsha](https://github.com/yingpengsha)
|
||||
- 🐞 修复 Select/TreeSelect 在 Chrome 下出现原生自动完成列表的问题。[#26590](https://github.com/ant-design/ant-design/pull/26590)
|
||||
- 🐞 修复 Cascader 搜索时 value 被覆盖的情况。[#26569](https://github.com/ant-design/ant-design/pull/26569) [@lich-yoo](https://github.com/lich-yoo)
|
||||
- 🐞 修复 Modal 在某些情况下溢出视窗的问题。[#25765](https://github.com/ant-design/ant-design/pull/25765) [@tanmoyopenroot](https://github.com/tanmoyopenroot)
|
||||
- 🐞 修复 Radio.Group 在 legacy Form 中,不能正常工作的问题。[#26555](https://github.com/ant-design/ant-design/pull/26555) [@willc001](https://github.com/willc001)
|
||||
- 🐞 修复 Pagination 切换按钮在 windows 下的对齐问题。[#26549](https://github.com/ant-design/ant-design/pull/26549)
|
||||
- 🐞 修复 Form 使用 `help` 时出现的同构问题。[#26542](https://github.com/ant-design/ant-design/pull/26542)
|
||||
- 🐞 修复 Avatar 在 `display: none` 时不会正确缩放 fallback 文字的问题。[#26522](https://github.com/ant-design/ant-design/pull/26522) [@zhangyu1818](https://github.com/zhangyu1818)
|
||||
- TypeScript
|
||||
- 🤖 Col 增加 `ColSize` 增加 `flex` 的定义。 [#26578](https://github.com/ant-design/ant-design/pull/26578) [@blaiz](https://github.com/blaiz)
|
||||
- 🤖 修复 Tooltip/Popover `children` 定义不接受 ReactNode 的问题。[#26534](https://github.com/ant-design/ant-design/pull/26534)
|
||||
|
||||
## 4.6.2
|
||||
|
||||
`2020-08-31`
|
||||
@@ -52,6 +205,7 @@ timeline: true
|
||||
- 💄 加深默认文本 `@text-color` 以满足 WCAG 2.0 对比度的规范。[#25630](https://github.com/ant-design/ant-design/pull/25630)
|
||||
- 🔥 新增图片组件 Image。[#26296](https://github.com/ant-design/ant-design/pull/26296)
|
||||
- 🔥 Table 新增 `sticky` 属性以支持固定表头和滚动条。[#25939](https://github.com/ant-design/ant-design/pull/25939)
|
||||
- 🛠 用 hooks 重构 Upload。[#26196](https://github.com/ant-design/ant-design/pull/26196)
|
||||
- Form
|
||||
- 🆕 Form 添加 `requiredMark` 属性以支持设置必选样式,废弃原 `hideRequiredMark`。[#26309](https://github.com/ant-design/ant-design/pull/26309)
|
||||
- 🆕 Form.List 中的 `add` 方法支持第二个 `index` 参数。[#26081](https://github.com/ant-design/ant-design/pull/26081)
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
一套企业级 UI 设计语言和 React 组件库。
|
||||
|
||||
|
||||
[![CircleCI status][circleci-image]][circleci-url] [![CI status][github-action-image]][github-action-url] [![codecov][codecov-image]][codecov-url] [![NPM version][npm-image]][npm-url] [![NPM downloads][download-image]][download-url]
|
||||
|
||||
[![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]
|
||||
@@ -18,8 +19,8 @@
|
||||
|
||||
[npm-image]: http://img.shields.io/npm/v/antd.svg?style=flat-square
|
||||
[npm-url]: http://npmjs.org/package/antd
|
||||
[circleci-image]: https://img.shields.io/travis/com/ant-design/ant-design.svg?style=flat-square
|
||||
[circleci-url]: https://travis-ci.com/ant-design/ant-design
|
||||
[circleci-image]: https://img.shields.io/circleci/build/github/ant-design/ant-design/master?style=flat-square
|
||||
[circleci-url]: https://circleci.com/gh/ant-design/ant-design
|
||||
[github-action-image]: https://github.com/ant-design/ant-design/workflows/test/badge.svg
|
||||
[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
|
||||
@@ -42,8 +43,8 @@
|
||||
[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=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
|
||||
[semver-stability-url]: https://dependabot.com/compatibility-score.html/?dependency-name=antd&package-manager=npm_and_yarn
|
||||
[semver-stability-image]: https://api.dependabot.com/badges/compatibility_score?dependency-name=antd&package-manager=npm_and_yarn&version-scheme=semver
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@ An enterprise-class UI design language and React UI library.
|
||||
|
||||
[npm-image]: http://img.shields.io/npm/v/antd.svg?style=flat-square
|
||||
[npm-url]: http://npmjs.org/package/antd
|
||||
[circleci-image]: https://img.shields.io/travis/com/ant-design/ant-design.svg?style=flat-square
|
||||
[circleci-url]: https://travis-ci.com/ant-design/ant-design
|
||||
[circleci-image]: https://img.shields.io/circleci/build/github/ant-design/ant-design/master?style=flat-square
|
||||
[circleci-url]: https://circleci.com/gh/ant-design/ant-design
|
||||
[github-action-image]: https://github.com/ant-design/ant-design/workflows/test/badge.svg
|
||||
[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
|
||||
|
||||
19
SECURITY.md
Normal file
19
SECURITY.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
Use this section to tell people about which versions of your project are
|
||||
currently being supported with security updates.
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 4.x | :white_check_mark: |
|
||||
| < 4.0 | :x: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Use this section to tell people how to report a vulnerability.
|
||||
|
||||
Tell them where to go, how often they can expect to get an update on a
|
||||
reported vulnerability, what to expect if the vulnerability is accepted or
|
||||
declined, etc.
|
||||
@@ -3,39 +3,61 @@ import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import KeyCode from 'rc-util/lib/KeyCode';
|
||||
import delayRaf from '../raf';
|
||||
import throttleByAnimationFrame from '../throttleByAnimationFrame';
|
||||
import {
|
||||
throttleByAnimationFrame,
|
||||
throttleByAnimationFrameDecorator,
|
||||
} from '../throttleByAnimationFrame';
|
||||
import getDataOrAriaProps from '../getDataOrAriaProps';
|
||||
import Wave from '../wave';
|
||||
import TransButton from '../transButton';
|
||||
import openAnimation from '../openAnimation';
|
||||
import { isStyleSupport, isFlexSupported } from '../styleChecker';
|
||||
import { sleep } from '../../../tests/utils';
|
||||
import focusTest from '../../../tests/shared/focusTest';
|
||||
|
||||
describe('Test utils function', () => {
|
||||
focusTest(TransButton);
|
||||
|
||||
it('throttle function should work', async () => {
|
||||
const callback = jest.fn();
|
||||
const throttled = throttleByAnimationFrame(callback);
|
||||
expect(callback).not.toHaveBeenCalled();
|
||||
describe('throttle', () => {
|
||||
it('throttle function should work', async () => {
|
||||
const callback = jest.fn();
|
||||
const throttled = throttleByAnimationFrame(callback);
|
||||
expect(callback).not.toHaveBeenCalled();
|
||||
|
||||
throttled();
|
||||
throttled();
|
||||
await sleep(20);
|
||||
throttled();
|
||||
throttled();
|
||||
await sleep(20);
|
||||
|
||||
expect(callback).toHaveBeenCalled();
|
||||
expect(callback.mock.calls.length).toBe(1);
|
||||
});
|
||||
expect(callback).toHaveBeenCalled();
|
||||
expect(callback.mock.calls.length).toBe(1);
|
||||
});
|
||||
|
||||
it('throttle function should be canceled', async () => {
|
||||
const callback = jest.fn();
|
||||
const throttled = throttleByAnimationFrame(callback);
|
||||
it('throttle function should be canceled', async () => {
|
||||
const callback = jest.fn();
|
||||
const throttled = throttleByAnimationFrame(callback);
|
||||
|
||||
throttled();
|
||||
throttled.cancel();
|
||||
await sleep(20);
|
||||
throttled();
|
||||
throttled.cancel();
|
||||
await sleep(20);
|
||||
|
||||
expect(callback).not.toHaveBeenCalled();
|
||||
expect(callback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('throttleByAnimationFrameDecorator should works', async () => {
|
||||
const callbackFn = jest.fn();
|
||||
class Test {
|
||||
@throttleByAnimationFrameDecorator()
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
callback() {
|
||||
callbackFn();
|
||||
}
|
||||
}
|
||||
const test = new Test();
|
||||
test.callback();
|
||||
test.callback();
|
||||
test.callback();
|
||||
await sleep(30);
|
||||
expect(callbackFn).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getDataOrAriaProps', () => {
|
||||
@@ -187,20 +209,23 @@ describe('Test utils function', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('openAnimation', () => {
|
||||
it('should support openAnimation', () => {
|
||||
const done = jest.fn();
|
||||
const domNode = document.createElement('div');
|
||||
expect(typeof openAnimation.enter).toBe('function');
|
||||
expect(typeof openAnimation.leave).toBe('function');
|
||||
expect(typeof openAnimation.appear).toBe('function');
|
||||
const appear = openAnimation.appear(domNode, done);
|
||||
const enter = openAnimation.enter(domNode, done);
|
||||
const leave = openAnimation.leave(domNode, done);
|
||||
expect(typeof appear.stop).toBe('function');
|
||||
expect(typeof enter.stop).toBe('function');
|
||||
expect(typeof leave.stop).toBe('function');
|
||||
expect(done).toHaveBeenCalled();
|
||||
describe('style', () => {
|
||||
it('isFlexSupported', () => {
|
||||
expect(isFlexSupported).toBe(true);
|
||||
});
|
||||
|
||||
it('isStyleSupport', () => {
|
||||
expect(isStyleSupport('color')).toBe(true);
|
||||
expect(isStyleSupport('not-existed')).toBe(false);
|
||||
});
|
||||
|
||||
it('isStyleSupport return false in service side', () => {
|
||||
const spy = jest
|
||||
.spyOn(window.document, 'documentElement', 'get')
|
||||
.mockImplementation(() => undefined);
|
||||
expect(isStyleSupport('color')).toBe(false);
|
||||
expect(isStyleSupport('not-existed')).toBe(false);
|
||||
spy.mockRestore();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
19
components/_util/hooks/useCombinedRefs.tsx
Normal file
19
components/_util/hooks/useCombinedRefs.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
import * as React from 'react';
|
||||
import { fillRef } from '../ref';
|
||||
|
||||
function useCombinedRefs<T>(
|
||||
...refs: Array<React.MutableRefObject<T> | ((instance: T) => void) | null>
|
||||
) {
|
||||
const targetRef = React.useRef();
|
||||
|
||||
React.useEffect(() => {
|
||||
refs.forEach(ref => {
|
||||
if (!ref) return;
|
||||
fillRef(ref, targetRef.current);
|
||||
});
|
||||
}, [refs]);
|
||||
|
||||
return targetRef;
|
||||
}
|
||||
|
||||
export default useCombinedRefs;
|
||||
@@ -1,5 +1,4 @@
|
||||
import { CSSMotionProps } from 'rc-motion';
|
||||
import { MotionEventHandler, MotionEndEventHandler } from 'rc-motion/lib/CSSMotion';
|
||||
import { CSSMotionProps, MotionEventHandler, MotionEndEventHandler } from 'rc-motion';
|
||||
|
||||
// ================== Collapse Motion ==================
|
||||
const getCollapsedHeight: MotionEventHandler = () => ({ height: 0, opacity: 0 });
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export type Breakpoint = 'xxl' | 'xl' | 'lg' | 'md' | 'sm' | 'xs';
|
||||
export type BreakpointMap = Partial<Record<Breakpoint, string>>;
|
||||
export type ScreenMap = Partial<Record<Breakpoint, boolean>>;
|
||||
export type ScreenSizeMap = Partial<Record<Breakpoint, number>>;
|
||||
|
||||
export const responsiveArray: Breakpoint[] = ['xxl', 'xl', 'lg', 'md', 'sm', 'xs'];
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ interface ScrollToOptions {
|
||||
|
||||
export default function scrollTo(y: number, options: ScrollToOptions = {}) {
|
||||
const { getContainer = () => window, callback, duration = 450 } = options;
|
||||
|
||||
const container = getContainer();
|
||||
const scrollTop = getScroll(container, true);
|
||||
const startTime = Date.now();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const isStyleSupport = (styleName: string | Array<string>): boolean => {
|
||||
export const isStyleSupport = (styleName: string | Array<string>): boolean => {
|
||||
if (typeof window !== 'undefined' && window.document && window.document.documentElement) {
|
||||
const styleNameList = Array.isArray(styleName) ? styleName : [styleName];
|
||||
const { documentElement } = window.document;
|
||||
@@ -9,5 +9,3 @@ const isStyleSupport = (styleName: string | Array<string>): boolean => {
|
||||
};
|
||||
|
||||
export const isFlexSupported = isStyleSupport(['flex', 'webkitFlex', 'Flex', 'msFlex']);
|
||||
|
||||
export default isStyleSupport;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import raf from 'raf';
|
||||
|
||||
export default function throttleByAnimationFrame(fn: (...args: any[]) => void) {
|
||||
export function throttleByAnimationFrame(fn: (...args: any[]) => void) {
|
||||
let requestId: number | null;
|
||||
|
||||
const later = (args: any[]) => () => {
|
||||
@@ -20,15 +20,18 @@ export default function throttleByAnimationFrame(fn: (...args: any[]) => void) {
|
||||
}
|
||||
|
||||
export function throttleByAnimationFrameDecorator() {
|
||||
// eslint-disable-next-line func-names
|
||||
return function(target: any, key: string, descriptor: any) {
|
||||
return function throttle(target: any, key: string, descriptor: any) {
|
||||
const fn = descriptor.value;
|
||||
let definingProperty = false;
|
||||
return {
|
||||
configurable: true,
|
||||
get() {
|
||||
// In IE11 calling Object.defineProperty has a side-effect of evaluating the
|
||||
// getter for the property which is being replaced. This causes infinite
|
||||
// recursion and an "Out of stack space" error.
|
||||
// eslint-disable-next-line no-prototype-builtins
|
||||
if (definingProperty || this === target.prototype || this.hasOwnProperty(key)) {
|
||||
/* istanbul ignore next */
|
||||
return fn;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ export const tupleNum = <T extends number[]>(...args: T) => args;
|
||||
* https://stackoverflow.com/a/59187769
|
||||
* Extract the type of an element of an array/tuple without performing indexing
|
||||
*/
|
||||
export type ElementOf<T> = T extends (infer E)[] ? E : T extends readonly (infer E)[] ? E : never;
|
||||
export type ElementOf<T> = T extends (infer E)[] ? E : T extends readonly (infer F)[] ? F : never;
|
||||
|
||||
/**
|
||||
* https://github.com/Microsoft/TypeScript/issues/29729
|
||||
|
||||
@@ -4,7 +4,7 @@ import TransitionEvents from '@ant-design/css-animation/lib/Event';
|
||||
import raf from './raf';
|
||||
import { ConfigConsumer, ConfigConsumerProps, CSPConfig, ConfigContext } from '../config-provider';
|
||||
|
||||
let styleForPesudo: HTMLStyleElement | null;
|
||||
let styleForPseudo: HTMLStyleElement | null;
|
||||
|
||||
// Where el is the DOM element you'd like to test for visibility
|
||||
function isHidden(element: HTMLElement) {
|
||||
@@ -74,8 +74,8 @@ export default class Wave extends React.Component<{ insertExtraNode?: boolean }>
|
||||
extraNode.className = `${getPrefixCls('')}-click-animating-node`;
|
||||
const attributeName = this.getAttributeName();
|
||||
node.setAttribute(attributeName, 'true');
|
||||
// Not white or transparnt or grey
|
||||
styleForPesudo = styleForPesudo || document.createElement('style');
|
||||
// Not white or transparent or grey
|
||||
styleForPseudo = styleForPseudo || document.createElement('style');
|
||||
if (
|
||||
waveColor &&
|
||||
waveColor !== '#ffffff' &&
|
||||
@@ -86,18 +86,18 @@ export default class Wave extends React.Component<{ insertExtraNode?: boolean }>
|
||||
) {
|
||||
// Add nonce if CSP exist
|
||||
if (this.csp && this.csp.nonce) {
|
||||
styleForPesudo.nonce = this.csp.nonce;
|
||||
styleForPseudo.nonce = this.csp.nonce;
|
||||
}
|
||||
|
||||
extraNode.style.borderColor = waveColor;
|
||||
styleForPesudo.innerHTML = `
|
||||
styleForPseudo.innerHTML = `
|
||||
[${getPrefixCls('')}-click-animating-without-extra-node='true']::after, .${getPrefixCls(
|
||||
'',
|
||||
)}-click-animating-node {
|
||||
--antd-wave-shadow-color: ${waveColor};
|
||||
}`;
|
||||
if (!document.body.contains(styleForPesudo)) {
|
||||
document.body.appendChild(styleForPesudo);
|
||||
if (!document.body.contains(styleForPseudo)) {
|
||||
document.body.appendChild(styleForPseudo);
|
||||
}
|
||||
}
|
||||
if (insertExtraNode) {
|
||||
@@ -116,7 +116,6 @@ export default class Wave extends React.Component<{ insertExtraNode?: boolean }>
|
||||
if (!e || e.target !== node || this.animationStart) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.resetEffect(node);
|
||||
};
|
||||
|
||||
@@ -181,8 +180,8 @@ export default class Wave extends React.Component<{ insertExtraNode?: boolean }>
|
||||
const attributeName = this.getAttributeName();
|
||||
node.setAttribute(attributeName, 'false'); // edge has bug on `removeAttribute` #14466
|
||||
|
||||
if (styleForPesudo) {
|
||||
styleForPesudo.innerHTML = '';
|
||||
if (styleForPseudo) {
|
||||
styleForPseudo.innerHTML = '';
|
||||
}
|
||||
|
||||
if (insertExtraNode && this.extraNode && node.contains(this.extraNode)) {
|
||||
|
||||
@@ -186,7 +186,7 @@ describe('Affix Render', () => {
|
||||
it.each([
|
||||
{ name: 'inner', index: 0 },
|
||||
{ name: 'outer', index: 1 },
|
||||
])(name, async ({ index }) => {
|
||||
])('inner or outer', async ({ index }) => {
|
||||
document.body.innerHTML = '<div id="mounter" />';
|
||||
|
||||
const updateCalled = jest.fn();
|
||||
|
||||
@@ -19,10 +19,10 @@ Alert component for feedback.
|
||||
| afterClose | Called when close animation is finished | () => void | - |
|
||||
| banner | Whether to show as banner | boolean | false |
|
||||
| closable | Whether Alert can be closed | boolean | - |
|
||||
| closeText | Close text to show | string \| ReactNode | - |
|
||||
| description | Additional content of Alert | string \| ReactNode | - |
|
||||
| closeText | Close text to show | ReactNode | - |
|
||||
| description | Additional content of Alert | ReactNode | - |
|
||||
| icon | Custom icon, effective when `showIcon` is true | ReactNode | - |
|
||||
| message | Content of Alert | string \| ReactNode | - |
|
||||
| message | Content of Alert | ReactNode | - |
|
||||
| showIcon | Whether to show icon | boolean | false, in `banner` mode default is true |
|
||||
| type | Type of Alert styles, options: `success`, `info`, `warning`, `error` | string | `info`, in `banner` mode default is `warning` |
|
||||
| onClose | Callback when Alert is closed | (e: MouseEvent) => void | - |
|
||||
|
||||
@@ -20,10 +20,10 @@ cover: https://gw.alipayobjects.com/zos/alicdn/8emPa3fjl/Alert.svg
|
||||
| afterClose | 关闭动画结束后触发的回调函数 | () => void | - |
|
||||
| banner | 是否用作顶部公告 | boolean | false |
|
||||
| closable | 默认不显示关闭按钮 | boolean | - |
|
||||
| closeText | 自定义关闭按钮 | string \| ReactNode | - |
|
||||
| description | 警告提示的辅助性文字介绍 | string \| ReactNode | - |
|
||||
| closeText | 自定义关闭按钮 | ReactNode | - |
|
||||
| description | 警告提示的辅助性文字介绍 | ReactNode | - |
|
||||
| icon | 自定义图标,`showIcon` 为 true 时有效 | ReactNode | - |
|
||||
| message | 警告提示内容 | string \| ReactNode | - |
|
||||
| message | 警告提示内容 | ReactNode | - |
|
||||
| showIcon | 是否显示辅助图标 | boolean | false,`banner` 模式下默认值为 true |
|
||||
| type | 指定警告提示的样式,有四种选择 `success`、`info`、`warning`、`error` | string | `info`,`banner` 模式下默认值为 `warning` |
|
||||
| onClose | 关闭时触发的回调函数 | (e: MouseEvent) => void | - |
|
||||
|
||||
@@ -9,6 +9,8 @@ import scrollTo from '../_util/scrollTo';
|
||||
import getScroll from '../_util/getScroll';
|
||||
import AnchorContext from './context';
|
||||
|
||||
export type AnchorContainer = HTMLElement | Window;
|
||||
|
||||
function getDefaultContainer() {
|
||||
return window;
|
||||
}
|
||||
@@ -38,8 +40,6 @@ type Section = {
|
||||
top: number;
|
||||
};
|
||||
|
||||
export type AnchorContainer = HTMLElement | Window;
|
||||
|
||||
export interface AnchorProps {
|
||||
prefixCls?: string;
|
||||
className?: string;
|
||||
@@ -286,9 +286,13 @@ export default class Anchor extends React.Component<AnchorProps, AnchorState, Co
|
||||
visible: activeLink,
|
||||
});
|
||||
|
||||
const wrapperClass = classNames(className, `${prefixCls}-wrapper`, {
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
});
|
||||
const wrapperClass = classNames(
|
||||
`${prefixCls}-wrapper`,
|
||||
{
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
},
|
||||
className,
|
||||
);
|
||||
|
||||
const anchorClass = classNames(prefixCls, {
|
||||
fixed: !affix && !showInkInFixed,
|
||||
|
||||
@@ -51,9 +51,13 @@ class AnchorLink extends React.Component<AnchorLinkProps, any, AntAnchor> {
|
||||
const { prefixCls: customizePrefixCls, href, title, children, className, target } = this.props;
|
||||
const prefixCls = getPrefixCls('anchor', customizePrefixCls);
|
||||
const active = this.context.activeLink === href;
|
||||
const wrapperClassName = classNames(className, `${prefixCls}-link`, {
|
||||
[`${prefixCls}-link-active`]: active,
|
||||
});
|
||||
const wrapperClassName = classNames(
|
||||
`${prefixCls}-link`,
|
||||
{
|
||||
[`${prefixCls}-link-active`]: active,
|
||||
},
|
||||
className,
|
||||
);
|
||||
const titleClassName = classNames(`${prefixCls}-link-title`, {
|
||||
[`${prefixCls}-link-title-active`]: active,
|
||||
});
|
||||
|
||||
@@ -41,18 +41,6 @@ exports[`renders ./components/anchor/demo/basic.md correctly 1`] = `
|
||||
Static demo
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
href="#components-anchor-demo-basic"
|
||||
target="_blank"
|
||||
title="Basic demo with Target"
|
||||
>
|
||||
Basic demo with Target
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
>
|
||||
|
||||
@@ -22,7 +22,6 @@ ReactDOM.render(
|
||||
<Anchor>
|
||||
<Link href="#components-anchor-demo-basic" title="Basic demo" />
|
||||
<Link href="#components-anchor-demo-static" title="Static demo" />
|
||||
<Link href="#components-anchor-demo-basic" title="Basic demo with Target" target="_blank" />
|
||||
<Link href="#API" title="API">
|
||||
<Link href="#Anchor-Props" title="Anchor Props" />
|
||||
<Link href="#Link-Props" title="Link Props" />
|
||||
|
||||
@@ -19,14 +19,14 @@ import { Anchor } from 'antd';
|
||||
const { Link } = Anchor;
|
||||
|
||||
const handleClick = (
|
||||
e: React.MouseEvent<HTMLElement>,
|
||||
link: {
|
||||
title: React.ReactNode;
|
||||
href: string;
|
||||
},
|
||||
) => {
|
||||
e.preventDefault();
|
||||
console.log(link);
|
||||
e: React.MouseEvent<HTMLElement>,
|
||||
link: {
|
||||
title: React.ReactNode;
|
||||
href: string;
|
||||
},
|
||||
) => {
|
||||
e.preventDefault();
|
||||
console.log(link);
|
||||
};
|
||||
|
||||
ReactDOM.render(
|
||||
|
||||
@@ -21,9 +21,8 @@ For displaying anchor hyperlinks on page and jumping between them.
|
||||
| affix | Fixed mode of Anchor | boolean | true | |
|
||||
| bounds | Bounding distance of anchor area | number | 5 | |
|
||||
| getContainer | Scrolling container | () => HTMLElement | () => window | |
|
||||
| offsetBottom | Pixels to offset from bottom when calculating position of scroll | number | - | |
|
||||
| offsetTop | Pixels to offset from top when calculating position of scroll | number | 0 | |
|
||||
| showInkInFixed | Whether show ink-balls in Fixed mode | boolean | false | |
|
||||
| showInkInFixed | Whether show ink-balls when `affix={false}` | boolean | false | |
|
||||
| onClick | Set the handler to handle `click` event | function(e: Event, link: Object) | - | |
|
||||
| getCurrentAnchor | Customize the anchor highlight | () => string | - | |
|
||||
| targetOffset | Anchor scroll offset, default as `offsetTop`, [example](#components-anchor-demo-targetOffset) | number | - | |
|
||||
@@ -31,8 +30,8 @@ For displaying anchor hyperlinks on page and jumping between them.
|
||||
|
||||
### Link Props
|
||||
|
||||
| Property | Description | Type | Default | Version |
|
||||
| -------- | ----------------------------------------- | ------------------- | ------- | ------- |
|
||||
| href | The target of hyperlink | string | | |
|
||||
| title | The content of hyperlink | string \| ReactNode | | |
|
||||
| target | Specifies where to display the linked URL | string | | |
|
||||
| Property | Description | Type | Default | Version |
|
||||
| -------- | ----------------------------------------- | --------- | ------- | ------- |
|
||||
| href | The target of hyperlink | string | | |
|
||||
| title | The content of hyperlink | ReactNode | | |
|
||||
| target | Specifies where to display the linked URL | string | | |
|
||||
|
||||
@@ -22,9 +22,8 @@ cover: https://gw.alipayobjects.com/zos/alicdn/_1-C1JwsC/Anchor.svg
|
||||
| affix | 固定模式 | boolean | true | |
|
||||
| bounds | 锚点区域边界 | number | 5 | |
|
||||
| getContainer | 指定滚动的容器 | () => HTMLElement | () => window | |
|
||||
| offsetBottom | 距离窗口底部达到指定偏移量后触发 | number | | |
|
||||
| offsetTop | 距离窗口顶部达到指定偏移量后触发 | number | | |
|
||||
| showInkInFixed | 固定模式是否显示小圆点 | boolean | false | |
|
||||
| showInkInFixed | `affix={false}` 时是否显示小圆点 | boolean | false | |
|
||||
| onClick | `click` 事件的 handler | function(e: Event, link: Object) | - | |
|
||||
| getCurrentAnchor | 自定义高亮的锚点 | () => string | - | |
|
||||
| targetOffset | 锚点滚动偏移量,默认与 offsetTop 相同,[例子](#components-anchor-demo-targetOffset) | number | - | |
|
||||
@@ -32,8 +31,8 @@ cover: https://gw.alipayobjects.com/zos/alicdn/_1-C1JwsC/Anchor.svg
|
||||
|
||||
### Link Props
|
||||
|
||||
| 成员 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| ------ | -------------------------------- | ------------------- | ------ | ---- |
|
||||
| href | 锚点链接 | string | - | |
|
||||
| title | 文字内容 | string \| ReactNode | - | |
|
||||
| target | 该属性指定在何处显示链接的资源。 | string | - | |
|
||||
| 成员 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| ------ | -------------------------------- | --------- | ------ | ---- |
|
||||
| href | 锚点链接 | string | - | |
|
||||
| title | 文字内容 | ReactNode | - | |
|
||||
| target | 该属性指定在何处显示链接的资源。 | string | - | |
|
||||
|
||||
@@ -21,6 +21,7 @@ Array [
|
||||
autocomplete="off"
|
||||
class="ant-select-selection-search-input"
|
||||
role="combobox"
|
||||
type="search"
|
||||
value=""
|
||||
/>
|
||||
</span>
|
||||
@@ -52,6 +53,7 @@ Array [
|
||||
autocomplete="off"
|
||||
class="ant-select-selection-search-input"
|
||||
role="combobox"
|
||||
type="search"
|
||||
value=""
|
||||
/>
|
||||
</span>
|
||||
@@ -77,44 +79,52 @@ exports[`renders ./components/auto-complete/demo/certain-category.md correctly 1
|
||||
class="ant-select-selection-search"
|
||||
>
|
||||
<span
|
||||
class="ant-input-search ant-select-selection-search-input ant-input-affix-wrapper ant-input-affix-wrapper-lg"
|
||||
class="ant-input-group-wrapper ant-input-group-wrapper-lg ant-input-search ant-input-search-large ant-select-selection-search-input"
|
||||
>
|
||||
<input
|
||||
aria-activedescendant="undefined_list_0"
|
||||
aria-autocomplete="list"
|
||||
aria-controls="undefined_list"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="undefined_list"
|
||||
autocomplete="off"
|
||||
class="ant-input ant-input-lg"
|
||||
placeholder="input here"
|
||||
role="combobox"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
class="ant-input-suffix"
|
||||
class="ant-input-wrapper ant-input-group"
|
||||
>
|
||||
<input
|
||||
aria-activedescendant="undefined_list_0"
|
||||
aria-autocomplete="list"
|
||||
aria-controls="undefined_list"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="undefined_list"
|
||||
autocomplete="off"
|
||||
class="ant-input ant-input-lg"
|
||||
placeholder="input here"
|
||||
role="combobox"
|
||||
type="search"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
aria-label="search"
|
||||
class="anticon anticon-search ant-input-search-icon"
|
||||
role="img"
|
||||
tabindex="-1"
|
||||
class="ant-input-group-addon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<button
|
||||
class="ant-btn ant-btn-lg ant-btn-icon-only ant-input-search-button"
|
||||
type="button"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
<span
|
||||
aria-label="search"
|
||||
class="anticon anticon-search"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
@@ -148,6 +158,7 @@ exports[`renders ./components/auto-complete/demo/custom.md correctly 1`] = `
|
||||
placeholder="input here"
|
||||
role="combobox"
|
||||
style="height:50px"
|
||||
type="search"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
@@ -202,6 +213,7 @@ exports[`renders ./components/auto-complete/demo/form-debug.md correctly 1`] = `
|
||||
autocomplete="off"
|
||||
class="ant-select-selection-search-input"
|
||||
role="combobox"
|
||||
type="search"
|
||||
value=""
|
||||
/>
|
||||
</span>
|
||||
@@ -256,6 +268,7 @@ exports[`renders ./components/auto-complete/demo/form-debug.md correctly 1`] = `
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity:0"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
@@ -342,6 +355,7 @@ exports[`renders ./components/auto-complete/demo/form-debug.md correctly 1`] = `
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity:0"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
@@ -396,6 +410,7 @@ exports[`renders ./components/auto-complete/demo/form-debug.md correctly 1`] = `
|
||||
autocomplete="off"
|
||||
class="ant-select-selection-search-input"
|
||||
role="combobox"
|
||||
type="search"
|
||||
value=""
|
||||
/>
|
||||
</span>
|
||||
@@ -441,7 +456,7 @@ exports[`renders ./components/auto-complete/demo/form-debug.md correctly 1`] = `
|
||||
class="ant-select-selection-search"
|
||||
>
|
||||
<span
|
||||
class="ant-select-selection-search-input ant-input-affix-wrapper"
|
||||
class="ant-input-affix-wrapper ant-select-selection-search-input"
|
||||
>
|
||||
<input
|
||||
aria-activedescendant="undefined_list_0"
|
||||
@@ -452,7 +467,7 @@ exports[`renders ./components/auto-complete/demo/form-debug.md correctly 1`] = `
|
||||
autocomplete="off"
|
||||
class="ant-input"
|
||||
role="combobox"
|
||||
type="text"
|
||||
type="search"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
@@ -536,6 +551,7 @@ exports[`renders ./components/auto-complete/demo/form-debug.md correctly 1`] = `
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity:0"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
@@ -582,7 +598,7 @@ exports[`renders ./components/auto-complete/demo/form-debug.md correctly 1`] = `
|
||||
class="ant-select-selection-search"
|
||||
>
|
||||
<span
|
||||
class="ant-select-selection-search-input ant-input-affix-wrapper"
|
||||
class="ant-input-affix-wrapper ant-select-selection-search-input"
|
||||
>
|
||||
<input
|
||||
aria-activedescendant="undefined_list_0"
|
||||
@@ -593,7 +609,7 @@ exports[`renders ./components/auto-complete/demo/form-debug.md correctly 1`] = `
|
||||
autocomplete="off"
|
||||
class="ant-input"
|
||||
role="combobox"
|
||||
type="text"
|
||||
type="search"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
@@ -678,6 +694,7 @@ exports[`renders ./components/auto-complete/demo/form-debug.md correctly 1`] = `
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity:0"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
@@ -724,43 +741,51 @@ exports[`renders ./components/auto-complete/demo/form-debug.md correctly 1`] = `
|
||||
class="ant-select-selection-search"
|
||||
>
|
||||
<span
|
||||
class="ant-input-search ant-select-selection-search-input ant-input-affix-wrapper"
|
||||
class="ant-input-group-wrapper ant-input-search ant-select-selection-search-input"
|
||||
>
|
||||
<input
|
||||
aria-activedescendant="undefined_list_0"
|
||||
aria-autocomplete="list"
|
||||
aria-controls="undefined_list"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="undefined_list"
|
||||
autocomplete="off"
|
||||
class="ant-input"
|
||||
role="combobox"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
class="ant-input-suffix"
|
||||
class="ant-input-wrapper ant-input-group"
|
||||
>
|
||||
<input
|
||||
aria-activedescendant="undefined_list_0"
|
||||
aria-autocomplete="list"
|
||||
aria-controls="undefined_list"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="undefined_list"
|
||||
autocomplete="off"
|
||||
class="ant-input"
|
||||
role="combobox"
|
||||
type="search"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
aria-label="search"
|
||||
class="anticon anticon-search ant-input-search-icon"
|
||||
role="img"
|
||||
tabindex="-1"
|
||||
class="ant-input-group-addon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<button
|
||||
class="ant-btn ant-btn-icon-only ant-input-search-button"
|
||||
type="button"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
<span
|
||||
aria-label="search"
|
||||
class="anticon anticon-search"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
@@ -821,6 +846,7 @@ exports[`renders ./components/auto-complete/demo/form-debug.md correctly 1`] = `
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity:0"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
@@ -867,43 +893,51 @@ exports[`renders ./components/auto-complete/demo/form-debug.md correctly 1`] = `
|
||||
class="ant-select-selection-search"
|
||||
>
|
||||
<span
|
||||
class="ant-input-search ant-select-selection-search-input ant-input-affix-wrapper"
|
||||
class="ant-input-group-wrapper ant-input-search ant-select-selection-search-input"
|
||||
>
|
||||
<input
|
||||
aria-activedescendant="undefined_list_0"
|
||||
aria-autocomplete="list"
|
||||
aria-controls="undefined_list"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="undefined_list"
|
||||
autocomplete="off"
|
||||
class="ant-input"
|
||||
role="combobox"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
class="ant-input-suffix"
|
||||
class="ant-input-wrapper ant-input-group"
|
||||
>
|
||||
<input
|
||||
aria-activedescendant="undefined_list_0"
|
||||
aria-autocomplete="list"
|
||||
aria-controls="undefined_list"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="undefined_list"
|
||||
autocomplete="off"
|
||||
class="ant-input"
|
||||
role="combobox"
|
||||
type="search"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
aria-label="search"
|
||||
class="anticon anticon-search ant-input-search-icon"
|
||||
role="img"
|
||||
tabindex="-1"
|
||||
class="ant-input-group-addon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<button
|
||||
class="ant-btn ant-btn-icon-only ant-input-search-button"
|
||||
type="button"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
<span
|
||||
aria-label="search"
|
||||
class="anticon anticon-search"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
@@ -969,6 +1003,7 @@ exports[`renders ./components/auto-complete/demo/non-case-sensitive.md correctly
|
||||
autocomplete="off"
|
||||
class="ant-select-selection-search-input"
|
||||
role="combobox"
|
||||
type="search"
|
||||
value=""
|
||||
/>
|
||||
</span>
|
||||
@@ -1001,6 +1036,7 @@ exports[`renders ./components/auto-complete/demo/options.md correctly 1`] = `
|
||||
autocomplete="off"
|
||||
class="ant-select-selection-search-input"
|
||||
role="combobox"
|
||||
type="search"
|
||||
value=""
|
||||
/>
|
||||
</span>
|
||||
@@ -1025,7 +1061,7 @@ exports[`renders ./components/auto-complete/demo/uncertain-category.md correctly
|
||||
class="ant-select-selection-search"
|
||||
>
|
||||
<span
|
||||
class="ant-input-search ant-select-selection-search-input ant-input-search-enter-button ant-input-search-large ant-input-group-wrapper ant-input-group-wrapper-lg"
|
||||
class="ant-input-group-wrapper ant-input-group-wrapper-lg ant-input-search ant-input-search-large ant-select-selection-search-input"
|
||||
>
|
||||
<span
|
||||
class="ant-input-wrapper ant-input-group"
|
||||
@@ -1040,14 +1076,14 @@ exports[`renders ./components/auto-complete/demo/uncertain-category.md correctly
|
||||
class="ant-input ant-input-lg"
|
||||
placeholder="input here"
|
||||
role="combobox"
|
||||
type="text"
|
||||
type="search"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
class="ant-input-group-addon"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-input-search-button ant-btn-primary ant-btn-lg"
|
||||
class="ant-btn ant-btn-primary ant-btn-lg ant-input-search-button"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
|
||||
@@ -20,6 +20,7 @@ exports[`AutoComplete legacy dataSource should accept react element option 1`] =
|
||||
autocomplete="off"
|
||||
class="ant-select-selection-search-input"
|
||||
role="combobox"
|
||||
type="search"
|
||||
value=""
|
||||
/>
|
||||
</span>
|
||||
@@ -63,6 +64,7 @@ exports[`AutoComplete legacy dataSource should accept react element option 1`] =
|
||||
<div
|
||||
aria-selected="false"
|
||||
class="ant-select-item ant-select-item-option ant-select-item-option-active"
|
||||
title="ReactNode"
|
||||
>
|
||||
<div
|
||||
class="ant-select-item-option-content"
|
||||
@@ -88,7 +90,7 @@ exports[`AutoComplete legacy dataSource should accept react element option 1`] =
|
||||
|
||||
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"
|
||||
class="ant-select ant-select-rtl ant-select-auto-complete ant-select-single ant-select-show-search"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selector"
|
||||
@@ -105,6 +107,7 @@ exports[`AutoComplete rtl render component should be rendered correctly in RTL d
|
||||
autocomplete="off"
|
||||
class="ant-select-selection-search-input"
|
||||
role="combobox"
|
||||
type="search"
|
||||
value=""
|
||||
/>
|
||||
</span>
|
||||
|
||||
@@ -69,4 +69,13 @@ describe('AutoComplete', () => {
|
||||
wrapper.find('input').simulate('change', { target: { value: '1' } });
|
||||
expect(wrapper.find('.ant-select-item-option').length).toBe(2);
|
||||
});
|
||||
|
||||
it('should not warning when getInputElement is null', () => {
|
||||
jest.spyOn(console, 'warn').mockImplementation(() => undefined);
|
||||
mount(<AutoComplete placeholder="input here" allowClear />);
|
||||
// eslint-disable-next-line no-console
|
||||
expect(console.warn).not.toBeCalled();
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn.mockRestore();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,7 +7,7 @@ title:
|
||||
|
||||
## zh-CN
|
||||
|
||||
基本使用。通过 options 设置自动完成的数据源
|
||||
基本使用,通过 `options` 设置自动完成的数据源。
|
||||
|
||||
## en-US
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@ When there is a need for autocomplete functionality.
|
||||
| defaultActiveFirstOption | Whether active first option by default | boolean | true | |
|
||||
| defaultValue | Initial selected option | string | - | |
|
||||
| disabled | Whether disabled select | boolean | false | |
|
||||
| dropdownClassName | The className of dropdown menu | string | - | |
|
||||
| dropdownMatchSelectWidth | Determine whether the dropdown menu and the select input are the same width. Default set `min-width` same as input. Will ignore when value less than select width. `false` will disable virtual scroll | boolean \| number | true | |
|
||||
| filterOption | If true, filter options by input, if function, filter options against it. The function will receive two arguments, `inputValue` and `option`, if the function returns true, the option will be included in the filtered set; Otherwise, it will be excluded | boolean \| function(inputValue, option) | true | |
|
||||
| placeholder | The placeholder of input | string | - | |
|
||||
| value | Selected option | string | - | |
|
||||
@@ -34,6 +36,7 @@ When there is a need for autocomplete functionality.
|
||||
| onSelect | Called when a option is selected. param is option's value and option instance | function(value, option) | - | |
|
||||
| defaultOpen | Initial open state of dropdown | boolean | - | |
|
||||
| open | Controlled open state of dropdown | boolean | - | |
|
||||
| options | Select options. Will get better perf than jsx definition | { label, value }[] | - | |
|
||||
| onDropdownVisibleChange | Call when dropdown open | function(open) | - | |
|
||||
| notFoundContent | Specify content to show when no result matches | string | `Not Found` | |
|
||||
|
||||
@@ -55,3 +58,25 @@ Related issue: [#18230](https://github.com/ant-design/ant-design/issues/18230) [
|
||||
### Part of api from v3 not available in v4?
|
||||
|
||||
AutoComplete is a Input component support auto complete tips which should not support `labelInValue` prop to modify dispaly value in input. In v3, AutoComplete realization can not handle case that user type match of both `value` & `label` are the same. v4 not longer support `label` as the value input.
|
||||
|
||||
Besides, to unique API, `dataSource` replaced with `options`:
|
||||
|
||||
#### v3
|
||||
|
||||
```tsx
|
||||
dataSource = ['light', 'bamboo'];
|
||||
// or
|
||||
dataSource = [
|
||||
{ value: 'light', text: 'Light' },
|
||||
{ value: 'bamboo', text: 'Bamboo' },
|
||||
];
|
||||
```
|
||||
|
||||
#### v4
|
||||
|
||||
```tsx
|
||||
options = [
|
||||
{ value: 'light', label: 'Light' },
|
||||
{ value: 'bamboo', label: 'Bamboo' },
|
||||
];
|
||||
```
|
||||
|
||||
@@ -46,7 +46,7 @@ const AutoComplete: React.ForwardRefRenderFunction<Select, AutoCompleteProps> =
|
||||
React.useImperativeHandle<Select, Select>(ref, () => selectRef.current!);
|
||||
|
||||
// ============================= Input =============================
|
||||
let customizeInput: React.ReactElement;
|
||||
let customizeInput: React.ReactElement | undefined;
|
||||
|
||||
if (
|
||||
childNodes.length === 1 &&
|
||||
@@ -56,7 +56,7 @@ const AutoComplete: React.ForwardRefRenderFunction<Select, AutoCompleteProps> =
|
||||
[customizeInput] = childNodes;
|
||||
}
|
||||
|
||||
const getInputElement = (): React.ReactElement => customizeInput;
|
||||
const getInputElement = customizeInput ? (): React.ReactElement => customizeInput! : undefined;
|
||||
|
||||
// ============================ Options ============================
|
||||
let optionChildren: React.ReactNode;
|
||||
@@ -117,7 +117,7 @@ const AutoComplete: React.ForwardRefRenderFunction<Select, AutoCompleteProps> =
|
||||
ref={selectRef as any}
|
||||
{...omit(props, ['dataSource'])}
|
||||
prefixCls={prefixCls}
|
||||
className={classNames(className, `${prefixCls}-auto-complete`)}
|
||||
className={classNames(`${prefixCls}-auto-complete`, className)}
|
||||
mode={Select.SECRET_COMBOBOX_MODE_DO_NOT_USE as any}
|
||||
getInputElement={getInputElement}
|
||||
>
|
||||
@@ -131,10 +131,10 @@ const AutoComplete: React.ForwardRefRenderFunction<Select, AutoCompleteProps> =
|
||||
|
||||
const RefAutoComplete = React.forwardRef<Select, AutoCompleteProps>(AutoComplete);
|
||||
|
||||
type RefAutoComplete = typeof RefAutoComplete & {
|
||||
type RefAutoCompleteWithOption = typeof RefAutoComplete & {
|
||||
Option: OptionType;
|
||||
};
|
||||
|
||||
(RefAutoComplete as RefAutoComplete).Option = Option;
|
||||
(RefAutoComplete as RefAutoCompleteWithOption).Option = Option;
|
||||
|
||||
export default RefAutoComplete as RefAutoComplete;
|
||||
export default RefAutoComplete as RefAutoCompleteWithOption;
|
||||
|
||||
@@ -25,6 +25,8 @@ cover: https://gw.alipayobjects.com/zos/alicdn/qtJm4yt45/AutoComplete.svg
|
||||
| defaultActiveFirstOption | 是否默认高亮第一个选项 | boolean | true | |
|
||||
| defaultValue | 指定默认选中的条目 | string | - | |
|
||||
| disabled | 是否禁用 | boolean | false | |
|
||||
| dropdownClassName | 下拉菜单的 className 属性 | string | - | |
|
||||
| dropdownMatchSelectWidth | 下拉菜单和选择器同宽。默认将设置 `min-width`,当值小于选择框宽度时会被忽略。false 时会关闭虚拟滚动 | boolean \| number | true | |
|
||||
| filterOption | 是否根据输入项进行筛选。当其为一个函数时,会接收 `inputValue` `option` 两个参数,当 `option` 符合筛选条件时,应返回 true,反之则返回 false | boolean \| function(inputValue, option) | true | |
|
||||
| getPopupContainer | 菜单渲染父节点。默认渲染到 body 上,如果你遇到菜单滚动定位问题,试试修改为滚动的区域,并相对其定位。[示例](https://codesandbox.io/s/4j168r7jw0) | function(triggerNode) | () => document.body | |
|
||||
| placeholder | 输入框提示 | string | - | |
|
||||
@@ -36,6 +38,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/qtJm4yt45/AutoComplete.svg
|
||||
| onSelect | 被选中时调用,参数为选中项的 value 值 | function(value, option) | - | |
|
||||
| defaultOpen | 是否默认展开下拉菜单 | boolean | - | |
|
||||
| open | 是否展开下拉菜单 | boolean | - | |
|
||||
| options | 数据化配置选项内容,相比 jsx 定义会获得更好的渲染性能 | { label, value }[] | - | |
|
||||
| onDropdownVisibleChange | 展开下拉菜单的回调 | function(open) | - | |
|
||||
| notFoundContent | 当下拉列表为空时显示的内容 | ReactNode | - | |
|
||||
|
||||
@@ -57,3 +60,25 @@ cover: https://gw.alipayobjects.com/zos/alicdn/qtJm4yt45/AutoComplete.svg
|
||||
### v3 的部分属性为何在 v4 中没有了?
|
||||
|
||||
AutoComplete 组件是一个支持自动提示的 Input 组件,因而其不具有 `labelInValue` 等影响 value 展示的属性。在 v3 版本,AutoComplete 实现存在输入值如果遇到 `value` 与 `label` 相同时无法映射的问题。 v4 中不再支持 `label` 为值的输入形态。
|
||||
|
||||
此外为了统一 API,`dataSource` 改为 `options` 你可以如下转换:
|
||||
|
||||
#### v3
|
||||
|
||||
```tsx
|
||||
dataSource = ['light', 'bamboo'];
|
||||
// or
|
||||
dataSource = [
|
||||
{ value: 'light', text: 'Light' },
|
||||
{ value: 'bamboo', text: 'Bamboo' },
|
||||
];
|
||||
```
|
||||
|
||||
#### v4
|
||||
|
||||
```tsx
|
||||
options = [
|
||||
{ value: 'light', label: 'Light' },
|
||||
{ value: 'bamboo', label: 'Bamboo' },
|
||||
];
|
||||
```
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { mount } from 'enzyme';
|
||||
import Avatar from '..';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
import rtlTest from '../../../tests/shared/rtlTest';
|
||||
import useBreakpoint from '../../grid/hooks/useBreakpoint';
|
||||
|
||||
jest.mock('../../grid/hooks/useBreakpoint');
|
||||
|
||||
describe('Avatar Render', () => {
|
||||
mountTest(Avatar);
|
||||
rtlTest(Avatar);
|
||||
|
||||
const sizes = { xs: 24, sm: 32, md: 40, lg: 64, xl: 80, xxl: 100 };
|
||||
let originOffsetWidth;
|
||||
beforeAll(() => {
|
||||
// Mock offsetHeight
|
||||
@@ -152,6 +158,19 @@ describe('Avatar Render', () => {
|
||||
expect(wrapper).toMatchRenderedSnapshot();
|
||||
});
|
||||
|
||||
Object.entries(sizes).forEach(([key, value]) => {
|
||||
it(`adjusts component size to ${value} when window size is ${key}`, () => {
|
||||
const wrapper = global.document.createElement('div');
|
||||
|
||||
useBreakpoint.mockReturnValue({ [key]: true });
|
||||
act(() => {
|
||||
ReactDOM.render(<Avatar size={sizes} />, wrapper);
|
||||
});
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
it('support onMouseEnter', () => {
|
||||
const onMouseEnter = jest.fn();
|
||||
const wrapper = mount(<Avatar onMouseEnter={onMouseEnter}>TestString</Avatar>);
|
||||
|
||||
@@ -1,5 +1,89 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Avatar Render adjusts component size to 24 when window size is xs 1`] = `
|
||||
<div>
|
||||
<span
|
||||
class="ant-avatar ant-avatar-circle"
|
||||
style="width: 24px; height: 24px; line-height: 24px; font-size: 18px;"
|
||||
>
|
||||
<span
|
||||
class="ant-avatar-string"
|
||||
style="transform: scale(0.32) translateX(-50%);"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Avatar Render adjusts component size to 32 when window size is sm 1`] = `
|
||||
<div>
|
||||
<span
|
||||
class="ant-avatar ant-avatar-circle"
|
||||
style="width: 32px; height: 32px; line-height: 32px; font-size: 18px;"
|
||||
>
|
||||
<span
|
||||
class="ant-avatar-string"
|
||||
style="transform: scale(0.32) translateX(-50%);"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Avatar Render adjusts component size to 40 when window size is md 1`] = `
|
||||
<div>
|
||||
<span
|
||||
class="ant-avatar ant-avatar-circle"
|
||||
style="width: 40px; height: 40px; line-height: 40px; font-size: 18px;"
|
||||
>
|
||||
<span
|
||||
class="ant-avatar-string"
|
||||
style="transform: scale(0.32) translateX(-50%);"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Avatar Render adjusts component size to 64 when window size is lg 1`] = `
|
||||
<div>
|
||||
<span
|
||||
class="ant-avatar ant-avatar-circle"
|
||||
style="width: 64px; height: 64px; line-height: 64px; font-size: 18px;"
|
||||
>
|
||||
<span
|
||||
class="ant-avatar-string"
|
||||
style="transform: scale(0.32) translateX(-50%);"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Avatar Render adjusts component size to 80 when window size is xl 1`] = `
|
||||
<div>
|
||||
<span
|
||||
class="ant-avatar ant-avatar-circle"
|
||||
style="width: 80px; height: 80px; line-height: 80px; font-size: 18px;"
|
||||
>
|
||||
<span
|
||||
class="ant-avatar-string"
|
||||
style="transform: scale(0.32) translateX(-50%);"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Avatar Render adjusts component size to 100 when window size is xxl 1`] = `
|
||||
<div>
|
||||
<span
|
||||
class="ant-avatar ant-avatar-circle"
|
||||
style="width: 100px; height: 100px; line-height: 100px; font-size: 18px;"
|
||||
>
|
||||
<span
|
||||
class="ant-avatar-string"
|
||||
style="transform: scale(0.32) translateX(-50%);"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Avatar Render fallback 1`] = `
|
||||
<span
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
@@ -97,18 +181,22 @@ exports[`Avatar Render should show image on success after a failure state 1`] =
|
||||
className="ant-avatar ant-avatar-circle"
|
||||
style={Object {}}
|
||||
>
|
||||
<span
|
||||
className="ant-avatar-string"
|
||||
style={
|
||||
Object {
|
||||
"WebkitTransform": "scale(0.72) translateX(-50%)",
|
||||
"msTransform": "scale(0.72) translateX(-50%)",
|
||||
"transform": "scale(0.72) translateX(-50%)",
|
||||
}
|
||||
}
|
||||
<ResizeObserver
|
||||
onResize={[Function]}
|
||||
>
|
||||
Fallback
|
||||
</span>
|
||||
<span
|
||||
className="ant-avatar-string"
|
||||
style={
|
||||
Object {
|
||||
"WebkitTransform": "scale(1) translateX(-50%)",
|
||||
"msTransform": "scale(1) translateX(-50%)",
|
||||
"transform": "scale(1) translateX(-50%)",
|
||||
}
|
||||
}
|
||||
>
|
||||
Fallback
|
||||
</span>
|
||||
</ResizeObserver>
|
||||
</span>
|
||||
</Avatar>
|
||||
`;
|
||||
|
||||
@@ -469,6 +469,25 @@ Array [
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders ./components/avatar/demo/fallback.md correctly 1`] = `
|
||||
Array [
|
||||
<span
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="http://abc.com/not-exist.jpg"
|
||||
/>
|
||||
</span>,
|
||||
<span
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="http://abc.com/not-exist.jpg"
|
||||
/>
|
||||
</span>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders ./components/avatar/demo/group.md correctly 1`] = `
|
||||
Array [
|
||||
<div
|
||||
@@ -583,23 +602,31 @@ Array [
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders ./components/avatar/demo/fallback.md correctly 1`] = `
|
||||
Array [
|
||||
exports[`renders ./components/avatar/demo/responsive.md correctly 1`] = `
|
||||
<span
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-icon"
|
||||
>
|
||||
<span
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
aria-label="ant-design"
|
||||
class="anticon anticon-ant-design"
|
||||
role="img"
|
||||
>
|
||||
<img
|
||||
src="http://abc.com/not-exist.jpg"
|
||||
/>
|
||||
</span>,
|
||||
<span
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="http://abc.com/not-exist.jpg"
|
||||
/>
|
||||
</span>,
|
||||
]
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="ant-design"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M716.3 313.8c19-18.9 19-49.7 0-68.6l-69.9-69.9.1.1c-18.5-18.5-50.3-50.3-95.3-95.2-21.2-20.7-55.5-20.5-76.5.5L80.9 474.2a53.84 53.84 0 000 76.4L474.6 944a54.14 54.14 0 0076.5 0l165.1-165c19-18.9 19-49.7 0-68.6a48.7 48.7 0 00-68.7 0l-125 125.2c-5.2 5.2-13.3 5.2-18.5 0L189.5 521.4c-5.2-5.2-5.2-13.3 0-18.5l314.4-314.2c.4-.4.9-.7 1.3-1.1 5.2-4.1 12.4-3.7 17.2 1.1l125.2 125.1c19 19 49.8 19 68.7 0zM408.6 514.4a106.3 106.2 0 10212.6 0 106.3 106.2 0 10-212.6 0zm536.2-38.6L821.9 353.5c-19-18.9-49.8-18.9-68.7.1a48.4 48.4 0 000 68.6l83 82.9c5.2 5.2 5.2 13.3 0 18.5l-81.8 81.7a48.4 48.4 0 000 68.6 48.7 48.7 0 0068.7 0l121.8-121.7a53.93 53.93 0 00-.1-76.4z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/avatar/demo/toggle-debug.md correctly 1`] = `
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import * as React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import ResizeObserver from 'rc-resize-observer';
|
||||
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import devWarning from '../_util/devWarning';
|
||||
import { composeRef } from '../_util/ref';
|
||||
import { Breakpoint, responsiveArray, ScreenSizeMap } from '../_util/responsiveObserve';
|
||||
import useBreakpoint from '../grid/hooks/useBreakpoint';
|
||||
|
||||
export interface AvatarProps {
|
||||
/** Shape of avatar, options:`circle`, `square` */
|
||||
@@ -12,7 +15,7 @@ export interface AvatarProps {
|
||||
* Size of avatar, options: `large`, `small`, `default`
|
||||
* or a custom number size
|
||||
* */
|
||||
size?: 'large' | 'small' | 'default' | number;
|
||||
size?: 'large' | 'small' | 'default' | number | ScreenSizeMap;
|
||||
gap?: number;
|
||||
/** Src of image avatar */
|
||||
src?: string;
|
||||
@@ -41,9 +44,6 @@ const InternalAvatar: React.ForwardRefRenderFunction<unknown, AvatarProps> = (pr
|
||||
|
||||
const avatarNodeMergeRef = composeRef(ref, avatarNodeRef);
|
||||
|
||||
let lastChildrenWidth: number;
|
||||
let lastNodeWidth: number;
|
||||
|
||||
const { getPrefixCls } = React.useContext(ConfigContext);
|
||||
|
||||
const setScaleParam = () => {
|
||||
@@ -52,19 +52,12 @@ const InternalAvatar: React.ForwardRefRenderFunction<unknown, AvatarProps> = (pr
|
||||
}
|
||||
const childrenWidth = avatarChildrenRef.current.offsetWidth; // offsetWidth avoid affecting be transform scale
|
||||
const nodeWidth = avatarNodeRef.current.offsetWidth;
|
||||
const { gap = 4 } = props;
|
||||
// denominator is 0 is no meaning
|
||||
if (
|
||||
childrenWidth !== 0 &&
|
||||
nodeWidth !== 0 &&
|
||||
(lastChildrenWidth !== childrenWidth || lastNodeWidth !== nodeWidth)
|
||||
) {
|
||||
lastChildrenWidth = childrenWidth;
|
||||
lastNodeWidth = nodeWidth;
|
||||
}
|
||||
|
||||
if (gap * 2 < nodeWidth) {
|
||||
setScale(nodeWidth - gap * 2 < childrenWidth ? (nodeWidth - gap * 2) / childrenWidth : 1);
|
||||
if (childrenWidth !== 0 && nodeWidth !== 0) {
|
||||
const { gap = 4 } = props;
|
||||
if (gap * 2 < nodeWidth) {
|
||||
setScale(nodeWidth - gap * 2 < childrenWidth ? (nodeWidth - gap * 2) / childrenWidth : 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -79,13 +72,7 @@ const InternalAvatar: React.ForwardRefRenderFunction<unknown, AvatarProps> = (pr
|
||||
|
||||
React.useEffect(() => {
|
||||
setScaleParam();
|
||||
}, [props.children, props.gap, props.size]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (props.children) {
|
||||
setScaleParam();
|
||||
}
|
||||
}, [isImgExist]);
|
||||
}, [props.gap]);
|
||||
|
||||
const handleImgLoadError = () => {
|
||||
const { onError } = props;
|
||||
@@ -109,6 +96,25 @@ const InternalAvatar: React.ForwardRefRenderFunction<unknown, AvatarProps> = (pr
|
||||
...others
|
||||
} = props;
|
||||
|
||||
const screens = useBreakpoint();
|
||||
const responsiveSizeStyle: React.CSSProperties = React.useMemo(() => {
|
||||
if (typeof size !== 'object') {
|
||||
return {};
|
||||
}
|
||||
|
||||
const currentBreakpoint: Breakpoint = responsiveArray.find(screen => screens[screen])!;
|
||||
const currentSize = size[currentBreakpoint];
|
||||
|
||||
return currentSize
|
||||
? {
|
||||
width: currentSize,
|
||||
height: currentSize,
|
||||
lineHeight: `${currentSize}px`,
|
||||
fontSize: icon ? currentSize / 2 : 18,
|
||||
}
|
||||
: {};
|
||||
}, [screens, size]);
|
||||
|
||||
devWarning(
|
||||
!(typeof icon === 'string' && icon.length > 2),
|
||||
'Avatar',
|
||||
@@ -122,11 +128,16 @@ const InternalAvatar: React.ForwardRefRenderFunction<unknown, AvatarProps> = (pr
|
||||
[`${prefixCls}-sm`]: size === 'small',
|
||||
});
|
||||
|
||||
const classString = classNames(prefixCls, className, sizeCls, {
|
||||
[`${prefixCls}-${shape}`]: shape,
|
||||
[`${prefixCls}-image`]: src && isImgExist,
|
||||
[`${prefixCls}-icon`]: icon,
|
||||
});
|
||||
const classString = classNames(
|
||||
prefixCls,
|
||||
sizeCls,
|
||||
{
|
||||
[`${prefixCls}-${shape}`]: shape,
|
||||
[`${prefixCls}-image`]: src && isImgExist,
|
||||
[`${prefixCls}-icon`]: icon,
|
||||
},
|
||||
className,
|
||||
);
|
||||
|
||||
const sizeStyle: React.CSSProperties =
|
||||
typeof size === 'number'
|
||||
@@ -161,15 +172,17 @@ const InternalAvatar: React.ForwardRefRenderFunction<unknown, AvatarProps> = (pr
|
||||
: {};
|
||||
|
||||
childrenToRender = (
|
||||
<span
|
||||
className={`${prefixCls}-string`}
|
||||
ref={(node: HTMLElement) => {
|
||||
avatarChildrenRef.current = node;
|
||||
}}
|
||||
style={{ ...sizeChildrenStyle, ...childrenStyle }}
|
||||
>
|
||||
{children}
|
||||
</span>
|
||||
<ResizeObserver onResize={setScaleParam}>
|
||||
<span
|
||||
className={`${prefixCls}-string`}
|
||||
ref={(node: HTMLElement) => {
|
||||
avatarChildrenRef.current = node;
|
||||
}}
|
||||
style={{ ...sizeChildrenStyle, ...childrenStyle }}
|
||||
>
|
||||
{children}
|
||||
</span>
|
||||
</ResizeObserver>
|
||||
);
|
||||
} else {
|
||||
childrenToRender = (
|
||||
@@ -193,7 +206,7 @@ const InternalAvatar: React.ForwardRefRenderFunction<unknown, AvatarProps> = (pr
|
||||
return (
|
||||
<span
|
||||
{...others}
|
||||
style={{ ...sizeStyle, ...others.style }}
|
||||
style={{ ...sizeStyle, ...responsiveSizeStyle, ...others.style }}
|
||||
className={classString}
|
||||
ref={avatarNodeMergeRef as any}
|
||||
>
|
||||
|
||||
27
components/avatar/demo/responsive.md
Normal file
27
components/avatar/demo/responsive.md
Normal file
@@ -0,0 +1,27 @@
|
||||
---
|
||||
order: 5
|
||||
title:
|
||||
zh-CN: 响应式尺寸
|
||||
en-US: Responsive Size
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
头像大小可以根据屏幕大小自动调整。
|
||||
|
||||
## en-US
|
||||
|
||||
Avatar size can be automatically adjusted based on the screen size.
|
||||
|
||||
```tsx
|
||||
import { Avatar } from 'antd';
|
||||
import { AntDesignOutlined } from '@ant-design/icons';
|
||||
|
||||
ReactDOM.render(
|
||||
<Avatar
|
||||
size={{ xs: 24, sm: 32, md: 40, lg: 64, xl: 80, xxl: 100 }}
|
||||
icon={<AntDesignOutlined />}
|
||||
/>,
|
||||
mountNode,
|
||||
);
|
||||
```
|
||||
@@ -15,7 +15,7 @@ Avatars can be used to represent people or objects. It supports images, `Icon`s,
|
||||
| --- | --- | --- | --- | --- |
|
||||
| icon | Custom icon type for an icon avatar | ReactNode | - | |
|
||||
| shape | The shape of avatar | `circle` \| `square` | `circle` | |
|
||||
| size | The size of the avatar | number \| `large` \| `small` \| `default` | `default` | |
|
||||
| size | The size of the avatar | number \| `large` \| `small` \| `default` \| `{ xs: number, sm: number, ...}` | `default` | 4.7.0 |
|
||||
| src | The address of the image for an image avatar | string | - | |
|
||||
| srcSet | A list of sources to use for different screen resolutions | string | - | |
|
||||
| alt | This attribute defines the alternative text describing the image | string | - | |
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import * as React from 'react';
|
||||
import InternalAvatar, { AvatarProps } from './avatar';
|
||||
import Group from './group';
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ cover: https://gw.alipayobjects.com/zos/antfincdn/aBcnbw68hP/Avatar.svg
|
||||
|
||||
## 设计师专属
|
||||
|
||||
安装 [Kitchen Sketch 插件 💎](https://kitchen.alipay.com),一键填充高逼格头像和文本.
|
||||
安装 [Kitchen Sketch 插件 💎](https://kitchen.alipay.com),一键填充高逼格头像和文本。
|
||||
|
||||
## API
|
||||
|
||||
@@ -20,7 +20,7 @@ cover: https://gw.alipayobjects.com/zos/antfincdn/aBcnbw68hP/Avatar.svg
|
||||
| --- | --- | --- | --- | --- |
|
||||
| icon | 设置头像的自定义图标 | ReactNode | - | |
|
||||
| shape | 指定头像的形状 | `circle` \| `square` | `circle` | |
|
||||
| size | 设置头像的大小 | number \| `large` \| `small` \| `default` | `default` | |
|
||||
| size | 设置头像的大小 | number \| `large` \| `small` \| `default` \| `{ xs: number, sm: number, ...}` | `default` | 4.7.0 |
|
||||
| src | 图片类头像的资源地址 | string | - | |
|
||||
| srcSet | 设置图片类头像响应式资源地址 | string | - | |
|
||||
| alt | 图像无法显示时的替代文本 | string | - | |
|
||||
|
||||
@@ -2,4 +2,5 @@ import '../../style/index.less';
|
||||
import './index.less';
|
||||
|
||||
// style dependencies
|
||||
// deps-lint-skip: grid
|
||||
import '../../popover/style';
|
||||
|
||||
@@ -4,7 +4,7 @@ import addEventListener from 'rc-util/lib/Dom/addEventListener';
|
||||
import classNames from 'classnames';
|
||||
import omit from 'omit.js';
|
||||
import VerticalAlignTopOutlined from '@ant-design/icons/VerticalAlignTopOutlined';
|
||||
import throttleByAnimationFrame from '../_util/throttleByAnimationFrame';
|
||||
import { throttleByAnimationFrame } from '../_util/throttleByAnimationFrame';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import getScroll from '../_util/getScroll';
|
||||
import scrollTo from '../_util/scrollTo';
|
||||
@@ -98,9 +98,13 @@ const BackTop: React.FC<BackTopProps> = props => {
|
||||
const { getPrefixCls, direction } = React.useContext(ConfigContext);
|
||||
const { prefixCls: customizePrefixCls, className = '' } = props;
|
||||
const prefixCls = getPrefixCls('back-top', customizePrefixCls);
|
||||
const classString = classNames(prefixCls, className, {
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
});
|
||||
const classString = classNames(
|
||||
prefixCls,
|
||||
{
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
},
|
||||
className,
|
||||
);
|
||||
|
||||
// fix https://fb.me/react-unknown-prop
|
||||
const divProps = omit(props, [
|
||||
|
||||
@@ -32,11 +32,11 @@
|
||||
text-align: center;
|
||||
background-color: @back-top-bg;
|
||||
border-radius: 20px;
|
||||
transition: all 0.3s @ease-in-out;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
background-color: @back-top-hover-bg;
|
||||
transition: all 0.3s @ease-in-out;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,10 +29,15 @@ const Ribbon: React.FC<RibbonProps> = function Ribbon({
|
||||
const { getPrefixCls, direction } = React.useContext(ConfigContext);
|
||||
const prefixCls = getPrefixCls('ribbon', customizePrefixCls);
|
||||
const colorInPreset = isPresetColor(color);
|
||||
const ribbonCls = classNames(prefixCls, className, `${prefixCls}-placement-${placement}`, {
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
[`${prefixCls}-color-${color}`]: colorInPreset,
|
||||
});
|
||||
const ribbonCls = classNames(
|
||||
prefixCls,
|
||||
`${prefixCls}-placement-${placement}`,
|
||||
{
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
[`${prefixCls}-color-${color}`]: colorInPreset,
|
||||
},
|
||||
className,
|
||||
);
|
||||
const colorStyle: React.CSSProperties = {};
|
||||
const cornerColorStyle: React.CSSProperties = {};
|
||||
if (color && !colorInPreset) {
|
||||
@@ -43,7 +48,7 @@ const Ribbon: React.FC<RibbonProps> = function Ribbon({
|
||||
<div className={`${prefixCls}-wrapper`}>
|
||||
{children}
|
||||
<div className={ribbonCls} style={{ ...colorStyle, ...style }}>
|
||||
{text}
|
||||
<span className={`${prefixCls}-text`}>{text}</span>
|
||||
<div className={`${prefixCls}-corner`} style={cornerColorStyle} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1318,7 +1318,7 @@ exports[`renders ./components/badge/demo/no-wrapper.md correctly 1`] = `
|
||||
</sup>
|
||||
</span>
|
||||
<span
|
||||
class="site-badge-count-4 ant-badge ant-badge-not-a-wrapper"
|
||||
class="ant-badge ant-badge-not-a-wrapper site-badge-count-4"
|
||||
>
|
||||
<sup
|
||||
class="ant-scroll-number ant-badge-count"
|
||||
@@ -1483,7 +1483,7 @@ exports[`renders ./components/badge/demo/no-wrapper.md correctly 1`] = `
|
||||
</sup>
|
||||
</span>
|
||||
<span
|
||||
class="site-badge-count-109 ant-badge ant-badge-not-a-wrapper"
|
||||
class="ant-badge ant-badge-not-a-wrapper site-badge-count-109"
|
||||
>
|
||||
<sup
|
||||
class="ant-scroll-number ant-badge-count ant-badge-multiple-words"
|
||||
@@ -2060,7 +2060,11 @@ exports[`renders ./components/badge/demo/ribbbon.md correctly 1`] = `
|
||||
<div
|
||||
class="ant-ribbon ant-ribbon-placement-end"
|
||||
>
|
||||
Pushes open the window
|
||||
<span
|
||||
class="ant-ribbon-text"
|
||||
>
|
||||
Pushes open the window
|
||||
</span>
|
||||
<div
|
||||
class="ant-ribbon-corner"
|
||||
/>
|
||||
@@ -2092,7 +2096,11 @@ exports[`renders ./components/badge/demo/ribbon-debug.md correctly 1`] = `
|
||||
<div
|
||||
class="ant-ribbon ant-ribbon-placement-end"
|
||||
>
|
||||
啦啦啦啦
|
||||
<span
|
||||
class="ant-ribbon-text"
|
||||
>
|
||||
啦啦啦啦
|
||||
</span>
|
||||
<div
|
||||
class="ant-ribbon-corner"
|
||||
/>
|
||||
@@ -2118,7 +2126,11 @@ exports[`renders ./components/badge/demo/ribbon-debug.md correctly 1`] = `
|
||||
<div
|
||||
class="ant-ribbon ant-ribbon-placement-end ant-ribbon-color-purple"
|
||||
>
|
||||
啦啦啦啦
|
||||
<span
|
||||
class="ant-ribbon-text"
|
||||
>
|
||||
啦啦啦啦
|
||||
</span>
|
||||
<div
|
||||
class="ant-ribbon-corner"
|
||||
/>
|
||||
@@ -2145,7 +2157,11 @@ exports[`renders ./components/badge/demo/ribbon-debug.md correctly 1`] = `
|
||||
class="ant-ribbon ant-ribbon-placement-end"
|
||||
style="background:#2db7f5"
|
||||
>
|
||||
啦啦啦啦
|
||||
<span
|
||||
class="ant-ribbon-text"
|
||||
>
|
||||
啦啦啦啦
|
||||
</span>
|
||||
<div
|
||||
class="ant-ribbon-corner"
|
||||
style="color:#2db7f5"
|
||||
@@ -2173,7 +2189,11 @@ exports[`renders ./components/badge/demo/ribbon-debug.md correctly 1`] = `
|
||||
class="ant-ribbon ant-ribbon-placement-start"
|
||||
style="background:#2db7f5"
|
||||
>
|
||||
啦啦啦啦
|
||||
<span
|
||||
class="ant-ribbon-text"
|
||||
>
|
||||
啦啦啦啦
|
||||
</span>
|
||||
<div
|
||||
class="ant-ribbon-corner"
|
||||
style="color:#2db7f5"
|
||||
@@ -2200,7 +2220,11 @@ exports[`renders ./components/badge/demo/ribbon-debug.md correctly 1`] = `
|
||||
class="ant-ribbon ant-ribbon-placement-end"
|
||||
style="background:#2db7f5"
|
||||
>
|
||||
啦啦啦啦
|
||||
<span
|
||||
class="ant-ribbon-text"
|
||||
>
|
||||
啦啦啦啦
|
||||
</span>
|
||||
<div
|
||||
class="ant-ribbon-corner"
|
||||
style="color:#2db7f5"
|
||||
|
||||
@@ -3505,6 +3505,9 @@ exports[`Ribbon rtl render component should be rendered correctly in RTL directi
|
||||
<div
|
||||
class="ant-ribbon ant-ribbon-placement-end ant-ribbon-rtl"
|
||||
>
|
||||
<span
|
||||
class="ant-ribbon-text"
|
||||
/>
|
||||
<div
|
||||
class="ant-ribbon-corner"
|
||||
/>
|
||||
|
||||
@@ -62,7 +62,8 @@ const Badge: CompoundedComponent = ({
|
||||
return displayCount as string | number | null;
|
||||
};
|
||||
|
||||
const hasStatus = (): boolean => (status !== null && status !== undefined) || (color !== null && color !== undefined);
|
||||
const hasStatus = (): boolean =>
|
||||
(status !== null && status !== undefined) || (color !== null && color !== undefined);
|
||||
|
||||
const isZero = () => {
|
||||
const numberedDisplayCount = getNumberedDisplayCount();
|
||||
@@ -177,11 +178,15 @@ const Badge: CompoundedComponent = ({
|
||||
statusStyle.background = color;
|
||||
}
|
||||
|
||||
const badgeClassName = classNames(className, prefixCls, {
|
||||
[`${prefixCls}-status`]: hasStatus(),
|
||||
[`${prefixCls}-not-a-wrapper`]: !children,
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
});
|
||||
const badgeClassName = classNames(
|
||||
prefixCls,
|
||||
{
|
||||
[`${prefixCls}-status`]: hasStatus(),
|
||||
[`${prefixCls}-not-a-wrapper`]: !children,
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
},
|
||||
className,
|
||||
);
|
||||
|
||||
// <Badge status="success" />
|
||||
if (!children && hasStatus()) {
|
||||
|
||||
@@ -21,12 +21,16 @@
|
||||
background-color: @primary-color;
|
||||
border-radius: @border-radius-sm;
|
||||
|
||||
&-text {
|
||||
color: @white;
|
||||
}
|
||||
|
||||
&-corner {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
color: @primary-color;
|
||||
color: currentColor;
|
||||
border: 4px solid;
|
||||
transform: scaleY(0.75);
|
||||
transform-origin: top;
|
||||
@@ -50,10 +54,8 @@
|
||||
@color: extract(@preset-colors, @i);
|
||||
@darkColor: '@{color}-6';
|
||||
&-color-@{color} {
|
||||
background-color: @@darkColor;
|
||||
.@{ribbon-prefix-cls}-corner {
|
||||
color: @@darkColor;
|
||||
}
|
||||
color: @@darkColor;
|
||||
background: @@darkColor;
|
||||
}
|
||||
}
|
||||
.make-color-classes();
|
||||
@@ -65,20 +67,15 @@
|
||||
.@{ribbon-prefix-cls}-corner {
|
||||
right: 0;
|
||||
border-color: currentColor transparent transparent currentColor;
|
||||
&::after {
|
||||
border-color: currentColor transparent transparent currentColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.@{ribbon-prefix-cls}-placement-start {
|
||||
left: -8px;
|
||||
border-bottom-left-radius: 0;
|
||||
.@{ribbon-prefix-cls}-corner {
|
||||
left: 0;
|
||||
border-color: currentColor currentColor transparent transparent;
|
||||
&::after {
|
||||
border-color: currentColor currentColor transparent transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,9 +135,13 @@ const Breadcrumb: BreadcrumbInterface = ({
|
||||
});
|
||||
}
|
||||
|
||||
const breadcrumbClassName = classNames(className, prefixCls, {
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
});
|
||||
const breadcrumbClassName = classNames(
|
||||
prefixCls,
|
||||
{
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
},
|
||||
className,
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={breadcrumbClassName} style={style} {...restProps}>
|
||||
|
||||
@@ -116,7 +116,7 @@ exports[`Breadcrumb should render a menu 1`] = `
|
||||
</span>
|
||||
<span>
|
||||
<span
|
||||
class="ant-breadcrumb-overlay-link ant-dropdown-trigger"
|
||||
class="ant-dropdown-trigger ant-breadcrumb-overlay-link"
|
||||
>
|
||||
<span
|
||||
class="ant-breadcrumb-link"
|
||||
|
||||
@@ -97,7 +97,7 @@ exports[`renders ./components/breadcrumb/demo/overlay.md correctly 1`] = `
|
||||
</span>
|
||||
<span>
|
||||
<span
|
||||
class="ant-breadcrumb-overlay-link ant-dropdown-trigger"
|
||||
class="ant-dropdown-trigger ant-breadcrumb-overlay-link"
|
||||
>
|
||||
<span
|
||||
class="ant-breadcrumb-link"
|
||||
|
||||
@@ -22,7 +22,7 @@ A breadcrumb displays the current location within a hierarchy. It allows going b
|
||||
| itemRender | Custom item renderer | (route, params, routes, paths) => ReactNode | - | |
|
||||
| params | Routing parameters | object | - | |
|
||||
| routes | The routing stack information of router | [routes\[\]](#routes) | - | |
|
||||
| separator | Custom separator | string \| ReactNode | `/` | |
|
||||
| separator | Custom separator | ReactNode | `/` | |
|
||||
|
||||
### Breadcrumb.Item
|
||||
|
||||
@@ -35,9 +35,9 @@ A breadcrumb displays the current location within a hierarchy. It allows going b
|
||||
|
||||
### Breadcrumb.Separator
|
||||
|
||||
| Property | Description | Type | Default | Version |
|
||||
| -------- | ---------------- | ------------------- | ------- | ------- |
|
||||
| children | Custom separator | string \| ReactNode | `/` | |
|
||||
| Property | Description | Type | Default | Version |
|
||||
| -------- | ---------------- | --------- | ------- | ------- |
|
||||
| children | Custom separator | ReactNode | `/` | |
|
||||
|
||||
> When using `Breadcrumb.Separator`,its parent component must be set to `separator=""`, otherwise the default separator of the parent component will appear.
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/9Ltop8JwH/Breadcrumb.svg
|
||||
| itemRender | 自定义链接函数,和 react-router 配置使用 | (route, params, routes, paths) => ReactNode | - | |
|
||||
| params | 路由的参数 | object | - | |
|
||||
| routes | router 的路由栈信息 | [routes\[\]](#routes) | - | |
|
||||
| separator | 分隔符自定义 | string \| ReactNode | `/` | |
|
||||
| separator | 分隔符自定义 | ReactNode | `/` | |
|
||||
|
||||
### Breadcrumb.Item
|
||||
|
||||
@@ -36,9 +36,9 @@ cover: https://gw.alipayobjects.com/zos/alicdn/9Ltop8JwH/Breadcrumb.svg
|
||||
|
||||
### Breadcrumb.Separator
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| -------- | -------------- | ------------------- | ------ | ---- |
|
||||
| children | 要显示的分隔符 | string \| ReactNode | `/` | |
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| -------- | -------------- | --------- | ------ | ---- |
|
||||
| children | 要显示的分隔符 | ReactNode | `/` | |
|
||||
|
||||
> 注意:在使用 `Breadcrumb.Separator` 时,其父组件的分隔符必须设置为 `separator=""`,否则会出现父组件默认的分隔符。
|
||||
|
||||
|
||||
@@ -291,54 +291,10 @@ exports[`Button should not render as link button when href is undefined 1`] = `
|
||||
`;
|
||||
|
||||
exports[`Button should render empty button without errors 1`] = `
|
||||
<Button
|
||||
block={false}
|
||||
ghost={false}
|
||||
htmlType="button"
|
||||
loading={false}
|
||||
>
|
||||
<Wave>
|
||||
<button
|
||||
className="ant-btn"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<LoadingIcon
|
||||
existIcon={false}
|
||||
loading={false}
|
||||
prefixCls="ant-btn"
|
||||
>
|
||||
<ForwardRef
|
||||
motionName="ant-btn-loading-icon-motion"
|
||||
onAppearActive={[Function]}
|
||||
onAppearStart={[Function]}
|
||||
onEnterActive={[Function]}
|
||||
onEnterStart={[Function]}
|
||||
onLeaveActive={[Function]}
|
||||
onLeaveStart={[Function]}
|
||||
removeOnLeave={true}
|
||||
visible={false}
|
||||
>
|
||||
<CSSMotion
|
||||
internalRef={null}
|
||||
motionAppear={true}
|
||||
motionEnter={true}
|
||||
motionLeave={true}
|
||||
motionName="ant-btn-loading-icon-motion"
|
||||
onAppearActive={[Function]}
|
||||
onAppearStart={[Function]}
|
||||
onEnterActive={[Function]}
|
||||
onEnterStart={[Function]}
|
||||
onLeaveActive={[Function]}
|
||||
onLeaveStart={[Function]}
|
||||
removeOnLeave={true}
|
||||
visible={false}
|
||||
/>
|
||||
</ForwardRef>
|
||||
</LoadingIcon>
|
||||
</button>
|
||||
</Wave>
|
||||
</Button>
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`Button should support link button 1`] = `
|
||||
@@ -2,7 +2,7 @@ import React, { Component } from 'react';
|
||||
import { mount, render } from 'enzyme';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { SearchOutlined } from '@ant-design/icons';
|
||||
import { resetWarned } from 'rc-util/lib/warning'
|
||||
import { resetWarned } from 'rc-util/lib/warning';
|
||||
import Button from '..';
|
||||
import ConfigProvider from '../../config-provider';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
@@ -111,7 +111,7 @@ describe('Button', () => {
|
||||
{undefined}
|
||||
</Button>,
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('have static property for type detecting', () => {
|
||||
@@ -211,33 +211,6 @@ describe('Button', () => {
|
||||
expect(<Button>{false}</Button>).toMatchRenderedSnapshot();
|
||||
});
|
||||
|
||||
it('should have click wave effect', async () => {
|
||||
const wrapper = mount(<Button type="primary">button</Button>);
|
||||
wrapper.find('.ant-btn').getDOMNode<HTMLButtonElement>().click();
|
||||
await sleep(0);
|
||||
expect(
|
||||
wrapper.find('.ant-btn').getDOMNode().hasAttribute('ant-click-animating-without-extra-node'),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('should not have click wave effect for link type button', async () => {
|
||||
const wrapper = mount(<Button type="link">button</Button>);
|
||||
wrapper.find('.ant-btn').getDOMNode<HTMLButtonElement>().click();
|
||||
await sleep(0);
|
||||
expect(
|
||||
wrapper.find('.ant-btn').getDOMNode().hasAttribute('ant-click-animating-without-extra-node'),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('should not have click wave effect for text type button', async () => {
|
||||
const wrapper = mount(<Button type="link">button</Button>);
|
||||
wrapper.find('.ant-btn').getDOMNode<HTMLButtonElement>().click();
|
||||
await sleep(0);
|
||||
expect(
|
||||
wrapper.find('.ant-btn').getDOMNode().hasAttribute('ant-click-animating-without-extra-node'),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('should not render as link button when href is undefined', async () => {
|
||||
const wrapper = mount(
|
||||
<Button type="primary" href={undefined}>
|
||||
@@ -282,7 +255,7 @@ describe('Button', () => {
|
||||
});
|
||||
|
||||
it('should warning when pass a string as icon props', () => {
|
||||
resetWarned()
|
||||
resetWarned();
|
||||
const warnSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
mount(<Button type="primary" icon="ab" />);
|
||||
expect(warnSpy).not.toHaveBeenCalled();
|
||||
@@ -294,24 +267,24 @@ describe('Button', () => {
|
||||
});
|
||||
|
||||
it('should warning when pass type=link and ghost=true', () => {
|
||||
resetWarned()
|
||||
resetWarned();
|
||||
const warnSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
mount(<Button type="link" ghost />);
|
||||
expect(warnSpy).toHaveBeenCalledWith(
|
||||
"Warning: [antd: Button] `link` or `text` button can't be a `ghost` button.",
|
||||
);
|
||||
warnSpy.mockRestore();
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
it('should warning when pass type=text and ghost=true', () => {
|
||||
resetWarned()
|
||||
resetWarned();
|
||||
const warnSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
mount(<Button type="text" ghost />);
|
||||
expect(warnSpy).toHaveBeenCalledWith(
|
||||
"Warning: [antd: Button] `link` or `text` button can't be a `ghost` button.",
|
||||
);
|
||||
warnSpy.mockRestore();
|
||||
})
|
||||
});
|
||||
|
||||
it('skip check 2 words when ConfigProvider disable this', () => {
|
||||
const wrapper = mount(
|
||||
93
components/button/__tests__/wave.test.tsx
Normal file
93
components/button/__tests__/wave.test.tsx
Normal file
@@ -0,0 +1,93 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import Button from '..';
|
||||
import Wave from '../../_util/wave';
|
||||
import { sleep } from '../../../tests/utils';
|
||||
|
||||
describe('click wave effect', () => {
|
||||
async function clickButton(wrapper: any) {
|
||||
wrapper.find('.ant-btn').getDOMNode().click();
|
||||
wrapper.find('.ant-btn').getDOMNode().dispatchEvent(new Event('transitionstart'));
|
||||
await sleep(20);
|
||||
wrapper.find('.ant-btn').getDOMNode().dispatchEvent(new Event('animationend'));
|
||||
await sleep(20);
|
||||
}
|
||||
|
||||
it('should have click wave effect for primary button', async () => {
|
||||
const wrapper = mount(<Button type="primary">button</Button>);
|
||||
await clickButton(wrapper);
|
||||
expect(
|
||||
wrapper.find('.ant-btn').getDOMNode().hasAttribute('ant-click-animating-without-extra-node'),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('should have click wave effect for default button', async () => {
|
||||
const wrapper = mount(<Button>button</Button>);
|
||||
await clickButton(wrapper);
|
||||
expect(
|
||||
wrapper.find('.ant-btn').getDOMNode().hasAttribute('ant-click-animating-without-extra-node'),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('should not have click wave effect for link type button', async () => {
|
||||
const wrapper = mount(<Button type="link">button</Button>);
|
||||
await clickButton(wrapper);
|
||||
expect(
|
||||
wrapper.find('.ant-btn').getDOMNode().hasAttribute('ant-click-animating-without-extra-node'),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('should not have click wave effect for text type button', async () => {
|
||||
const wrapper = mount(<Button type="text">button</Button>);
|
||||
await clickButton(wrapper);
|
||||
expect(
|
||||
wrapper.find('.ant-btn').getDOMNode().hasAttribute('ant-click-animating-without-extra-node'),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('should handle transitionstart', async () => {
|
||||
const wrapper = mount(<Button type="primary">button</Button>);
|
||||
await clickButton(wrapper);
|
||||
const buttonNode = wrapper.find('.ant-btn').getDOMNode();
|
||||
buttonNode.dispatchEvent(new Event('transitionstart'));
|
||||
expect(
|
||||
wrapper.find('.ant-btn').getDOMNode().hasAttribute('ant-click-animating-without-extra-node'),
|
||||
).toBe(true);
|
||||
wrapper.unmount();
|
||||
buttonNode.dispatchEvent(new Event('transitionstart'));
|
||||
});
|
||||
|
||||
it('should run resetEffect in transitionstart', async () => {
|
||||
const wrapper = mount(<Button type="primary">button</Button>);
|
||||
const waveInstance = wrapper.find(Wave).instance() as any;
|
||||
const resetEffect = jest.spyOn(waveInstance, 'resetEffect');
|
||||
await clickButton(wrapper);
|
||||
expect(resetEffect).toHaveBeenCalledTimes(1);
|
||||
wrapper.find('.ant-btn').getDOMNode<HTMLButtonElement>().click();
|
||||
await sleep(10);
|
||||
expect(resetEffect).toHaveBeenCalledTimes(2);
|
||||
waveInstance.animationStart = false;
|
||||
wrapper.find('.ant-btn').getDOMNode().dispatchEvent(new Event('transitionstart'));
|
||||
expect(resetEffect).toHaveBeenCalledTimes(3);
|
||||
resetEffect.mockRestore();
|
||||
});
|
||||
|
||||
it('should handle transitionend', async () => {
|
||||
const wrapper = mount(<Button type="primary">button</Button>);
|
||||
const waveInstance = wrapper.find(Wave).instance() as any;
|
||||
const resetEffect = jest.spyOn(waveInstance, 'resetEffect');
|
||||
await clickButton(wrapper);
|
||||
expect(resetEffect).toHaveBeenCalledTimes(1);
|
||||
const event = new Event('animationend');
|
||||
Object.assign(event, { animationName: 'fadeEffect' });
|
||||
wrapper.find('.ant-btn').getDOMNode().dispatchEvent(event);
|
||||
expect(resetEffect).toHaveBeenCalledTimes(2);
|
||||
resetEffect.mockRestore();
|
||||
});
|
||||
|
||||
it('Wave on falsy element', async () => {
|
||||
const wrapper = mount(<Wave />);
|
||||
const waveInstance = wrapper.find(Wave).instance() as any;
|
||||
waveInstance.resetEffect();
|
||||
});
|
||||
});
|
||||
@@ -74,7 +74,7 @@ function spaceChildren(children: React.ReactNode, needInserted: boolean) {
|
||||
|
||||
const ButtonTypes = tuple('default', 'primary', 'ghost', 'dashed', 'link', 'text');
|
||||
export type ButtonType = typeof ButtonTypes[number];
|
||||
const ButtonShapes = tuple('circle', 'circle-outline', 'round');
|
||||
const ButtonShapes = tuple('circle', 'round');
|
||||
export type ButtonShape = typeof ButtonShapes[number];
|
||||
const ButtonHTMLTypes = tuple('submit', 'button', 'reset');
|
||||
export type ButtonHTMLType = typeof ButtonHTMLTypes[number];
|
||||
@@ -233,18 +233,22 @@ const InternalButton: React.ForwardRefRenderFunction<unknown, ButtonProps> = (pr
|
||||
|
||||
const iconType = innerLoading ? '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 && !isUnborderedButtonType(type),
|
||||
[`${prefixCls}-loading`]: innerLoading,
|
||||
[`${prefixCls}-two-chinese-chars`]: hasTwoCNChar && autoInsertSpace,
|
||||
[`${prefixCls}-block`]: block,
|
||||
[`${prefixCls}-dangerous`]: !!danger,
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
});
|
||||
const classes = classNames(
|
||||
prefixCls,
|
||||
{
|
||||
[`${prefixCls}-${type}`]: type,
|
||||
[`${prefixCls}-${shape}`]: shape,
|
||||
[`${prefixCls}-${sizeCls}`]: sizeCls,
|
||||
[`${prefixCls}-icon-only`]: !children && children !== 0 && iconType,
|
||||
[`${prefixCls}-background-ghost`]: ghost && !isUnborderedButtonType(type),
|
||||
[`${prefixCls}-loading`]: innerLoading,
|
||||
[`${prefixCls}-two-chinese-chars`]: hasTwoCNChar && autoInsertSpace,
|
||||
[`${prefixCls}-block`]: block,
|
||||
[`${prefixCls}-dangerous`]: !!danger,
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
},
|
||||
className,
|
||||
);
|
||||
|
||||
const iconNode =
|
||||
icon && !innerLoading ? (
|
||||
@@ -258,7 +262,7 @@ const InternalButton: React.ForwardRefRenderFunction<unknown, ButtonProps> = (pr
|
||||
? spaceChildren(children, isNeedInserted() && autoInsertSpace)
|
||||
: null;
|
||||
|
||||
const linkButtonRestProps = omit(rest as AnchorButtonProps, ['htmlType', 'loading']);
|
||||
const linkButtonRestProps = omit(rest as AnchorButtonProps, ['htmlType', 'loading', 'navigate']);
|
||||
if (linkButtonRestProps.href !== undefined) {
|
||||
return (
|
||||
<a {...linkButtonRestProps} className={classes} onClick={handleClick} ref={buttonRef}>
|
||||
|
||||
@@ -23,7 +23,7 @@ And 4 other properties additionally.
|
||||
|
||||
- `danger`: used for actions of risk, like deletion or authorization.
|
||||
- `ghost`: used in situations with complex background, home pages usually.
|
||||
- `disabled`: when actions is not available.
|
||||
- `disabled`: when actions are not available.
|
||||
- `loading`: add loading spinner in button, avoiding multiple submits too.
|
||||
|
||||
## API
|
||||
@@ -41,10 +41,10 @@ Different button styles can be generated by setting Button properties. The recom
|
||||
| icon | Set the icon component of button | ReactNode | - | |
|
||||
| loading | Set the loading status of button | boolean \| { delay: number } | false | |
|
||||
| onClick | Set the handler to handle `click` event | (event) => void | - | |
|
||||
| shape | Can be set to `circle`, `round` or omitted | string | - | |
|
||||
| shape | Can be set button shape | `circle` \| `round` | - | |
|
||||
| size | Set the size of button | `large` \| `middle` \| `small` | - | |
|
||||
| target | Same as target attribute of a, works when href is specified | string | - | |
|
||||
| type | Can be set to `primary` `ghost` `dashed` `danger` `link` `text` `default` | string | `default` | |
|
||||
| type | Can be set to `primary` `ghost` `dashed` `link` `text` `default` | string | `default` | |
|
||||
|
||||
It accepts all props which native buttons support.
|
||||
|
||||
|
||||
@@ -44,10 +44,10 @@ cover: https://gw.alipayobjects.com/zos/alicdn/fNUKzY1sk/Button.svg
|
||||
| icon | 设置按钮的图标组件 | ReactNode | - | |
|
||||
| loading | 设置按钮载入状态 | boolean \| { delay: number } | false | |
|
||||
| onClick | 点击按钮时的回调 | (event) => void | - | |
|
||||
| shape | 设置按钮形状,可选值为 `circle`、 `round` 或者不设 | string | - | |
|
||||
| shape | 设置按钮形状 | `circle` \| `round` | - | |
|
||||
| size | 设置按钮大小 | `large` \| `middle` \| `small` | - | |
|
||||
| target | 相当于 a 链接的 target 属性,href 存在时生效 | string | - | |
|
||||
| type | 设置按钮类型 | `primary` \| `ghost` \| `dashed` \| `danger` \| `link` \| `text` \| `default` | `default` | |
|
||||
| type | 设置按钮类型 | `primary` \| `ghost` \| `dashed` \| `link` \| `text` \| `default` | `default` | |
|
||||
|
||||
支持原生 button 的其他所有属性。
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
|
||||
&-icon-only {
|
||||
.btn-square(@btn-prefix-cls);
|
||||
vertical-align: -0.5px;
|
||||
vertical-align: -1px;
|
||||
}
|
||||
|
||||
&-round {
|
||||
@@ -111,8 +111,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
&-circle,
|
||||
&-circle-outline {
|
||||
&-circle {
|
||||
.btn-circle(@btn-prefix-cls);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ exports[`renders ./components/calendar/demo/basic.md correctly 1`] = `
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity:0"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
@@ -86,6 +87,7 @@ exports[`renders ./components/calendar/demo/basic.md correctly 1`] = `
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity:0"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
@@ -953,7 +955,7 @@ exports[`renders ./components/calendar/demo/card.md correctly 1`] = `
|
||||
class="ant-picker-calendar-header"
|
||||
>
|
||||
<div
|
||||
class="ant-select ant-picker-calendar-year-select ant-select-sm ant-select-single ant-select-show-arrow"
|
||||
class="ant-select ant-select-sm ant-picker-calendar-year-select ant-select-single ant-select-show-arrow"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selector"
|
||||
@@ -972,6 +974,7 @@ exports[`renders ./components/calendar/demo/card.md correctly 1`] = `
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity:0"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
@@ -1012,7 +1015,7 @@ exports[`renders ./components/calendar/demo/card.md correctly 1`] = `
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-select ant-picker-calendar-month-select ant-select-sm ant-select-single ant-select-show-arrow"
|
||||
class="ant-select ant-select-sm ant-picker-calendar-month-select ant-select-single ant-select-show-arrow"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selector"
|
||||
@@ -1031,6 +1034,7 @@ exports[`renders ./components/calendar/demo/card.md correctly 1`] = `
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity:0"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
@@ -1960,7 +1964,7 @@ exports[`renders ./components/calendar/demo/customize-header.md correctly 1`] =
|
||||
style="padding-left:4px;padding-right:4px"
|
||||
>
|
||||
<div
|
||||
class="ant-select my-year-select ant-select-sm ant-select-single ant-select-show-arrow"
|
||||
class="ant-select ant-select-sm my-year-select ant-select-single ant-select-show-arrow"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selector"
|
||||
@@ -1979,6 +1983,7 @@ exports[`renders ./components/calendar/demo/customize-header.md correctly 1`] =
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity:0"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
@@ -2043,6 +2048,7 @@ exports[`renders ./components/calendar/demo/customize-header.md correctly 1`] =
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity:0"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
@@ -2886,6 +2892,7 @@ exports[`renders ./components/calendar/demo/notice-calendar.md correctly 1`] = `
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity:0"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
@@ -2945,6 +2952,7 @@ exports[`renders ./components/calendar/demo/notice-calendar.md correctly 1`] = `
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity:0"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
@@ -4240,6 +4248,7 @@ Array [
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity:0"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
@@ -4299,6 +4308,7 @@ Array [
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity:0"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
|
||||
@@ -28,6 +28,7 @@ exports[`Calendar Calendar should support locale 1`] = `
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity: 0;"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
@@ -88,6 +89,7 @@ exports[`Calendar Calendar should support locale 1`] = `
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity: 0;"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
@@ -952,7 +954,7 @@ exports[`Calendar rtl render component should be rendered correctly in RTL direc
|
||||
class="ant-picker-calendar-header"
|
||||
>
|
||||
<div
|
||||
class="ant-select ant-picker-calendar-year-select ant-select-rtl ant-select-single ant-select-show-arrow"
|
||||
class="ant-select ant-select-rtl ant-picker-calendar-year-select ant-select-single ant-select-show-arrow"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selector"
|
||||
@@ -971,6 +973,7 @@ exports[`Calendar rtl render component should be rendered correctly in RTL direc
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity:0"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
@@ -1011,7 +1014,7 @@ exports[`Calendar rtl render component should be rendered correctly in RTL direc
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-select ant-picker-calendar-month-select ant-select-rtl ant-select-single ant-select-show-arrow"
|
||||
class="ant-select ant-select-rtl ant-picker-calendar-month-select ant-select-single ant-select-show-arrow"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selector"
|
||||
@@ -1030,6 +1033,7 @@ exports[`Calendar rtl render component should be rendered correctly in RTL direc
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity:0"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
|
||||
@@ -214,7 +214,7 @@ describe('Calendar', () => {
|
||||
expect(onValueChange).toHaveBeenCalledWith(value.year('2019').month('3'));
|
||||
});
|
||||
|
||||
it('if start.month > value.month, set value.month to start.month ', () => {
|
||||
it('if start.month > value.month, set value.month to start.month', () => {
|
||||
const value = new Moment('1990-01-03');
|
||||
const start = new Moment('2019-11-01');
|
||||
const end = new Moment('2019-03-01');
|
||||
@@ -223,7 +223,7 @@ describe('Calendar', () => {
|
||||
expect(onValueChange).toHaveBeenCalledWith(value.year('2019').month('10'));
|
||||
});
|
||||
|
||||
it('if change year and new month > end month, set value.month to end.month ', () => {
|
||||
it('if change year and new month > end month, set value.month to end.month', () => {
|
||||
const value = new Moment('2018-11-03');
|
||||
const start = new Moment('2000-01-01');
|
||||
const end = new Moment('2019-03-01');
|
||||
|
||||
@@ -241,11 +241,15 @@ function generateCalendar<DateType>(generateConfig: GenerateConfig<DateType>) {
|
||||
{(mergedLocale: any) => {
|
||||
return (
|
||||
<div
|
||||
className={classNames(calendarPrefixCls, className, {
|
||||
[`${calendarPrefixCls}-full`]: fullscreen,
|
||||
[`${calendarPrefixCls}-mini`]: !fullscreen,
|
||||
[`${calendarPrefixCls}-rtl`]: direction === 'rtl',
|
||||
})}
|
||||
className={classNames(
|
||||
calendarPrefixCls,
|
||||
{
|
||||
[`${calendarPrefixCls}-full`]: fullscreen,
|
||||
[`${calendarPrefixCls}-mini`]: !fullscreen,
|
||||
[`${calendarPrefixCls}-rtl`]: direction === 'rtl',
|
||||
},
|
||||
className,
|
||||
)}
|
||||
style={style}
|
||||
>
|
||||
{headerRender ? (
|
||||
|
||||
3
components/calendar/locale/by_BY.tsx
Normal file
3
components/calendar/locale/by_BY.tsx
Normal file
@@ -0,0 +1,3 @@
|
||||
import byBY from '../../date-picker/locale/by_BY';
|
||||
|
||||
export default byBY;
|
||||
@@ -839,7 +839,7 @@ Array [
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-tabs ant-tabs-top ant-card-head-tabs ant-tabs-large"
|
||||
class="ant-tabs ant-tabs-top ant-tabs-large ant-card-head-tabs"
|
||||
>
|
||||
<div
|
||||
class="ant-tabs-nav"
|
||||
@@ -962,7 +962,7 @@ Array [
|
||||
class="ant-card-head-wrapper"
|
||||
/>
|
||||
<div
|
||||
class="ant-tabs ant-tabs-top ant-card-head-tabs ant-tabs-large"
|
||||
class="ant-tabs ant-tabs-top ant-tabs-large ant-card-head-tabs"
|
||||
>
|
||||
<div
|
||||
class="ant-tabs-nav"
|
||||
|
||||
@@ -29,13 +29,13 @@ A card can be used to display content related to a single subject. The content c
|
||||
| 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 | - | |
|
||||
| extra | Content to render in the top-right corner of the card | string \| ReactNode | - | |
|
||||
| extra | Content to render in the top-right corner of the card | ReactNode | - | |
|
||||
| hoverable | Lift up when hovering card | boolean | false | |
|
||||
| loading | Shows a loading indicator while the contents of the card are being fetched | boolean | false | |
|
||||
| tabList | List of TabPane's head | Array<{key: string, tab: ReactNode}> | - | |
|
||||
| tabBarExtraContent | Extra content in tab bar | ReactNode | - | |
|
||||
| size | Size of card | `default` \| `small` | `default` | |
|
||||
| title | Card title | string \| ReactNode | - | |
|
||||
| title | Card title | ReactNode | - | |
|
||||
| type | Card style type, can be set to `inner` or not set | string | - | |
|
||||
| onTabChange | Callback when tab is switched | (key) => void | - | |
|
||||
| tabProps | [Tabs](/components/tabs/#Tabs) | - | - | |
|
||||
|
||||
@@ -183,16 +183,20 @@ const Card: CardInterface = props => {
|
||||
) : null;
|
||||
const divProps = omit(others, ['onTabChange']);
|
||||
const mergedSize = customizeSize || size;
|
||||
const classString = classNames(prefixCls, className, {
|
||||
[`${prefixCls}-loading`]: loading,
|
||||
[`${prefixCls}-bordered`]: bordered,
|
||||
[`${prefixCls}-hoverable`]: hoverable,
|
||||
[`${prefixCls}-contain-grid`]: isContainGrid(),
|
||||
[`${prefixCls}-contain-tabs`]: tabList && tabList.length,
|
||||
[`${prefixCls}-${mergedSize}`]: mergedSize,
|
||||
[`${prefixCls}-type-${type}`]: !!type,
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
});
|
||||
const classString = classNames(
|
||||
prefixCls,
|
||||
{
|
||||
[`${prefixCls}-loading`]: loading,
|
||||
[`${prefixCls}-bordered`]: bordered,
|
||||
[`${prefixCls}-hoverable`]: hoverable,
|
||||
[`${prefixCls}-contain-grid`]: isContainGrid(),
|
||||
[`${prefixCls}-contain-tabs`]: tabList && tabList.length,
|
||||
[`${prefixCls}-${mergedSize}`]: mergedSize,
|
||||
[`${prefixCls}-type-${type}`]: !!type,
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
},
|
||||
className,
|
||||
);
|
||||
|
||||
return (
|
||||
<div {...divProps} className={classString}>
|
||||
|
||||
@@ -30,13 +30,13 @@ cover: https://gw.alipayobjects.com/zos/antfincdn/NqXt8DJhky/Card.svg
|
||||
| bordered | 是否有边框 | boolean | true | |
|
||||
| cover | 卡片封面 | ReactNode | - | |
|
||||
| defaultActiveTabKey | 初始化选中页签的 key,如果没有设置 activeTabKey | string | `第一个页签` | |
|
||||
| extra | 卡片右上角的操作区域 | string \| ReactNode | - | |
|
||||
| extra | 卡片右上角的操作区域 | ReactNode | - | |
|
||||
| hoverable | 鼠标移过时可浮起 | boolean | false | |
|
||||
| loading | 当卡片内容还在加载中时,可以用 loading 展示一个占位 | boolean | false | |
|
||||
| tabList | 页签标题列表 | Array<{key: string, tab: ReactNode}> | - | |
|
||||
| tabBarExtraContent | tab bar 上额外的元素 | ReactNode | - | |
|
||||
| size | card 的尺寸 | `default` \| `small` | `default` | |
|
||||
| title | 卡片标题 | string \| ReactNode | - | |
|
||||
| title | 卡片标题 | ReactNode | - | |
|
||||
| type | 卡片类型,可设置为 `inner` 或 不设置 | string | - | |
|
||||
| onTabChange | 页签切换的回调 | (key) => void | - | |
|
||||
| tabProps | [Tabs](/components/tabs/#Tabs) | - | - | |
|
||||
|
||||
@@ -133,6 +133,7 @@
|
||||
&-bordered &-cover {
|
||||
margin-right: -1px;
|
||||
margin-left: -1px;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
&-cover {
|
||||
|
||||
@@ -86,6 +86,7 @@ describe('Carousel', () => {
|
||||
|
||||
describe('should works for dotPosition', () => {
|
||||
['left', 'right', 'top', 'bottom'].forEach(dotPosition => {
|
||||
// eslint-disable-next-line jest/valid-title
|
||||
it(dotPosition, () => {
|
||||
const wrapper = mount(
|
||||
<Carousel dotPosition={dotPosition}>
|
||||
@@ -118,12 +119,7 @@ describe('Carousel', () => {
|
||||
children: [<div key="1" />, <div key="2" />, <div key="3" />],
|
||||
});
|
||||
wrapper.update();
|
||||
expect(
|
||||
wrapper
|
||||
.find('.slick-dots li')
|
||||
.at(1)
|
||||
.hasClass('slick-active'),
|
||||
).toBeTruthy();
|
||||
expect(wrapper.find('.slick-dots li').at(1).hasClass('slick-active')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -134,7 +134,7 @@ describe('Cascader', () => {
|
||||
wrapper.find('input').simulate('change', { target: { value: 'z' } });
|
||||
expect(wrapper.state('inputValue')).toBe('z');
|
||||
const popupWrapper = mount(wrapper.find('Trigger').instance().getComponent());
|
||||
expect(popupWrapper).toMatchSnapshot();
|
||||
expect(popupWrapper.render()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should highlight keyword and filter when search in Cascader with same field name of label and value', () => {
|
||||
@@ -184,7 +184,7 @@ describe('Cascader', () => {
|
||||
wrapper.find('input').simulate('change', { target: { value: '__notfoundkeyword__' } });
|
||||
expect(wrapper.state('inputValue')).toBe('__notfoundkeyword__');
|
||||
const popupWrapper = mount(wrapper.find('Trigger').instance().getComponent());
|
||||
expect(popupWrapper).toMatchSnapshot();
|
||||
expect(popupWrapper.render()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should support to clear selection', async () => {
|
||||
@@ -318,7 +318,7 @@ describe('Cascader', () => {
|
||||
const wrapper = mount(<Cascader options={customerOptions} />);
|
||||
wrapper.find('input').simulate('click');
|
||||
const popupWrapper = mount(wrapper.find('Trigger').instance().getComponent());
|
||||
expect(popupWrapper).toMatchSnapshot();
|
||||
expect(popupWrapper.render()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe('limit filtered item count', () => {
|
||||
@@ -524,4 +524,22 @@ describe('Cascader', () => {
|
||||
wrapper.find('input').simulate('change', { target: { value: 'jin' } });
|
||||
expect(wrapper.state('popupVisible')).toBe(true);
|
||||
});
|
||||
|
||||
it('onChange works correctly when the label of fieldNames is the same as value', () => {
|
||||
const onChange = jest.fn();
|
||||
const sameNames = { label: 'label', value: 'label', children: 'children' };
|
||||
const wrapper = mount(
|
||||
<Cascader options={options} onChange={onChange} showSearch fieldNames={sameNames} />,
|
||||
);
|
||||
wrapper.find('input').simulate('click');
|
||||
wrapper.find('input').simulate('change', { target: { value: 'est' } });
|
||||
const popupWrapper = mount(wrapper.find('Cascader').find('Trigger').instance().getComponent());
|
||||
popupWrapper
|
||||
.find('.ant-cascader-menu')
|
||||
.at(0)
|
||||
.find('.ant-cascader-menu-item')
|
||||
.at(0)
|
||||
.simulate('click');
|
||||
expect(onChange).toHaveBeenCalledWith(['Zhejiang', 'Hangzhou', 'West Lake'], expect.anything());
|
||||
});
|
||||
});
|
||||
|
||||
@@ -84,6 +84,10 @@ export interface CascaderProps {
|
||||
placeholder?: string;
|
||||
/** 输入框大小,可选 `large` `default` `small` */
|
||||
size?: SizeType;
|
||||
/** 输入框name */
|
||||
name?: string;
|
||||
/** 输入框id */
|
||||
id?: string;
|
||||
/** whether has border style */
|
||||
bordered?: boolean;
|
||||
/** 禁用 */
|
||||
@@ -128,6 +132,9 @@ interface CascaderLocale {
|
||||
// We limit the filtered item count by default
|
||||
const defaultLimit = 50;
|
||||
|
||||
// keep value when filtering
|
||||
const keepFilteredValueField = '__KEEP_FILTERED_OPTION_VALUE';
|
||||
|
||||
function highlightKeyword(str: string, keyword: string, prefixCls: string | undefined) {
|
||||
return str.split(keyword).map((node: string, index: number) =>
|
||||
index === 0
|
||||
@@ -308,7 +315,10 @@ class Cascader extends React.Component<CascaderProps, CascaderState> {
|
||||
handleChange = (value: any, selectedOptions: CascaderOptionType[]) => {
|
||||
this.setState({ inputValue: '' });
|
||||
if (selectedOptions[0].__IS_FILTERED_OPTION) {
|
||||
const unwrappedValue = value[0];
|
||||
const unwrappedValue =
|
||||
selectedOptions[0][keepFilteredValueField] === undefined
|
||||
? value[0]
|
||||
: selectedOptions[0][keepFilteredValueField];
|
||||
const unwrappedSelectedOptions = selectedOptions[0].path;
|
||||
this.setValue(unwrappedValue, unwrappedSelectedOptions);
|
||||
return;
|
||||
@@ -413,11 +423,14 @@ class Cascader extends React.Component<CascaderProps, CascaderState> {
|
||||
filtered = filtered.sort((a, b) => sort(a, b, inputValue, names));
|
||||
|
||||
if (filtered.length > 0) {
|
||||
// Fix issue: https://github.com/ant-design/ant-design/issues/26554
|
||||
const field = names.value === names.label ? keepFilteredValueField : names.value;
|
||||
|
||||
return filtered.map((path: CascaderOptionType[]) => {
|
||||
return {
|
||||
__IS_FILTERED_OPTION: true,
|
||||
path,
|
||||
[names.value]: path.map((o: CascaderOptionType) => o[names.value]),
|
||||
[field]: path.map((o: CascaderOptionType) => o[names.value]),
|
||||
[names.label]: render(inputValue, path, prefixCls, names),
|
||||
disabled: path.some((o: CascaderOptionType) => !!o.disabled),
|
||||
isEmptyNode: true,
|
||||
@@ -506,15 +519,19 @@ class Cascader extends React.Component<CascaderProps, CascaderState> {
|
||||
[`${prefixCls}-picker-arrow`]: true,
|
||||
[`${prefixCls}-picker-arrow-expand`]: state.popupVisible,
|
||||
});
|
||||
const pickerCls = classNames(className, `${prefixCls}-picker`, {
|
||||
[`${prefixCls}-picker-rtl`]: isRtlLayout,
|
||||
[`${prefixCls}-picker-with-value`]: state.inputValue,
|
||||
[`${prefixCls}-picker-disabled`]: disabled,
|
||||
[`${prefixCls}-picker-${mergedSize}`]: !!mergedSize,
|
||||
[`${prefixCls}-picker-show-search`]: !!showSearch,
|
||||
[`${prefixCls}-picker-focused`]: inputFocused,
|
||||
[`${prefixCls}-picker-borderless`]: !bordered,
|
||||
});
|
||||
const pickerCls = classNames(
|
||||
`${prefixCls}-picker`,
|
||||
{
|
||||
[`${prefixCls}-picker-rtl`]: isRtlLayout,
|
||||
[`${prefixCls}-picker-with-value`]: state.inputValue,
|
||||
[`${prefixCls}-picker-disabled`]: disabled,
|
||||
[`${prefixCls}-picker-${mergedSize}`]: !!mergedSize,
|
||||
[`${prefixCls}-picker-show-search`]: !!showSearch,
|
||||
[`${prefixCls}-picker-focused`]: inputFocused,
|
||||
[`${prefixCls}-picker-borderless`]: !bordered,
|
||||
},
|
||||
className,
|
||||
);
|
||||
|
||||
// Fix bug of https://github.com/facebook/react/pull/5004
|
||||
// and https://fb.me/react-unknown-prop
|
||||
@@ -625,12 +642,19 @@ class Cascader extends React.Component<CascaderProps, CascaderState> {
|
||||
);
|
||||
|
||||
const getPopupContainer = props.getPopupContainer || getContextPopupContainer;
|
||||
const rest = omit(props, ['inputIcon', 'expandIcon', 'loadingIcon', 'bordered']);
|
||||
const rest = omit(props, [
|
||||
'inputIcon',
|
||||
'expandIcon',
|
||||
'loadingIcon',
|
||||
'bordered',
|
||||
'className',
|
||||
]);
|
||||
const rcCascaderPopupClassName = classNames(popupClassName, {
|
||||
[`${prefixCls}-menu-${direction}`]: direction === 'rtl',
|
||||
[`${prefixCls}-menu-empty`]:
|
||||
options.length === 1 && options[0].value === 'ANT_CASCADER_NOT_FOUND',
|
||||
});
|
||||
|
||||
return (
|
||||
<RcCascader
|
||||
{...rest}
|
||||
|
||||
@@ -223,11 +223,10 @@
|
||||
|
||||
&-expand &-expand-icon,
|
||||
&-loading-icon {
|
||||
.iconfont-size-under-12px(10px);
|
||||
|
||||
position: absolute;
|
||||
right: @control-padding-horizontal;
|
||||
color: @text-color-secondary;
|
||||
font-size: 10px;
|
||||
|
||||
.@{cascader-prefix-cls}-menu-item-disabled& {
|
||||
color: @disabled-color;
|
||||
|
||||
@@ -85,5 +85,11 @@
|
||||
left: @control-padding-horizontal;
|
||||
}
|
||||
}
|
||||
|
||||
&-loading-icon {
|
||||
.@{menu-rtl-cls} & {
|
||||
transform: scaleY(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,10 +27,6 @@ export interface AbstractCheckboxProps<T> {
|
||||
type?: string;
|
||||
}
|
||||
|
||||
export interface CheckboxProps extends AbstractCheckboxProps<CheckboxChangeEvent> {
|
||||
indeterminate?: boolean;
|
||||
}
|
||||
|
||||
export interface CheckboxChangeEventTarget extends CheckboxProps {
|
||||
checked: boolean;
|
||||
}
|
||||
@@ -42,6 +38,10 @@ export interface CheckboxChangeEvent {
|
||||
nativeEvent: MouseEvent;
|
||||
}
|
||||
|
||||
export interface CheckboxProps extends AbstractCheckboxProps<CheckboxChangeEvent> {
|
||||
indeterminate?: boolean;
|
||||
}
|
||||
|
||||
class Checkbox extends React.PureComponent<CheckboxProps, {}> {
|
||||
static Group: typeof CheckboxGroup;
|
||||
|
||||
@@ -119,12 +119,15 @@ class Checkbox extends React.PureComponent<CheckboxProps, {}> {
|
||||
checkboxProps.checked = checkboxGroup.value.indexOf(props.value) !== -1;
|
||||
checkboxProps.disabled = props.disabled || checkboxGroup.disabled;
|
||||
}
|
||||
const classString = classNames(className, {
|
||||
[`${prefixCls}-wrapper`]: true,
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
[`${prefixCls}-wrapper-checked`]: checkboxProps.checked,
|
||||
[`${prefixCls}-wrapper-disabled`]: checkboxProps.disabled,
|
||||
});
|
||||
const classString = classNames(
|
||||
{
|
||||
[`${prefixCls}-wrapper`]: true,
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
[`${prefixCls}-wrapper-checked`]: checkboxProps.checked,
|
||||
[`${prefixCls}-wrapper-disabled`]: checkboxProps.disabled,
|
||||
},
|
||||
className,
|
||||
);
|
||||
const checkboxClass = classNames({
|
||||
[`${prefixCls}-indeterminate`]: indeterminate,
|
||||
});
|
||||
|
||||
@@ -2,7 +2,7 @@ import * as React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import omit from 'omit.js';
|
||||
import Checkbox, { CheckboxChangeEvent } from './Checkbox';
|
||||
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
|
||||
export type CheckboxValueType = string | number | boolean;
|
||||
|
||||
@@ -27,11 +27,7 @@ export interface CheckboxGroupProps extends AbstractCheckboxGroupProps {
|
||||
defaultValue?: Array<CheckboxValueType>;
|
||||
value?: Array<CheckboxValueType>;
|
||||
onChange?: (checkedValue: Array<CheckboxValueType>) => void;
|
||||
}
|
||||
|
||||
export interface CheckboxGroupState {
|
||||
value: CheckboxValueType[];
|
||||
registeredValues: CheckboxValueType[];
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export interface CheckboxGroupContext {
|
||||
@@ -42,131 +38,119 @@ export interface CheckboxGroupContext {
|
||||
|
||||
export const GroupContext = React.createContext<CheckboxGroupContext | null>(null);
|
||||
|
||||
class CheckboxGroup extends React.PureComponent<CheckboxGroupProps, CheckboxGroupState> {
|
||||
static defaultProps = {
|
||||
options: [],
|
||||
};
|
||||
const CheckboxGroup: React.FC<CheckboxGroupProps> = ({
|
||||
defaultValue,
|
||||
children,
|
||||
options = [],
|
||||
prefixCls: customizePrefixCls,
|
||||
className,
|
||||
style,
|
||||
onChange,
|
||||
...restProps
|
||||
}) => {
|
||||
const { getPrefixCls, direction } = React.useContext(ConfigContext);
|
||||
|
||||
static getDerivedStateFromProps(nextProps: CheckboxGroupProps) {
|
||||
if ('value' in nextProps) {
|
||||
return {
|
||||
value: nextProps.value || [],
|
||||
};
|
||||
const [value, setValue] = React.useState<CheckboxValueType[]>(
|
||||
restProps.value || defaultValue || [],
|
||||
);
|
||||
const [registeredValues, setRegisteredValues] = React.useState<CheckboxValueType[]>([]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if ('value' in restProps) {
|
||||
setValue(restProps.value || []);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}, [restProps.value]);
|
||||
|
||||
constructor(props: CheckboxGroupProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
value: props.value || props.defaultValue || [],
|
||||
registeredValues: [],
|
||||
};
|
||||
}
|
||||
|
||||
getOptions() {
|
||||
const { options } = this.props;
|
||||
// https://github.com/Microsoft/TypeScript/issues/7960
|
||||
return (options as Array<CheckboxOptionType>).map(option => {
|
||||
const getOptions = () => {
|
||||
return options.map(option => {
|
||||
if (typeof option === 'string') {
|
||||
return {
|
||||
label: option,
|
||||
value: option,
|
||||
} as CheckboxOptionType;
|
||||
};
|
||||
}
|
||||
return option;
|
||||
});
|
||||
}
|
||||
|
||||
cancelValue = (value: string) => {
|
||||
this.setState(({ registeredValues }) => ({
|
||||
registeredValues: registeredValues.filter(val => val !== value),
|
||||
}));
|
||||
};
|
||||
|
||||
registerValue = (value: string) => {
|
||||
this.setState(({ registeredValues }) => ({
|
||||
registeredValues: [...registeredValues, value],
|
||||
}));
|
||||
const cancelValue = (val: string) => {
|
||||
setRegisteredValues(prevValues => prevValues.filter(v => v !== val));
|
||||
};
|
||||
|
||||
toggleOption = (option: CheckboxOptionType) => {
|
||||
const { registeredValues } = this.state;
|
||||
const optionIndex = this.state.value.indexOf(option.value);
|
||||
const value = [...this.state.value];
|
||||
const registerValue = (val: string) => {
|
||||
setRegisteredValues(prevValues => [...prevValues, val]);
|
||||
};
|
||||
|
||||
const toggleOption = (option: CheckboxOptionType) => {
|
||||
const optionIndex = value.indexOf(option.value);
|
||||
const newValue = [...value];
|
||||
if (optionIndex === -1) {
|
||||
value.push(option.value);
|
||||
newValue.push(option.value);
|
||||
} else {
|
||||
value.splice(optionIndex, 1);
|
||||
newValue.splice(optionIndex, 1);
|
||||
}
|
||||
if (!('value' in this.props)) {
|
||||
this.setState({ value });
|
||||
if (!('value' in restProps)) {
|
||||
setValue(newValue);
|
||||
}
|
||||
const { onChange } = this.props;
|
||||
if (onChange) {
|
||||
const options = this.getOptions();
|
||||
const opts = getOptions();
|
||||
onChange(
|
||||
value
|
||||
newValue
|
||||
.filter(val => registeredValues.indexOf(val) !== -1)
|
||||
.sort((a, b) => {
|
||||
const indexA = options.findIndex(opt => opt.value === a);
|
||||
const indexB = options.findIndex(opt => opt.value === b);
|
||||
const indexA = opts.findIndex(opt => opt.value === a);
|
||||
const indexB = opts.findIndex(opt => opt.value === b);
|
||||
return indexA - indexB;
|
||||
}),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
renderGroup = ({ getPrefixCls, direction }: ConfigConsumerProps) => {
|
||||
const { props, state } = this;
|
||||
const { prefixCls: customizePrefixCls, className, style, options, ...restProps } = props;
|
||||
const prefixCls = getPrefixCls('checkbox', customizePrefixCls);
|
||||
const groupPrefixCls = `${prefixCls}-group`;
|
||||
const prefixCls = getPrefixCls('checkbox', customizePrefixCls);
|
||||
const groupPrefixCls = `${prefixCls}-group`;
|
||||
|
||||
const domProps = omit(restProps, ['children', 'defaultValue', 'value', 'onChange', 'disabled']);
|
||||
const domProps = omit(restProps, ['value', 'disabled']);
|
||||
|
||||
let { children } = props;
|
||||
if (options && options.length > 0) {
|
||||
children = this.getOptions().map(option => (
|
||||
<Checkbox
|
||||
prefixCls={prefixCls}
|
||||
key={option.value.toString()}
|
||||
disabled={'disabled' in option ? option.disabled : props.disabled}
|
||||
value={option.value}
|
||||
checked={state.value.indexOf(option.value) !== -1}
|
||||
onChange={option.onChange}
|
||||
className={`${groupPrefixCls}-item`}
|
||||
style={option.style}
|
||||
>
|
||||
{option.label}
|
||||
</Checkbox>
|
||||
));
|
||||
}
|
||||
if (options && options.length > 0) {
|
||||
children = getOptions().map(option => (
|
||||
<Checkbox
|
||||
prefixCls={prefixCls}
|
||||
key={option.value.toString()}
|
||||
disabled={'disabled' in option ? option.disabled : restProps.disabled}
|
||||
value={option.value}
|
||||
checked={value.indexOf(option.value) !== -1}
|
||||
onChange={option.onChange}
|
||||
className={`${groupPrefixCls}-item`}
|
||||
style={option.style}
|
||||
>
|
||||
{option.label}
|
||||
</Checkbox>
|
||||
));
|
||||
}
|
||||
|
||||
const context = {
|
||||
toggleOption: this.toggleOption,
|
||||
value: this.state.value,
|
||||
disabled: this.props.disabled,
|
||||
name: this.props.name,
|
||||
const context = {
|
||||
toggleOption,
|
||||
value,
|
||||
disabled: restProps.disabled,
|
||||
name: restProps.name,
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/16376
|
||||
registerValue: this.registerValue,
|
||||
cancelValue: this.cancelValue,
|
||||
};
|
||||
|
||||
const classString = classNames(groupPrefixCls, className, {
|
||||
[`${groupPrefixCls}-rtl`]: direction === 'rtl',
|
||||
});
|
||||
return (
|
||||
<div className={classString} style={style} {...domProps}>
|
||||
<GroupContext.Provider value={context}>{children}</GroupContext.Provider>
|
||||
</div>
|
||||
);
|
||||
// https://github.com/ant-design/ant-design/issues/16376
|
||||
registerValue,
|
||||
cancelValue,
|
||||
};
|
||||
|
||||
render() {
|
||||
return <ConfigConsumer>{this.renderGroup}</ConfigConsumer>;
|
||||
}
|
||||
}
|
||||
const classString = classNames(
|
||||
groupPrefixCls,
|
||||
{
|
||||
[`${groupPrefixCls}-rtl`]: direction === 'rtl',
|
||||
},
|
||||
className,
|
||||
);
|
||||
return (
|
||||
<div className={classString} style={style} {...domProps}>
|
||||
<GroupContext.Provider value={context}>{children}</GroupContext.Provider>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CheckboxGroup;
|
||||
export default React.memo(CheckboxGroup);
|
||||
|
||||
@@ -50,7 +50,7 @@ Array [
|
||||
class="ant-checkbox-group"
|
||||
>
|
||||
<label
|
||||
class="ant-checkbox-group-item ant-checkbox-wrapper ant-checkbox-wrapper-checked"
|
||||
class="ant-checkbox-wrapper ant-checkbox-wrapper-checked ant-checkbox-group-item"
|
||||
>
|
||||
<span
|
||||
class="ant-checkbox ant-checkbox-checked"
|
||||
@@ -70,7 +70,7 @@ Array [
|
||||
</span>
|
||||
</label>
|
||||
<label
|
||||
class="ant-checkbox-group-item ant-checkbox-wrapper"
|
||||
class="ant-checkbox-wrapper ant-checkbox-group-item"
|
||||
>
|
||||
<span
|
||||
class="ant-checkbox"
|
||||
@@ -89,7 +89,7 @@ Array [
|
||||
</span>
|
||||
</label>
|
||||
<label
|
||||
class="ant-checkbox-group-item ant-checkbox-wrapper ant-checkbox-wrapper-checked"
|
||||
class="ant-checkbox-wrapper ant-checkbox-wrapper-checked ant-checkbox-group-item"
|
||||
>
|
||||
<span
|
||||
class="ant-checkbox ant-checkbox-checked"
|
||||
@@ -204,7 +204,7 @@ Array [
|
||||
class="ant-checkbox-group"
|
||||
>
|
||||
<label
|
||||
class="ant-checkbox-group-item ant-checkbox-wrapper ant-checkbox-wrapper-checked"
|
||||
class="ant-checkbox-wrapper ant-checkbox-wrapper-checked ant-checkbox-group-item"
|
||||
>
|
||||
<span
|
||||
class="ant-checkbox ant-checkbox-checked"
|
||||
@@ -224,7 +224,7 @@ Array [
|
||||
</span>
|
||||
</label>
|
||||
<label
|
||||
class="ant-checkbox-group-item ant-checkbox-wrapper"
|
||||
class="ant-checkbox-wrapper ant-checkbox-group-item"
|
||||
>
|
||||
<span
|
||||
class="ant-checkbox"
|
||||
@@ -243,7 +243,7 @@ Array [
|
||||
</span>
|
||||
</label>
|
||||
<label
|
||||
class="ant-checkbox-group-item ant-checkbox-wrapper"
|
||||
class="ant-checkbox-wrapper ant-checkbox-group-item"
|
||||
>
|
||||
<span
|
||||
class="ant-checkbox"
|
||||
@@ -268,7 +268,7 @@ Array [
|
||||
class="ant-checkbox-group"
|
||||
>
|
||||
<label
|
||||
class="ant-checkbox-group-item ant-checkbox-wrapper"
|
||||
class="ant-checkbox-wrapper ant-checkbox-group-item"
|
||||
>
|
||||
<span
|
||||
class="ant-checkbox"
|
||||
@@ -287,7 +287,7 @@ Array [
|
||||
</span>
|
||||
</label>
|
||||
<label
|
||||
class="ant-checkbox-group-item ant-checkbox-wrapper ant-checkbox-wrapper-checked"
|
||||
class="ant-checkbox-wrapper ant-checkbox-wrapper-checked ant-checkbox-group-item"
|
||||
>
|
||||
<span
|
||||
class="ant-checkbox ant-checkbox-checked"
|
||||
@@ -307,7 +307,7 @@ Array [
|
||||
</span>
|
||||
</label>
|
||||
<label
|
||||
class="ant-checkbox-group-item ant-checkbox-wrapper"
|
||||
class="ant-checkbox-wrapper ant-checkbox-group-item"
|
||||
>
|
||||
<span
|
||||
class="ant-checkbox"
|
||||
@@ -332,7 +332,7 @@ Array [
|
||||
class="ant-checkbox-group"
|
||||
>
|
||||
<label
|
||||
class="ant-checkbox-group-item ant-checkbox-wrapper ant-checkbox-wrapper-checked ant-checkbox-wrapper-disabled"
|
||||
class="ant-checkbox-wrapper ant-checkbox-wrapper-checked ant-checkbox-wrapper-disabled ant-checkbox-group-item"
|
||||
>
|
||||
<span
|
||||
class="ant-checkbox ant-checkbox-checked ant-checkbox-disabled"
|
||||
@@ -353,7 +353,7 @@ Array [
|
||||
</span>
|
||||
</label>
|
||||
<label
|
||||
class="ant-checkbox-group-item ant-checkbox-wrapper ant-checkbox-wrapper-disabled"
|
||||
class="ant-checkbox-wrapper ant-checkbox-wrapper-disabled ant-checkbox-group-item"
|
||||
>
|
||||
<span
|
||||
class="ant-checkbox ant-checkbox-disabled"
|
||||
@@ -373,7 +373,7 @@ Array [
|
||||
</span>
|
||||
</label>
|
||||
<label
|
||||
class="ant-checkbox-group-item ant-checkbox-wrapper ant-checkbox-wrapper-disabled"
|
||||
class="ant-checkbox-wrapper ant-checkbox-wrapper-disabled ant-checkbox-group-item"
|
||||
>
|
||||
<span
|
||||
class="ant-checkbox ant-checkbox-disabled"
|
||||
|
||||
@@ -5,7 +5,7 @@ exports[`CheckboxGroup passes prefixCls down to checkbox 1`] = `
|
||||
class="my-checkbox-group"
|
||||
>
|
||||
<label
|
||||
class="my-checkbox-group-item my-checkbox-wrapper"
|
||||
class="my-checkbox-wrapper my-checkbox-group-item"
|
||||
>
|
||||
<span
|
||||
class="my-checkbox"
|
||||
@@ -24,7 +24,7 @@ exports[`CheckboxGroup passes prefixCls down to checkbox 1`] = `
|
||||
</span>
|
||||
</label>
|
||||
<label
|
||||
class="my-checkbox-group-item my-checkbox-wrapper"
|
||||
class="my-checkbox-wrapper my-checkbox-group-item"
|
||||
style="font-size:12px"
|
||||
>
|
||||
<span
|
||||
|
||||
@@ -14,25 +14,13 @@ describe('CheckboxGroup', () => {
|
||||
const wrapper = mount(
|
||||
<Checkbox.Group options={['Apple', 'Pear', 'Orange']} onChange={onChange} />,
|
||||
);
|
||||
wrapper
|
||||
.find('.ant-checkbox-input')
|
||||
.at(0)
|
||||
.simulate('change');
|
||||
wrapper.find('.ant-checkbox-input').at(0).simulate('change');
|
||||
expect(onChange).toHaveBeenCalledWith(['Apple']);
|
||||
wrapper
|
||||
.find('.ant-checkbox-input')
|
||||
.at(1)
|
||||
.simulate('change');
|
||||
wrapper.find('.ant-checkbox-input').at(1).simulate('change');
|
||||
expect(onChange).toHaveBeenCalledWith(['Apple', 'Pear']);
|
||||
wrapper
|
||||
.find('.ant-checkbox-input')
|
||||
.at(2)
|
||||
.simulate('change');
|
||||
wrapper.find('.ant-checkbox-input').at(2).simulate('change');
|
||||
expect(onChange).toHaveBeenCalledWith(['Apple', 'Pear', 'Orange']);
|
||||
wrapper
|
||||
.find('.ant-checkbox-input')
|
||||
.at(1)
|
||||
.simulate('change');
|
||||
wrapper.find('.ant-checkbox-input').at(1).simulate('change');
|
||||
expect(onChange).toHaveBeenCalledWith(['Apple', 'Orange']);
|
||||
});
|
||||
|
||||
@@ -47,15 +35,9 @@ describe('CheckboxGroup', () => {
|
||||
const groupWrapper = mount(
|
||||
<Checkbox.Group options={options} onChange={onChangeGroup} disabled />,
|
||||
);
|
||||
groupWrapper
|
||||
.find('.ant-checkbox-input')
|
||||
.at(0)
|
||||
.simulate('change');
|
||||
groupWrapper.find('.ant-checkbox-input').at(0).simulate('change');
|
||||
expect(onChangeGroup).not.toHaveBeenCalled();
|
||||
groupWrapper
|
||||
.find('.ant-checkbox-input')
|
||||
.at(1)
|
||||
.simulate('change');
|
||||
groupWrapper.find('.ant-checkbox-input').at(1).simulate('change');
|
||||
expect(onChangeGroup).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -68,15 +50,9 @@ describe('CheckboxGroup', () => {
|
||||
];
|
||||
|
||||
const groupWrapper = mount(<Checkbox.Group options={options} onChange={onChangeGroup} />);
|
||||
groupWrapper
|
||||
.find('.ant-checkbox-input')
|
||||
.at(0)
|
||||
.simulate('change');
|
||||
groupWrapper.find('.ant-checkbox-input').at(0).simulate('change');
|
||||
expect(onChangeGroup).toHaveBeenCalledWith(['Apple']);
|
||||
groupWrapper
|
||||
.find('.ant-checkbox-input')
|
||||
.at(1)
|
||||
.simulate('change');
|
||||
groupWrapper.find('.ant-checkbox-input').at(1).simulate('change');
|
||||
expect(onChangeGroup).toHaveBeenCalledWith(['Apple']);
|
||||
});
|
||||
|
||||
@@ -105,10 +81,10 @@ describe('CheckboxGroup', () => {
|
||||
];
|
||||
|
||||
const wrapper = mount(<Checkbox.Group options={options} />);
|
||||
|
||||
expect(wrapper.instance().state.value).toEqual([]);
|
||||
expect(wrapper.find('.ant-checkbox-checked').length).toBe(0);
|
||||
wrapper.setProps({ value: ['Apple'] });
|
||||
expect(wrapper.instance().state.value).toEqual(['Apple']);
|
||||
wrapper.update();
|
||||
expect(wrapper.find('.ant-checkbox-checked').length).toBe(1);
|
||||
});
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/12642
|
||||
@@ -119,10 +95,7 @@ describe('CheckboxGroup', () => {
|
||||
<Checkbox value="my" onChange={onChange} />
|
||||
</Checkbox.Group>,
|
||||
);
|
||||
wrapper
|
||||
.find('.ant-checkbox-input')
|
||||
.at(0)
|
||||
.simulate('change');
|
||||
wrapper.find('.ant-checkbox-input').at(0).simulate('change');
|
||||
expect(onChange).toHaveBeenCalled();
|
||||
expect(onChange.mock.calls[0][0].target.value).toEqual('my');
|
||||
});
|
||||
@@ -141,10 +114,7 @@ describe('CheckboxGroup', () => {
|
||||
children: [<Checkbox key={2} value={2} />],
|
||||
});
|
||||
|
||||
wrapper
|
||||
.find('.ant-checkbox-input')
|
||||
.at(0)
|
||||
.simulate('change');
|
||||
wrapper.find('.ant-checkbox-input').at(0).simulate('change');
|
||||
|
||||
expect(onChange).toHaveBeenCalledWith([2]);
|
||||
});
|
||||
@@ -160,12 +130,7 @@ describe('CheckboxGroup', () => {
|
||||
wrapper.setProps({
|
||||
children: [<Checkbox key={1} value={2} />],
|
||||
});
|
||||
expect(
|
||||
wrapper
|
||||
.find('.ant-checkbox-input')
|
||||
.at(0)
|
||||
.prop('checked'),
|
||||
).toBe(false);
|
||||
expect(wrapper.find('.ant-checkbox-input').at(0).prop('checked')).toBe(false);
|
||||
});
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/17297
|
||||
@@ -180,25 +145,13 @@ describe('CheckboxGroup', () => {
|
||||
</Checkbox.Group>,
|
||||
);
|
||||
|
||||
wrapper
|
||||
.find('.ant-checkbox-input')
|
||||
.at(0)
|
||||
.simulate('change');
|
||||
wrapper.find('.ant-checkbox-input').at(0).simulate('change');
|
||||
expect(onChange).toHaveBeenCalledWith([1]);
|
||||
wrapper
|
||||
.find('.ant-checkbox-input')
|
||||
.at(1)
|
||||
.simulate('change');
|
||||
wrapper.find('.ant-checkbox-input').at(1).simulate('change');
|
||||
expect(onChange).toHaveBeenCalledWith([1, 2]);
|
||||
wrapper
|
||||
.find('.ant-checkbox-input')
|
||||
.at(0)
|
||||
.simulate('change');
|
||||
wrapper.find('.ant-checkbox-input').at(0).simulate('change');
|
||||
expect(onChange).toHaveBeenCalledWith([2]);
|
||||
wrapper
|
||||
.find('.ant-checkbox-input')
|
||||
.at(0)
|
||||
.simulate('change');
|
||||
wrapper.find('.ant-checkbox-input').at(0).simulate('change');
|
||||
expect(onChange).toHaveBeenCalledWith([1, 2]);
|
||||
});
|
||||
|
||||
@@ -215,30 +168,10 @@ describe('CheckboxGroup', () => {
|
||||
</Collapse>
|
||||
</Checkbox.Group>,
|
||||
);
|
||||
wrapper
|
||||
.find('.ant-collapse-item')
|
||||
.at(0)
|
||||
.find('.ant-collapse-header')
|
||||
.simulate('click');
|
||||
wrapper
|
||||
.find('.ant-checkbox-input')
|
||||
.at(0)
|
||||
.simulate('change');
|
||||
expect(
|
||||
wrapper
|
||||
.find(Checkbox.Group)
|
||||
.at(0)
|
||||
.state('value'),
|
||||
).toEqual(['1']);
|
||||
wrapper
|
||||
.find('.ant-checkbox-input')
|
||||
.at(0)
|
||||
.simulate('change');
|
||||
expect(
|
||||
wrapper
|
||||
.find(Checkbox.Group)
|
||||
.at(0)
|
||||
.state('value'),
|
||||
).toEqual([]);
|
||||
wrapper.find('.ant-collapse-item').at(0).find('.ant-collapse-header').simulate('click');
|
||||
wrapper.find('.ant-checkbox-input').at(0).simulate('change');
|
||||
expect(wrapper.find('.ant-checkbox-checked').length).toBe(1);
|
||||
wrapper.find('.ant-checkbox-input').at(0).simulate('change');
|
||||
expect(wrapper.find('.ant-checkbox-checked').length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
15
components/checkbox/__tests__/type.test.tsx
Normal file
15
components/checkbox/__tests__/type.test.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import * as React from 'react';
|
||||
import Checkbox from '..';
|
||||
import Input from '../../input';
|
||||
|
||||
describe('Checkbox.typescript', () => {
|
||||
it('Checkbox.Group', () => {
|
||||
const group = (
|
||||
<Checkbox.Group>
|
||||
<Input />
|
||||
</Checkbox.Group>
|
||||
);
|
||||
|
||||
expect(group).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -5,7 +5,7 @@ import RightOutlined from '@ant-design/icons/RightOutlined';
|
||||
|
||||
import CollapsePanel from './CollapsePanel';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import animation from '../_util/openAnimation';
|
||||
import animation from './openAnimation';
|
||||
import { cloneElement } from '../_util/reactNode';
|
||||
|
||||
export type ExpandIconPosition = 'left' | 'right' | undefined;
|
||||
|
||||
@@ -677,6 +677,7 @@ Array [
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity:0"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
|
||||
@@ -1,8 +1,26 @@
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
import rtlTest from '../../../tests/shared/rtlTest';
|
||||
import Collapse from '..';
|
||||
import openAnimation from '../openAnimation';
|
||||
|
||||
describe('Collapse', () => {
|
||||
mountTest(Collapse);
|
||||
rtlTest(Collapse);
|
||||
});
|
||||
|
||||
describe('openAnimation', () => {
|
||||
it('should support openAnimation', () => {
|
||||
const done = jest.fn();
|
||||
const domNode = document.createElement('div');
|
||||
expect(typeof openAnimation.enter).toBe('function');
|
||||
expect(typeof openAnimation.leave).toBe('function');
|
||||
expect(typeof openAnimation.appear).toBe('function');
|
||||
const appear = openAnimation.appear(domNode, done);
|
||||
const enter = openAnimation.enter(domNode, done);
|
||||
const leave = openAnimation.leave(domNode, done);
|
||||
expect(typeof appear.stop).toBe('function');
|
||||
expect(typeof enter.stop).toBe('function');
|
||||
expect(typeof leave.stop).toBe('function');
|
||||
expect(done).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,17 +3,6 @@ import { mount } from 'enzyme';
|
||||
import { sleep } from '../../../tests/utils';
|
||||
|
||||
describe('Collapse', () => {
|
||||
// Fix css-animation deps on these
|
||||
// https://github.com/yiminghe/css-animation/blob/a5986d73fd7dfce75665337f39b91483d63a4c8c/src/Event.js#L44
|
||||
window.AnimationEvent = window.AnimationEvent || (() => {});
|
||||
window.TransitionEvent = window.TransitionEvent || (() => {});
|
||||
|
||||
afterAll(() => {
|
||||
// restore it
|
||||
delete window.AnimationEvent;
|
||||
delete window.TransitionEvent;
|
||||
});
|
||||
|
||||
// eslint-disable-next-line global-require
|
||||
const Collapse = require('..').default;
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ A content area which can be collapsed and expanded.
|
||||
| --- | --- | --- | --- | --- |
|
||||
| disabled | If true, panel cannot be opened or closed | boolean | false | |
|
||||
| forceRender | Forced render of content on panel, instead of lazy rending after clicking on header | boolean | false | |
|
||||
| header | Title of the panel | string \| ReactNode | - | |
|
||||
| header | Title of the panel | ReactNode | - | |
|
||||
| key | Unique key identifying the panel from among its siblings | string \| number | - | |
|
||||
| showArrow | If false, panel will not show arrow icon | boolean | true | |
|
||||
| extra | The extra element in the corner | ReactNode | - | |
|
||||
|
||||
@@ -32,11 +32,11 @@ cover: https://gw.alipayobjects.com/zos/alicdn/IxH16B9RD/Collapse.svg
|
||||
|
||||
### Collapse.Panel
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| ----------- | ------------------------------------------ | ------------------- | ------ | ---- |
|
||||
| disabled | 禁用后的面板展开与否将无法通过用户交互改变 | boolean | false | |
|
||||
| forceRender | 被隐藏时是否渲染 DOM 结构 | boolean | false | |
|
||||
| header | 面板头内容 | string \| ReactNode | - | |
|
||||
| key | 对应 activeKey | string \| number | - | |
|
||||
| showArrow | 是否展示当前面板上的箭头 | boolean | true | |
|
||||
| extra | 自定义渲染每个面板右上角的内容 | ReactNode | - | |
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| ----------- | ------------------------------------------ | ---------------- | ------ | ---- |
|
||||
| disabled | 禁用后的面板展开与否将无法通过用户交互改变 | boolean | false | |
|
||||
| forceRender | 被隐藏时是否渲染 DOM 结构 | boolean | false | |
|
||||
| header | 面板头内容 | ReactNode | - | |
|
||||
| key | 对应 activeKey | string \| number | - | |
|
||||
| showArrow | 是否展示当前面板上的箭头 | boolean | true | |
|
||||
| extra | 自定义渲染每个面板右上角的内容 | ReactNode | - | |
|
||||
|
||||
@@ -20,9 +20,6 @@ function animate(node: HTMLElement, show: boolean, done: () => void) {
|
||||
}
|
||||
},
|
||||
active() {
|
||||
if (requestAnimationFrameId) {
|
||||
raf.cancel(requestAnimationFrameId);
|
||||
}
|
||||
requestAnimationFrameId = raf(() => {
|
||||
node.style.height = `${show ? height : 0}px`;
|
||||
node.style.opacity = show ? '1' : '0';
|
||||
@@ -196,7 +196,7 @@ exports[`renders ./components/comment/demo/editor.md correctly 1`] = `
|
||||
|
||||
exports[`renders ./components/comment/demo/list.md correctly 1`] = `
|
||||
<div
|
||||
class="ant-list comment-list ant-list-split"
|
||||
class="ant-list ant-list-split comment-list"
|
||||
>
|
||||
<div
|
||||
class="ant-list-header"
|
||||
|
||||
@@ -17,8 +17,8 @@ Comments can be used to enable discussions on an entity such as a page, blog pos
|
||||
| Property | Description | Type | Default | Version |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| actions | List of action items rendered below the comment content | Array<ReactNode> | - | |
|
||||
| author | The element to display as the comment author | string \| ReactNode | - | |
|
||||
| avatar | The element to display as the comment avatar - generally an antd Avatar or src | string \| ReactNode | - | |
|
||||
| author | The element to display as the comment author | ReactNode | - | |
|
||||
| avatar | The element to display as the comment avatar - generally an antd Avatar or src | ReactNode | - | |
|
||||
| children | Nested comments should be provided as children of the Comment | ReactNode | - | |
|
||||
| content | The main content of the comment | string \| ReactNode | - | |
|
||||
| datetime | A datetime element containing the time to be displayed | string \| ReactNode | - | |
|
||||
| content | The main content of the comment | ReactNode | - | |
|
||||
| datetime | A datetime element containing the time to be displayed | ReactNode | - | |
|
||||
|
||||
@@ -72,9 +72,13 @@ const Comment: React.FC<CommentProps> = ({
|
||||
</div>
|
||||
);
|
||||
|
||||
const cls = classNames(prefixCls, className, {
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
});
|
||||
const cls = classNames(
|
||||
prefixCls,
|
||||
{
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
},
|
||||
className,
|
||||
);
|
||||
|
||||
return (
|
||||
<div {...otherProps} className={cls}>
|
||||
|
||||
@@ -18,8 +18,8 @@ cover: https://gw.alipayobjects.com/zos/alicdn/ILhxpGzBO/Comment.svg
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| actions | 在评论内容下面呈现的操作项列表 | Array<ReactNode> | - | |
|
||||
| author | 要显示为注释作者的元素 | string \| ReactNode | - | |
|
||||
| avatar | 要显示为评论头像的元素 - 通常是 antd Avatar 或者 src | string \| ReactNode | - | |
|
||||
| author | 要显示为注释作者的元素 | ReactNode | - | |
|
||||
| avatar | 要显示为评论头像的元素 - 通常是 antd Avatar 或者 src | ReactNode | - | |
|
||||
| children | 嵌套注释应作为注释的子项提供 | ReactNode | - | |
|
||||
| content | 评论的主要内容 | string \| ReactNode | - | |
|
||||
| datetime | 展示时间描述 | string \| ReactNode | - | |
|
||||
| content | 评论的主要内容 | ReactNode | - | |
|
||||
| datetime | 展示时间描述 | ReactNode | - | |
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
78
components/config-provider/__tests__/form-locale.test.js
Normal file
78
components/config-provider/__tests__/form-locale.test.js
Normal file
@@ -0,0 +1,78 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import ConfigProvider from '..';
|
||||
import zhCN from '../../locale/zh_CN';
|
||||
import Form from '../../form';
|
||||
|
||||
describe('ConfigProvider.Form.Locale', () => {
|
||||
describe('form validateMessages', () => {
|
||||
const wrapperComponent = ({ validateMessages }) => {
|
||||
const formRef = React.createRef();
|
||||
|
||||
const wrapper = mount(
|
||||
<ConfigProvider locale={zhCN} form={{ validateMessages }}>
|
||||
<Form ref={formRef} initialValues={{ age: 18 }}>
|
||||
<Form.Item name="test" label="姓名" rules={[{ required: true }]}>
|
||||
<input />
|
||||
</Form.Item>
|
||||
<Form.Item name="age" label="年龄" rules={[{ type: 'number', len: 17 }]}>
|
||||
<input />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</ConfigProvider>,
|
||||
);
|
||||
|
||||
return [wrapper, formRef];
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('set locale zhCN', async () => {
|
||||
const [wrapper, formRef] = wrapperComponent({});
|
||||
|
||||
await act(async () => {
|
||||
try {
|
||||
await formRef.current.validateFields();
|
||||
} catch (e) {
|
||||
// Do nothing
|
||||
}
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
jest.runAllTimers();
|
||||
wrapper.update();
|
||||
await Promise.resolve();
|
||||
});
|
||||
|
||||
expect(wrapper.find('.ant-form-item-explain').first().text()).toEqual('请输入姓名');
|
||||
});
|
||||
|
||||
it('set locale zhCN and set form validateMessages one item, other use default message', async () => {
|
||||
const [wrapper, formRef] = wrapperComponent({ validateMessages: { required: '必须' } });
|
||||
|
||||
await act(async () => {
|
||||
try {
|
||||
await formRef.current.validateFields();
|
||||
} catch (e) {
|
||||
// Do nothing
|
||||
}
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
jest.runAllTimers();
|
||||
wrapper.update();
|
||||
await Promise.resolve();
|
||||
});
|
||||
|
||||
expect(wrapper.find('.ant-form-item-explain').first().text()).toEqual('必须');
|
||||
expect(wrapper.find('.ant-form-item-explain').last().text()).toEqual('年龄必须等于17');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -6,12 +6,6 @@ import zhCN from '../../locale/zh_CN';
|
||||
import enUS from '../../locale/en_US';
|
||||
import TimePicker from '../../time-picker';
|
||||
import Modal from '../../modal';
|
||||
import Form from '../../form';
|
||||
|
||||
const delay = (timeout = 0) =>
|
||||
new Promise(resolve => {
|
||||
setTimeout(resolve, timeout);
|
||||
});
|
||||
|
||||
describe('ConfigProvider.Locale', () => {
|
||||
function $$(className) {
|
||||
@@ -113,41 +107,4 @@ describe('ConfigProvider.Locale', () => {
|
||||
testLocale(wrapper);
|
||||
});
|
||||
});
|
||||
|
||||
describe('form validateMessages', () => {
|
||||
const wrapperComponent = ({ validateMessages }) =>
|
||||
mount(
|
||||
<ConfigProvider locale={zhCN} form={{ validateMessages }}>
|
||||
<Form initialValues={{ age: 18 }}>
|
||||
<Form.Item name="test" label="姓名" rules={[{ required: true }]}>
|
||||
<input />
|
||||
</Form.Item>
|
||||
<Form.Item name="age" label="年龄" rules={[{ type: 'number', len: 17 }]}>
|
||||
<input />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</ConfigProvider>,
|
||||
);
|
||||
|
||||
it('set locale zhCN', async () => {
|
||||
const wrapper = wrapperComponent({});
|
||||
|
||||
wrapper.find('form').simulate('submit');
|
||||
await delay(50);
|
||||
wrapper.update();
|
||||
|
||||
expect(wrapper.find('.ant-form-item-explain').first().text()).toEqual('请输入姓名');
|
||||
});
|
||||
|
||||
it('set locale zhCN and set form validateMessages one item, other use default message', async () => {
|
||||
const wrapper = wrapperComponent({ validateMessages: { required: '必须' } });
|
||||
|
||||
wrapper.find('form').simulate('submit');
|
||||
await delay(200);
|
||||
wrapper.update();
|
||||
|
||||
expect(wrapper.find('.ant-form-item-explain').first().text()).toEqual('必须');
|
||||
expect(wrapper.find('.ant-form-item-explain').last().text()).toEqual('年龄必须等于17');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -53,7 +53,9 @@ export interface ConfigProviderProps {
|
||||
dropdownMatchSelectWidth?: boolean;
|
||||
}
|
||||
|
||||
const ConfigProvider: React.FC<ConfigProviderProps> = props => {
|
||||
const ConfigProvider: React.FC<ConfigProviderProps> & {
|
||||
ConfigContext: typeof ConfigContext;
|
||||
} = props => {
|
||||
React.useEffect(() => {
|
||||
if (props.direction) {
|
||||
message.config({
|
||||
@@ -166,4 +168,6 @@ const ConfigProvider: React.FC<ConfigProviderProps> = props => {
|
||||
);
|
||||
};
|
||||
|
||||
/** @private internal usage. do not use in your production */
|
||||
ConfigProvider.ConfigContext = ConfigContext;
|
||||
export default ConfigProvider;
|
||||
|
||||
@@ -48,7 +48,7 @@ export default () => (
|
||||
| getPopupContainer | 弹出框(Select, Tooltip, Menu 等等)渲染父节点,默认渲染到 body 上。 | function(triggerNode) | () => document.body | |
|
||||
| getTargetContainer | 配置 Affix、Anchor 滚动监听容器。 | () => HTMLElement | () => window | 4.2.0 |
|
||||
| locale | 语言包配置,语言包可到 [antd/es/locale](http://unpkg.com/antd/es/locale/) 目录下寻找 | object | - | |
|
||||
| prefixCls | 设置统一样式前缀。`注意:需要配合 less 变量 [@ant-prefix](https://github.com/ant-design/ant-design/blob/2c6c789e3a9356f96c47aea0083f5a15538315cf/components/style/themes/default.less#L7) 使用` | string | `ant` | |
|
||||
| prefixCls | 设置统一样式前缀。注意:需要配合 `less` 变量 [@ant-prefix](https://github.com/ant-design/ant-design/blob/2c6c789e3a9356f96c47aea0083f5a15538315cf/components/style/themes/default.less#L7) 使用 | string | `ant` | |
|
||||
| pageHeader | 统一设置 PageHeader 的 ghost,参考 [PageHeader](/components/page-header) | { ghost: boolean } | true | |
|
||||
| direction | 设置文本展示方向。 [示例](#components-config-provider-demo-direction) | `ltr` \| `rtl` | `ltr` | |
|
||||
| space | 设置 Space 的 `size`,参考 [Space](/components/space) | { size: `small` \| `middle` \| `large` \| `number` } | - | 4.1.0 |
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user