Compare commits

..

182 Commits
3.5.2 ... 3.6.2

Author SHA1 Message Date
Wei Zhu
c3769e3b96 Bump 3.6.2 2018-06-10 12:04:00 +08:00
Wei Zhu
f597c32aa6 Add 3.6.2 changelog (#10856) 2018-06-10 11:53:50 +08:00
Wei Zhu
4d6f8e96b9 Improve AutoComplete types
close #10619
2018-06-09 16:01:18 +08:00
dependabot[bot]
ae6de361e2 Update eslint-plugin-react requirement to 7.9.1 (#10760)
Updates the requirements on [eslint-plugin-react](https://github.com/yannickcr/eslint-plugin-react) to permit the latest version.
<details>
<summary>Release notes</summary>

*Sourced from [eslint-plugin-react's releases](https://github.com/yannickcr/eslint-plugin-react/releases).*

> ## v7.9.1
> Nothing was fixed; this is a republish with some updated deps. ([#1804](https://github-redirect.dependabot.com/yannickcr/eslint-plugin-react/issues/1804) [**ljharb**](https://github.com/ljharb))
</details>
<details>
<summary>Changelog</summary>

*Sourced from [eslint-plugin-react's changelog](https://github.com/yannickcr/eslint-plugin-react/blob/master/CHANGELOG.md).*

> ## [7.9.1] - 2018-06-03
> * Nothing was fixed; this is a republish with some updated deps. ([#1804][] [**ljharb**](https://github.com/ljharb))
> 
> [#1804]: https://github-redirect.dependabot.com/yannickcr/eslint-plugin-react/issues/1804
> 
> ## [7.9.0] - 2018-06-03
> ### Added
> * Add [`jsx-props-no-multi-spaces`][] rule ([#1755][] [**ThiefMaster**](https://github.com/ThiefMaster))
> * Add `first` option to [`jsx-indent-props`][] ([#398][] [**ThiefMaster**](https://github.com/ThiefMaster))
> * Add `enforceDynamicLinks` option to [`jsx-no-target-blank`][] ([#1737][] [**kenearley**](https://github.com/kenearley))
> 
> ### Fixed
> * Fix static lifecycle methods validation in [`sort-comp`][] ([#1793][] [**lynxtaa**](https://github.com/lynxtaa))
> * Fix crash in [`no-typos`][] when encountering anonymous react imports ([#1796][] [**jsg2021**](https://github.com/jsg2021))
> * Fix ESLint 3 support ([#1779][])
> 
> ### Changed
> * Documentation improvements ([#1794][] [**lencioni**](https://github.com/lencioni))
> * Update Travis CI configuration to test on multiple ESLint verions
> 
> [7.9.0]: https://github.com/yannickcr/eslint-plugin-react/compare/v7.8.2...v7.9.0
> [#1755]: https://github-redirect.dependabot.com/yannickcr/eslint-plugin-react/pull/1755
> [#398]: https://github-redirect.dependabot.com/yannickcr/eslint-plugin-react/issues/398
> [#1737]: https://github-redirect.dependabot.com/yannickcr/eslint-plugin-react/issues/1737
> [#1793]: https://github-redirect.dependabot.com/yannickcr/eslint-plugin-react/issues/1793
> [#1796]: https://github-redirect.dependabot.com/yannickcr/eslint-plugin-react/pull/1796
> [#1779]: https://github-redirect.dependabot.com/yannickcr/eslint-plugin-react/issues/1779
> [#1794]: https://github-redirect.dependabot.com/yannickcr/eslint-plugin-react/pull/1794
> 
> ## [7.8.2] - 2018-05-13
> ### Fixed
> * Fix crash in [`boolean-prop-naming`][] when encountering a required shape prop type ([#1791][] [**pcorpet**](https://github.com/pcorpet))
> 
> [7.8.2]: https://github.com/yannickcr/eslint-plugin-react/compare/v7.8.1...v7.8.2
> [#1791]: https://github-redirect.dependabot.com/yannickcr/eslint-plugin-react/issues/1791
> 
> ## [7.8.1] - 2018-05-12
> ### Fixed
> * Fix crash in [`no-deprecated`][] when encountering a class constructor ([#1785][] [**taddei**](https://github.com/taddei))
> 
> [7.8.1]: https://github.com/yannickcr/eslint-plugin-react/compare/v7.8.0...v7.8.1
> [#1785]: https://github-redirect.dependabot.com/yannickcr/eslint-plugin-react/issues/1785
> 
> ## [7.8.0] - 2018-05-11
> ### Added
> * Add support for fragments to [`react-in-jsx-scope`][] ([#1758][])
> * Add support for Flow generic PropType to [`require-default-props`][] ([#1724][] [**Miziak**](https://github.com/Miziak))
> * Add component whitelist option to [`forbid-component-props`][] ([#1732][] [**ThiefMaster**](https://github.com/ThiefMaster))
> * Add support for React 16.3 lifecycle methods to [`no-unused-prop-types`][] ([#1681][] [**bvaughn**](https://github.com/bvaughn))
> * Add support for React 16.3 lifecycle methods to [`sort-comp`][] ([#1767][] [**joe-denea**](https://github.com/joe-denea))
></table> ... (truncated)
</details>
<details>
<summary>Commits</summary>

- See full diff in [compare view](https://github.com/yannickcr/eslint-plugin-react/commits/v7.9.1)
</details>
<br />

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot ignore this [patch|minor|major] version` will close this PR and stop Dependabot creating any more for this minor/major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
- `@dependabot use (this|these) label[s]` will set the current labels as the default for future PRs for this repo and language
- `@dependabot use (this|these) reviewer[s]` will set the current reviewers as the default for future PRs for this repo and language
- `@dependabot use (this|these) assignee[s]` will set the current assignees as the default for future PRs for this repo and language

Additionally, you can set the following in your Dependabot [dashboard](https://app.dependabot.com):
- Update frequency (including time of day and day of week)
- Automerge options (never/patch/minor, and dev/runtime dependencies)
- Pull request limits (per update run and/or open at any time)
- Out-of-range updates (receive only lockfile updates, if desired)
- Security updates (receive only security updates, if desired)

Finally, you can contact us by mentioning @dependabot.

</details>
2018-06-09 14:51:15 +08:00
Wei Zhu
1a9456f03a Add boolean to CheckboxValueType
Close #10677
2018-06-09 14:39:42 +08:00
Wei Zhu
05c5115991 site: fix lint 2018-06-08 23:21:25 +08:00
bLue
8e26b6823a Fix spin delay issue if mounts with spinning=true (#10727)
* Fix spin delay issue if mounts with spinning=true

* Add test for spin delay issue

* Update spin lifecycle method
2018-06-08 23:13:47 +08:00
Wei Zhu
5174801b95 Revert "Upgrade react-dnd"
This reverts commit 71d2a991ed.
2018-06-08 19:01:54 +08:00
Wei Zhu
ac0b4bacc5 Revert "Update snapshot"
This reverts commit e7cd474894.
2018-06-08 19:01:34 +08:00
Wei Zhu
e7cd474894 Update snapshot 2018-06-08 18:13:51 +08:00
陈帅
789b54905c fix #10842 Badge status does not change with themes 2018-06-08 17:59:31 +08:00
Wei Zhu
71d2a991ed Upgrade react-dnd 2018-06-08 17:22:55 +08:00
picodoth
8610eb054f docs: remove changlog info for 3.6.1 2018-06-08 16:58:08 +08:00
afc163
71d3af310a Fix missing border in Button.Group
https://gw.alipayobjects.com/zos/rmsportal/hKuBQeoCgjruYXCGnrDt.png
2018-06-08 15:08:04 +08:00
Wei Zhu
89228118af docs: update moment locale usage 2018-06-08 12:22:22 +08:00
Kirill Alexander Khalitov
0ca1a990be Makes TreeNode component more type safe
Makes TreeNode component more type safe
2018-06-08 10:32:00 +08:00
Kirill Alexander Khalitov
74755fef99 Fix #10838
Fix [#10838](https://github.com/ant-design/ant-design/issues/10838)
2018-06-08 10:32:00 +08:00
Wei Zhu
396f81dbab Update cases.zh-CN.md 2018-06-07 11:58:16 +08:00
Wei Zhu
a4a3b5e12d Update cases.en-US.md 2018-06-07 11:57:11 +08:00
zombiej
78adc05973 close #10745, move dropdownMatchSelectWidth into AbstractSelectProps 2018-06-07 10:24:12 +08:00
zombiej
b524e1fe7e adjust defaultProps def 2018-06-07 00:33:52 +08:00
zombiej
8444ad209d close #10786, spin icon css for adjust font size 2018-06-06 19:53:50 +08:00
杨小事er
ad52250256 fix(calendar): fix fullcalendar content 2px overflow 2018-06-06 16:59:42 +08:00
Junbin Huang
e1ba74e5fc fix: still keep order when upload fails (#10794) 2018-06-06 12:13:06 +08:00
afc163
6602df16e6 Fix extra border style in Button.Group 2018-06-06 11:33:13 +08:00
afc163
17b158c091 Fix CheckboxAll status when remove data and selectedKeys
close #10629
2018-06-05 20:45:19 +08:00
Wei Zhu
c2d94ad84d Don't cache badge since they don't allow cor 2018-06-04 16:24:49 +08:00
Wei Zhu
57a01e1b9f Update offline-plugin 2018-06-04 15:00:43 +08:00
wangshantao
cdc571b17e 图片描述与内容不符 (#10755) 2018-06-04 10:41:47 +08:00
Junbin Huang
d69610a17f docs: update changelog for 3.6.1 (#10753) 2018-06-04 00:02:32 +08:00
Lyndon001
e13c1a678d Update introduce.zh-CN.md 2018-06-03 22:58:59 +08:00
afc163
248dbc2429 docs: update checkbox api 2018-06-03 16:28:20 +08:00
Junbin Huang
37d5f895d2 docs: clean up changelog (#10746) 2018-06-03 00:49:51 +08:00
picodoth
70ca0281ed 3.6.1 2018-06-02 20:41:59 +08:00
Junbin Huang
bbf5cb75c3 chore: update typescript@~2.9.1 (#10748) 2018-06-02 20:12:09 +08:00
Junbin Huang
30eacdfb1b chore: fix lint (#10747) 2018-06-02 18:49:39 +08:00
picodoth
f8314a6b1e docs: add author link correctly in changelog 2018-06-02 16:16:26 +08:00
picodoth
0ea890a0a4 docs: fix changelog typo 2018-06-02 16:02:43 +08:00
picodoth
0fdd13e5d6 chore: update change log for 3.6.0 2018-06-02 15:52:52 +08:00
picodoth
15637c885b 3.6.0 2018-06-02 15:52:52 +08:00
Jack Works
163ec46cbb Fix #9859, #9858 (#10294)
First of all, thank you for your contribution! :-)

Please makes sure that these checkboxes are checked before submitting your PR, thank you!

* [x] Make sure that you propose PR to right branch: bugfix for `master`, feature for latest active branch `feature-x.x`.
* [x] Make sure that you follow antd's [code convention](https://github.com/ant-design/ant-design/wiki/Code-convention-for-antd).
* [x] Run `npm run lint` and fix those errors before submitting in order to keep consistent code style.
* [x] Rebase before creating a PR to keep commit history clear.
* [x] Add some descriptions and refer relative issues for you PR.

Extra checklist:

**if** *isBugFix* **:**

  * [-] Make sure that you add at least one unit test for the bug which you had fixed.
2018-06-02 15:49:11 +08:00
Wei Zhu
2b5abd6dec Use forked offline-plugin 2018-06-02 14:20:03 +08:00
picodoth
e25323882a Merge branch 'feature-3.6.0' 2018-06-02 13:36:05 +08:00
afc163
e124cabc5b update badge snapshot test 2018-06-02 13:18:25 +08:00
Wei Zhu
7149d1fdff Add offline support (#10738)
* site: add offline support

* test update

* Revert "test update"

This reverts commit e1cb2fba80.

* use reduce
2018-06-02 12:46:09 +08:00
hank
5be1b9c33c Fix issue #8666 (#10739)
* fix issue #8666

* add issue #8666 test
2018-06-01 18:09:11 +08:00
Karol Majewski
7c273912fd Fix #10729 (#10730)
* Lift the requirement of the omitted keys being of string type

* Remove unused Diff mapped type
2018-06-01 16:58:15 +08:00
Wei Zhu
87163dfcd6 tests: mock xhr request
Close #10342
2018-05-31 22:37:09 +08:00
Wei Zhu
05251682f1 Remove window reference 2018-05-30 18:13:22 +08:00
Wei Zhu
31be3717ad Upgrade react-dnd 2018-05-30 17:56:56 +08:00
zombiej
ca7ed4c07d clean up 3.5.5 since warning 4.0.1 already fixed 2018-05-30 17:12:18 +08:00
dependabot[bot]
64a29dfd1a Update warning requirement to ~4.0.1
Updates the requirements on [warning](https://github.com/BerkeleyTrue/warning) to permit the latest version.
- [Release notes](https://github.com/BerkeleyTrue/warning/releases)
- [Changelog](https://github.com/BerkeleyTrue/warning/blob/master/CHANGELOG.md)
- [Commits](https://github.com/BerkeleyTrue/warning/commits/v4.0.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-05-30 15:18:58 +08:00
afc163
b5c5f0b5d4 update snapshot 2018-05-29 23:50:49 +08:00
Wu Haotian
4f91fe61bf add z-index for fixed header demo
#10693
2018-05-29 23:49:09 +08:00
Eduardo Ludi
7f16ded760 Updates test for Transfer (removes snapshot) 2018-05-29 17:54:31 +08:00
Eduardo Ludi
9bc98b6471 Adds some tests for Transfer custom styles. 2018-05-29 17:54:31 +08:00
Eduardo Ludi
e8351b8104 Adds style prop to Transfer operation. 2018-05-29 17:54:31 +08:00
Eduardo Ludi
6d610de157 Adds support for custom styles in Transfer and Transfer operation. 2018-05-29 17:54:31 +08:00
Oleg Kuzava
be7f540fba Fix breakpoint for mobile view 2018-05-29 14:05:40 +08:00
afc163
814ee7365a tweak popover arrow style detail 2018-05-28 23:29:04 +08:00
afc163
5fd4139661 Fix Affix offsetBottom not working, close #10674 2018-05-28 17:49:11 +08:00
zombiej
e14928b4f9 update doc 2018-05-28 17:09:49 +08:00
zombiej
19a04e52f4 update change log 2018-05-28 15:34:04 +08:00
afc163
21ca50fca1 Merge branch 'master' into feature-3.6.0 2018-05-28 14:41:02 +08:00
afc163
38f94990f8 Merge branch 'feature-3.6.0' of github.com:ant-design/ant-design into feature-3.6.0 2018-05-28 14:40:58 +08:00
zombiej
d18f100721 Bump 3.5.5 2018-05-28 14:37:57 +08:00
Wu Haotian
b10e7c4e82 downgrade warning to 3.0.0 2018-05-28 14:00:29 +08:00
zombiej
9552f80cde update change-log 2018-05-27 10:39:03 +08:00
zombiej
ad0108dfd5 bump 3.5.4, update change log 2018-05-26 23:59:18 +08:00
zombiej
a6e2037c06 update test case 2018-05-26 23:18:18 +08:00
afc163
ac4a9086a0 test: press enter to search 2018-05-26 17:03:07 +08:00
afc163
12d0aedeca docs: make markdown format 2018-05-26 16:57:52 +08:00
afc163
36ffe7e1dc Search icon could be clicked, close #10634 2018-05-26 16:52:33 +08:00
Eric Celeste
b86f4eeaad improve english 2018-05-26 13:26:11 +08:00
afc163
3ceb619b92 Fix and optimize table demo, close #10639 2018-05-26 00:54:30 +08:00
clinyong
baa78bfa5f Change default word-break to break-word 2018-05-26 00:22:03 +08:00
afc163
8c2f99fd3e test alert 2018-05-25 21:56:57 +08:00
afc163
50057739bf Add test cases for Anchor 2018-05-25 21:43:21 +08:00
afc163
3a445f3e75 more test cases 2018-05-25 21:43:21 +08:00
afc163
be13326a1b Fix typo 2018-05-25 21:43:21 +08:00
afc163
93b14da4a6 improve test code 2018-05-25 21:43:21 +08:00
afc163
21db29bd53 Add test cases for Badge 2018-05-25 21:43:21 +08:00
afc163
d58c0780f9 test Popconfirm 2018-05-25 21:43:21 +08:00
afc163
042c014a38 test => it 2018-05-25 21:43:21 +08:00
afc163
aff9d8fc62 fix lint 2018-05-25 21:43:21 +08:00
afc163
b7b12b657c test: test carousel 2018-05-25 21:43:21 +08:00
afc163
0feaf95629 Fix breadcrumb test case 2018-05-25 21:43:21 +08:00
afc163
076540c83e test: breadcrumd work with react-router 2018-05-25 21:43:21 +08:00
afc163
3db0610d52 Add test case for Cascader 2018-05-25 21:43:21 +08:00
afc163
7222944347 test babel-plugin-import warning 2018-05-25 21:43:21 +08:00
afc163
322ebf0039 fix badge snapshot 2018-05-25 21:43:21 +08:00
Jinxuan Zhu
c2519e776b Add promise-like interface (#10470)
* Add promise-like interface

* Keep hide interface

* Shorten

* Test Promise

* Update document

* Update demo: 2.5 second is insignificant with the default 3s hiding

* Update demo: then  interface

* Fix line break

* Chainable

* Thenable demo

* Thenable test

* Fix tsc error

* Fix tsc error

* Better document

* Revert change in loading.md

* Change snapshot
2018-05-25 20:41:07 +08:00
Winter Zhong
33b604f7a8 Fix issue #10635 Parent element set text-align break Spin (#10643)
* fix the issue when settingthe  parent ele text-align center, the spin is on the right

* put the display in the proper place
2018-05-25 20:40:17 +08:00
dependabot[bot]
4c101275a5 Update jest requirement to ^23.0.0 (#10653)
Updates the requirements on [jest](https://github.com/facebook/jest) to permit the latest version.
- [Release notes](https://github.com/facebook/jest/releases)
- [Changelog](https://github.com/facebook/jest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/facebook/jest/commits/v23.0.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-05-25 16:31:51 +08:00
dependabot[bot]
4c1b2369d7 Update warning requirement to ~4.0.0 (#10654)
Updates the requirements on [warning](https://github.com/BerkeleyTrue/warning) to permit the latest version.
- [Release notes](https://github.com/BerkeleyTrue/warning/releases)
- [Changelog](https://github.com/BerkeleyTrue/warning/blob/master/CHANGELOG.md)
- [Commits](https://github.com/BerkeleyTrue/warning/commits/v4.0.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-05-25 16:31:34 +08:00
afc163
cbff10db15 test: update snapshots 2018-05-25 14:25:26 +08:00
afc163
b7cf33d1eb Fix test case temporarily 2018-05-24 21:45:40 +08:00
afc163
b828a599fb Fix test case temporarily 2018-05-24 21:40:56 +08:00
Rongjian Zhang
f3869270ae Fix #10142: Add theme props to Layout.Sider (#10631)
* Fix #10142: Add `theme` props to `Layout.Sider`

* Update documentation of Layout.Sider for new theme props

* Fix snapshot tests

* Add unit test for sider theme
2018-05-23 23:46:28 +08:00
afc163
2989e8dba0 docs: update API 2018-05-23 22:36:06 +08:00
afc163
6d8df2ac25 test: improve affix test case 2018-05-23 21:03:32 +08:00
Dmitry Snegirev
fd96b4a784 Added missing prop firstActiveValue in Select component (#10636) 2018-05-23 19:13:11 +08:00
jim
af8f4dc5c3 Merge branch 'master' into feature-3.6.0 2018-05-23 16:34:59 +08:00
afc163
8da79f4b34 Badge[status] should work with Tooltip
close #10626
2018-05-23 13:11:49 +08:00
afc163
247d78990e demo: improve editable row demo 2018-05-23 11:32:23 +08:00
Douglas Mason
acb56281f8 fix: update "from" to "form" in code example (#10628)
update `save` method parameter from `from` to `form` in code example
2018-05-23 10:55:20 +08:00
afc163
fafd83cadc Fix mention test case in react 15 2018-05-22 23:29:09 +08:00
afc163
7e96ae1a6a add jest.runAllTimers 2018-05-22 23:29:09 +08:00
afc163
3c381c6dd1 fix test case skip 2018-05-22 23:29:09 +08:00
afc163
292a91a777 Add test cases for Mention 2018-05-22 23:29:09 +08:00
afc163
89ed0dcb35 fix autoUpdateProgress percent and add test case 2018-05-22 23:29:09 +08:00
afc163
77301c378f skip mention test when test dist file 2018-05-22 23:29:09 +08:00
afc163
22d2f9eb01 update snapshot 2018-05-22 23:29:09 +08:00
afc163
3078819535 jest mock generateRandomKey for ssr test
facebook/draft-js#702
2018-05-22 23:29:09 +08:00
afc163
6471e5d4f0 write snapshot files 2018-05-22 23:29:09 +08:00
afc163
1e585135aa Try test mention to see what the problem is 2018-05-22 23:29:09 +08:00
Shun
6057821f39 Change order of loader option in docs (#10627) 2018-05-22 23:08:44 +08:00
Ivan Trofimov
33c58a8ef6 Update ru_RU.tsx (#10616)
* Update locale-provider ru_RU and tests

* Update locale-provider ru_RU and tests: patch-2
2018-05-22 16:31:12 +08:00
paranoidjk
b09e03d82a doc(Input): fix wrong desc about input size in form. 2018-05-22 06:50:14 +00:00
偏右
a2e0e40caa [WIP] Use raf to replace getRequestAnimationFrame (#10614)
* use raf to replace getRequestAnimationFrame

* remove isCssAnimationSupported
2018-05-22 13:01:28 +08:00
dependabot[bot]
f409df8d84 Update react-virtualized requirement to ~9.19.0 (#10552)
Updates the requirements on [react-virtualized](https://github.com/bvaughn/react-virtualized) to permit the latest version.
- [Release notes](https://github.com/bvaughn/react-virtualized/releases)
- [Changelog](https://github.com/bvaughn/react-virtualized/blob/master/CHANGELOG.md)
- [Commits](https://github.com/bvaughn/react-virtualized/commits/9.19.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-05-22 11:26:32 +08:00
afc163
a148bc7b79 doc: update dependencies check badages 2018-05-22 11:26:12 +08:00
Walter Barbagallo
4077ffb58c Enhanced InputNumber props with HTMLInputElement attributes. (#10608)
* Enhanced InputNumber props with HTMLInputElement attributes.

It is possibile to use additional props supported by the inner input
element:

```
const inputEl = <InputNumber autoFocus />
```

Before this commit the type checker did not recognize the `autoFocus`
prop.

Some attributes must be omitted because they conflict with props
defined on `InputNumberProps` interface

* Renamed type

Probably they conflicts with a reserved name?
@see https://travis-ci.org/ant-design/ant-design/jobs/381668406
> components/input-number/index.tsx(9,93): error TS4022: 'extends' clause of exported interface 'InputNumberProps' has or is using private name 'OmitAttributes'.

* Replace InputNumber onKeyDown typing with the typed one.

Extending HTMLInputElement attributes the `onKeyDown` props now have a
better typing.

For example before this commit accessing to the event `key` attribute resulted
in a type error.
@see https://reactjs.org/docs/events.html#keyboard-events

* Exporting type OmitAttrs on InputNumber component.

This is an attempt to solve the ci error:
> components/input-number/index.tsx(9,93): error TS4022: 'extends' clause of exported
> interface 'InputNumberProps' has or is using private name 'OmitAttrs'.

@see https://travis-ci.org/ant-design/ant-design/jobs/381678316
2018-05-22 10:46:20 +08:00
Ezekiel Keator
bb4bc61556 Added missing API documentation (#10611)
* Added missing API documentation

Added missing Divider API documentation.

* Corrected styling

Corrected styling on dash to match other documentation pages.
2018-05-22 10:46:01 +08:00
afc163
0fc5a0ece5 site: add alt to images 2018-05-21 23:47:22 +08:00
afc163
6458280cb3 site: add alt to images 2018-05-21 23:42:57 +08:00
afc163
0f73b5d3f7 site: upgrade analytics code 2018-05-21 23:27:26 +08:00
afc163
14beee1fe1 site: add baidu tongji 2018-05-21 22:58:12 +08:00
dependabot[bot]
e0312f65ee Update stylelint requirement to 9.2.1 (#10553)
Updates the requirements on [stylelint](https://github.com/stylelint/stylelint) to permit the latest version.
- [Release notes](https://github.com/stylelint/stylelint/releases)
- [Changelog](https://github.com/stylelint/stylelint/blob/master/CHANGELOG.md)
- [Commits](https://github.com/stylelint/stylelint/commits/9.2.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-05-21 22:33:53 +08:00
Zheeeng
389c7c4f10 DRY the styles writing for maintenance (#10220) 2018-05-21 21:53:20 +08:00
Zheeeng
59fe98a194 Add position config for List pagination (#10581) 2018-05-21 21:52:18 +08:00
Jamie.LiuMJ
2955600642 fix clearfix (#10563) 2018-05-21 21:52:15 +08:00
sosohime
d4ed303bcd doc: Update DatePicker document about locale (#10598) 2018-05-21 21:51:39 +08:00
Wei Zhu
ff458a2c3f Improve Input type definitions
Close #10166
2018-05-21 21:31:59 +08:00
zombiej
06ffd9ca04 Adjust Tree icon vertical-align, fix #10603 2018-05-21 21:24:16 +08:00
afc163
251d882101 fix dropdown any type 2018-05-21 21:02:03 +08:00
afc163
129baddc44 Remove some typescript any types of cascader 2018-05-21 20:35:14 +08:00
afc163
968488a2fa fix: Cascader showSearch not working bug, close #10599 2018-05-21 18:07:56 +08:00
afc163
00d710cef0 demo: fix select demo order 2018-05-21 17:07:39 +08:00
afc163
ddc242a9cb Merge branch 'master' into feature-3.6.0 2018-05-21 16:11:57 +08:00
jim
d6a554823f Rollback ci modification 2018-05-20 21:38:29 +08:00
jim
fd1d9661c0 update snap fix ci 2018-05-20 15:49:56 +08:00
jim
07b24f4edd fix doc 2018-05-20 14:57:52 +08:00
jim
dbd2bd1866 release 3.5.3 2018-05-20 14:57:52 +08:00
Zheeeng
8b420c41bb Fix typo (#10582)
* Fix typo: splited -> separated

* Fix typo: splited -> separated
2018-05-20 00:50:19 +08:00
方剑成
96d53aefb8 Remove redundant icons (#10583) 2018-05-20 00:49:48 +08:00
afc163
8e2f72ffe0 tweak dropdown menu item padding 2018-05-19 20:34:19 +08:00
afc163
29229ebee7 fix: input onDoubleClick type, close #10518 2018-05-19 20:01:47 +08:00
afc163
e1ad91119a change deps badges 2018-05-18 23:59:42 +08:00
dependabot[bot]
76bf36a79b Update eslint-plugin-react requirement to 7.8.2 (#10493)
Updates the requirements on [eslint-plugin-react](https://github.com/yannickcr/eslint-plugin-react) to permit the latest version.
- [Release notes](https://github.com/yannickcr/eslint-plugin-react/releases)
- [Changelog](https://github.com/yannickcr/eslint-plugin-react/blob/master/CHANGELOG.md)
- [Commits](https://github.com/yannickcr/eslint-plugin-react/commits/v7.8.2)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-05-18 23:43:37 +08:00
Wei Zhu
aa87fcb01e Update snapshot 2018-05-18 18:53:26 +08:00
Wei Zhu
1ed9fed2cf Improve Button and Tag types 2018-05-18 18:22:33 +08:00
afc163
7c4f6e8b2a fix: Revert checkbox z-index
fix #10480

ref #10452

reverted for #10385
2018-05-18 15:36:54 +08:00
Zohaib Ijaz
df7ef9a833 site: Repalced generateColorLess script with antd-theme-generator
* Repalced generateColorLess script with antd-theme-generator which allows to dynamically change theme for all color variables

* Updated antd-theme-generator version

* Updated Ant styles directory path
2018-05-18 12:01:32 +08:00
afc163
9b17a943f5 site: use correct locale for component 2018-05-18 11:34:26 +08:00
qhxin
7404b7f36c fix Affix/index.tsx while offsetTop === 0 and offsetBottom is numberic (#10566)
* Update index.tsx

Fix: if offsetTop === 0, it will get undefined, if offsetBottom is type of number, offsetMode will be { top: false, ... }

* Update index.tsx
2018-05-18 10:18:19 +08:00
Walter Barbagallo
963120f702 Improved Form component typings (#10564)
* Improved Form component typings

With this fix you can use HTMLFormElement attributes on Form component
without getting TypeScript errors.

For example this code does not longer produce error for the additional
`autoComplete` prop:

```
const myForm = (
  <Form autoComplete="off">
    ...
  </Form>
)
```

* Fix onBlur / onChange typings with Input component

This improvement fix a typing issue incompatibility with
`react-final-form`
The incompatibility involve [this
line](https://github.com/final-form/react-final-form/blob/v3.4.2/src/index.d.ts#L20)
where the handler argument is a more specific SyntheticEvent
2018-05-17 23:45:13 +08:00
Wei Zhu
b7d508e166 Fix Row gutter type 2018-05-17 21:47:09 +08:00
afc163
cafeb8e3eb fix button group split border color 2018-05-17 21:36:05 +08:00
afc163
99dca86904 update button disable demo 2018-05-17 21:23:36 +08:00
afc163
09d5e36cfa style: fix hightlight link color in menu item 2018-05-17 21:17:20 +08:00
afc163
6e0865f691 fix less compile error 2018-05-17 17:20:47 +08:00
afc163
eb17aae25c Fix less import error again 2018-05-17 15:21:31 +08:00
afc163
593435ce65 fix import path 2018-05-17 14:39:33 +08:00
afc163
c4f58e7027 fix import path 2018-05-17 11:04:14 +08:00
afc163
b76910f63f fix typo 2018-05-16 11:49:35 +08:00
afc163
12d3046687 style: unify the less vars naming 2018-05-15 17:02:01 +08:00
afc163
d5d0501ac7 site: change footer ui 2018-05-15 12:40:15 +08:00
Wei Zhu
c7c85e3d5d docs: Revert unexpected modify 2018-05-15 12:11:21 +08:00
Wei Zhu
78af67a057 docs: fix table custom search panel demo
close #10494
2018-05-15 11:58:02 +08:00
Reed Sun
604584931e fix text error (#10510)
回掉 => 回调
2018-05-15 11:22:29 +08:00
afc163
77e21d33ea site: fix link 2018-05-14 21:25:38 +08:00
afc163
bdb4483ef5 site: add kitchen link in footer 2018-05-14 19:52:51 +08:00
Andreas Cederström
97c2d58d15 remove bundle size warning in test env (#10363) 2018-05-14 17:13:27 +08:00
Winter Zhong
f09c799bba add the border-right-width to fix the Input.Group component covered box-shadow effect (#10492) 2018-05-14 17:11:11 +08:00
afc163
bc8353729c site: add kitchen homepage 2018-05-14 13:58:54 +08:00
Wei Zhu
bf03d954d4 docs: Fix indent 2018-05-14 12:29:04 +08:00
Xiping.wang
413479a5b9 修改案例title值,原title值容易产生误导
修改案例title值,原title值容易产生误导
2018-05-14 12:08:50 +08:00
afc163
5e0b8df412 site: fix button align of home page 2018-05-14 00:07:39 +08:00
afc163
3413774ae5 update changelog 2018-05-14 00:06:06 +08:00
afc163
f3545ccdc7 Merge branch 'master' into feature-3.6.0 2018-05-12 13:49:33 +08:00
konakona
6c0d6d302a Add feature: can use type ReactNode for message of rules (#10136) (#10395)
* Add feature: can use type ReactNode for message of rules (#10136)

* fix: Replace React.Fragment to span

* Add unit test for Form (Not passed)

* fix: unit test of Form

* fix: unit test of Form & remove demo

* fix: update unit test for Form

* Refine code for Form

* Add error check for getHelpMessage
2018-05-08 14:00:00 +08:00
188 changed files with 6097 additions and 1213 deletions

View File

@@ -15,13 +15,71 @@ timeline: true
---
## 3.6.2
`2018-06-09`
- 🐞 Fix the wrong status of check all checkbox in Table when data change. [#10629](https://github.com/ant-design/ant-design/issues/10629)
- 🐞 Fix border style of Button.Group.
- 🐞 Fix file list being reversed when `beforeUpload` returns `false` in Upload component. [#10681](https://github.com/ant-design/ant-design/issues/10681)
- 🐞 Fix overflow of cell content in Calendar. [#10808](https://github.com/ant-design/ant-design/pull/10808) [@Yangzhedi](https://github.com/ant-design/Yangzhedi)
- 🐞 Fix the processing color of Badge not follows the `primary-color`.
- Spin
- 🐞 Fix custom icon does not follow the value of `size`. [#10786](https://github.com/ant-design/ant-design/issues/10786)
- 🐞 Fix no `delay` issue when sets `spinning` to `true` as default.[#10727](https://github.com/ant-design/ant-design/pull/10727) [@dreamerblue](https://github.com/dreamerblue)
- TypeScript
- 🐞 Fix Menu type definition. [#10773](https://github.com/ant-design/ant-design/issues/10773)
- 🐞 Fix AutoComplete type definition. [#10745](https://github.com/ant-design/ant-design/issues/10745) [#10619](https://github.com/ant-design/ant-design/issues/10619)
- 🐞 Fix Tree type definition. [#10841](https://github.com/ant-design/ant-design/pull/10841) [@Voronar](https://github.com/Voronar)
- 🐞 Fix Checkbox.Group definition. [#10677](https://github.com/ant-design/ant-design/pull/10677)
## 3.6.0
`2018-06-02`
* 🌟 `Form`'s error message now can be customized with ReactNode. [#10136](https://github.com/ant-design/ant-design/issues/10136) [@lovekonakona](https://github.com/lovekonakona)
* 🌟 `List` support customized configuration for position of pagination. [#10581](https://github.com/ant-design/ant-design/pull/10581) [@zheeeng](https://github.com/zheeeng)
* 🌟 `Layout.Sider` now can be configured with `light` or `dark` theme. [#10142](https://github.com/ant-design/ant-design/issues/10142) [@pd4d10](https://github.com/pd4d10)
* 🌟 Ant Design official site now supports offline mode. [#10625](https://github.com/ant-design/ant-design/issues/10625)
* 🌟 `Transfer` adding `style` and `operationStyle` props for further customization. [@eduludi](https://github.com/eduludi)
* 🌟 `Message` adds a promisfied interface to handle callback. [#10421](https://github.com/ant-design/ant-design/issues/10421) [@zhujinxuan](https://github.com/zhujinxuan)
* 🐞 Fix compilation issue with typescript@v2.9.1 . [#10729](https://github.com/ant-design/ant-design/issues/10729) [@karol-majewski](https://github.com/karol-majewski)
* 🐞 Fix a bug in `Menu` where outer menu item not highlighting while inner item is selected. [#8666](https://github.com/ant-design/ant-design/issues/8666) [@stonehank](https://github.com/stonehank)
* 🐞 Affix `offsetBottom` not working. [#10674](https://github.com/ant-design/ant-design/issues/10674)
## 3.5.4
`2018-05-26`
- 🐞 Fix `showSearch` on `Cascader` not working.[968488a2](https://github.com/ant-design/ant-design/commit/968488a2fac9bcb16bee9f0c248f49bca00dbec6)
- 🐞 `Badge[status]` support `Tooltip`.[#10626](https://github.com/ant-design/ant-design/issues/10626)
- 🐞 Fix `text-align` on parent element affects `Spin`.[#10643](https://github.com/ant-design/ant-design/pull/10643) [@wmzhong](https://github.com/wmzhong)
- 💄 `Table` break line style change from `break-all` to `break-word`.[#10655](https://github.com/ant-design/ant-design/pull/10655) [@clinyong](https://github.com/clinyong)
- 🌟 When `Search` not define `enterButton`, click search icon will trigger `onSearch`. [36ffe7e1](https://github.com/ant-design/ant-design/commit/36ffe7e1dc9d9473c8c68168ab79b7a03a604702)
## 3.5.3
`2018-05-20`
- 🐞 Fix `Affix` with offsetTop === 0, value becomes `undefined` problem [#10566](https://github.com/ant-design/ant-design/pull/10566)
- 🐞 Fixed issue with shaded `Input.Group` component shadows[#10230](https://github.com/ant-design/ant-design/issues/10230)
- 🐞 Fixed issue where the `Transfer` component checkbox event fired twice [#10480](https://github.com/ant-design/ant-design/issues/10480)
- 💄 Unifying the name of the variable [12d3046](https://github.com/ant-design/ant-design/commit/12d3046687a0dcdb51fece08dd2bea64f185cc40)
- 💄 Fine-tuned the style of `Dropdown` [8e2f72f](https://github.com/ant-design/ant-design/commit/8e2f72ffe0eb300f5997296726b02246bf990c8f)
- 💄 The components of the Chinese document will now be demonstrated using Chinese language packages. [9b17a94](https://github.com/ant-design/ant-design/commit/9b17a943f5d57d40d65041b7b0c247add09d2851)
- 💄 The main theme switch was changed to `antd-theme-generato`, thanks to the work of [@mzohaibqc](https://github.com/mzohaibqc).
- TypeScript
- 🐞 Fixed an issue with the type of gutter attribute in `Row` [b7d508e](https://github.com/ant-design/ant-design/commit/b7d508e1662bf20a0cacbe6440a2ce31a65a8a59)
- 💄 Improved the `Form` component type [#10564](https://github.com/ant-design/ant-design/pull/10564)
- 💄 Improved the `Button` and `Tag` types[1ed9fed](https://github.com/ant-design/ant-design/commit/1ed9fed2cf1c99b947359fafb101b2e58213cb48)
## 3.5.2
`2018-05-13`
- 🐞 Fixed `Table` filter doesn't work when click checkbox. [#10452](https://github.com/ant-design/ant-design/issues/10452)
- 🐞 Fixed `Cascader` displayRender z-index issue. [#10433](https://github.com/ant-design/ant-design/issues/10433)
- 🐞 Fixed `Button` Types of property 'ref' are incompatible. [#10405](https://github.com/ant-design/ant-design/issues/10405)
- 🐞 Fixed `Table` filter doesn't work on checkbox click. [#10452](https://github.com/ant-design/ant-design/issues/10452)
- 🐞 Fixed the height of `Form` item when checks position is dithered. [#10445](https://github.com/ant-design/ant-design/issues/10445)
- 🌟 Allow to use any CSS units for `Layout` width. [#10479](https://github.com/ant-design/ant-design/pull/10479)
@@ -441,7 +499,7 @@ Happy 2018 !~ 2018 2018 2018 coming!~~~
`2017-12-04`
Learn more in the [Ant Design 3.0 announcement post](https://medium.com/ant-design/announcing-ant-design-3-0-70e3e65eca0c)!
Learn more in the [Ant Design 3.0 announcement post](https://medium.com/ant-design/announcing-ant-design-3-0-70e3e65eca0c).
### Major Changes

View File

@@ -15,13 +15,72 @@ timeline: true
---
## 3.6.2
`2018-06-09`
- 🐞 修复 Table 数据变化时全选勾选框状态显示不正确的问题。[#10629](https://github.com/ant-design/ant-design/issues/10629)
- 🐞 修复 Button.Group 中使用 disabled 按钮时缺失边框。
- 🐞 修复 Upload 中 `beforeUpload` 返回 `false` 时,文件列表排序会被反转的问题。[#10681](https://github.com/ant-design/ant-design/issues/10681)
- 🐞 修复 Calendar 表格中内容溢出的问题。[#10808](https://github.com/ant-design/ant-design/pull/10808) [@Yangzhedi](https://github.com/ant-design/Yangzhedi)
- Spin
- 🐞 修复使用图标时不能按照 `size` 正确显示大小的问题。[#10786](https://github.com/ant-design/ant-design/issues/10786)
- 🐞 修复默认旋转时 `delay` 不生效的问题。[#10727](https://github.com/ant-design/ant-design/pull/10727) [@dreamerblue](https://github.com/dreamerblue)
- 修复 Badge 的状态色不跟主题色变化的问题。
- TypeScript
- 🐞 修复 Menu 类型定义。[#10773](https://github.com/ant-design/ant-design/issues/10773)
- 🐞 修复 AutoComplete 类型定义。[#10745](https://github.com/ant-design/ant-design/issues/10745) [#10619](https://github.com/ant-design/ant-design/issues/10619)
- 🐞 修复 Tree 类型定义。[#10841](https://github.com/ant-design/ant-design/pull/10841) [@Voronar](https://github.com/Voronar)
- 🐞 修复 Checkbox.Group 的类型定义。[#10677](https://github.com/ant-design/ant-design/pull/10677)
## 3.6.0
`2018-06-02`
* 🌟 `Form` 表单错误信息展示支持传入 ReactNode。 [#10136](https://github.com/ant-design/ant-design/issues/10136) [@lovekonakona](https://github.com/lovekonakona)
* 🌟 `List` 组件支持指定分页器的位置。 [#10581](https://github.com/ant-design/ant-design/pull/10581) [@zheeeng](https://github.com/zheeeng)
* 🌟 `Layout.Sider` 支持 dark/light 主题定制。 [#10142](https://github.com/ant-design/ant-design/issues/10142) [@pd4d10](https://github.com/pd4d10)
* 🌟 支持 Ant Design 站点的离线模式。 [#10625](https://github.com/ant-design/ant-design/issues/10625)
* 🌟 `Transfer` 新增 `style` 以及 `operationStyle` 属性配置样式。 [@eduludi](https://github.com/eduludi)
* 🌟 `Message` 增加 promise 化的回调接口。 [#10421](https://github.com/ant-design/ant-design/issues/10421) [@zhujinxuan](https://github.com/zhujinxuan)
* 🐞 修复编译时 typescript v2.9.1兼容性问题。 [#10729](https://github.com/ant-design/ant-design/issues/10729) [@karol-majewski](https://github.com/karol-majewski)
* 🐞 修复 `Menu` 嵌套超过两层时选中最里层后对应最外层没有亮起问题。 [#8666](https://github.com/ant-design/ant-design/issues/8666) [@stonehank](https://github.com/stonehank)
* 🐞 修复 `Affix` 组件 offsetBottom 无效问题。 [#10674](https://github.com/ant-design/ant-design/issues/10674)
## 3.5.4
`2018-05-26`
- 🐞 修复 `Cascader``showSearch` 无效问题。[968488a2](https://github.com/ant-design/ant-design/commit/968488a2fac9bcb16bee9f0c248f49bca00dbec6)
- 🐞 使 `Badge[status]` 支持 `Tooltip`。[#10626](https://github.com/ant-design/ant-design/issues/10626)
- 🐞 修复父元素使用 `text-align` 会影响 `Spin` 的问题。[#10643](https://github.com/ant-design/ant-design/pull/10643) [@wmzhong](https://github.com/wmzhong)
- 💄 `Table` 换行从 `break-all` 改为 `break-word`。[#10655](https://github.com/ant-design/ant-design/pull/10655) [@clinyong](https://github.com/clinyong)
- 🌟 `Search` 在未定义 `enterButton` 时,点击搜索图标将触发 `onSearch`。 [36ffe7e1](https://github.com/ant-design/ant-design/commit/36ffe7e1dc9d9473c8c68168ab79b7a03a604702)
## 3.5.3
`2018-05-20`
- 🐞 修复了 `Affix``offsetTop === 0`, 值将变为 `undefined` 的问题 [#10566](https://github.com/ant-design/ant-design/pull/10566)
- 🐞 修复了 `Menu` item 中的高亮链接颜色问题 [09d5e36](https://github.com/ant-design/ant-design/commit/09d5e36cfa27e371a7b4d4e68276a279698ea901)
- 🐞 修复了 `Input.Group` 组件阴影被遮盖的问题 [#10230](https://github.com/ant-design/ant-design/issues/10230)
- 🐞 修复了 `Transfer` 组件 checkbox 事件触发两次的问题 [`#10480`](https://github.com/ant-design/ant-design/issues/10480)
- 💄 统一 less 的变量命名 [12d3046](https://github.com/ant-design/ant-design/commit/12d3046687a0dcdb51fece08dd2bea64f185cc40)
- 💄 微调了 `Dropdown` 的样式 [8e2f72f](https://github.com/ant-design/ant-design/commit/8e2f72ffe0eb300f5997296726b02246bf990c8f)
- 💄 现在中文文档的组件会用中文语言包进行演示。[9b17a94](https://github.com/ant-design/ant-design/commit/9b17a943f5d57d40d65041b7b0c247add09d2851)
- 💄 主站主题切换 修改为 `antd-theme-generato` ,感谢 [@mzohaibqc](https://github.com/mzohaibqc) 的工作.
- TypeScript
- 🐞 修复了 `Row` 中 gutter 属性的类型问题 [b7d508e](https://github.com/ant-design/ant-design/commit/b7d508e1662bf20a0cacbe6440a2ce31a65a8a59)
- 💄 改进了 `Form` 组件类型 [#10564](https://github.com/ant-design/ant-design/pull/10564)
- 💄 改进了 `Button``Tag` 类型 [1ed9fed](https://github.com/ant-design/ant-design/commit/1ed9fed2cf1c99b947359fafb101b2e58213cb48)
## 3.5.2
`2018-05-13`
- 🐞 修复 `Cascader` displayRender 问题。[#10433](https://github.com/ant-design/ant-design/issues/10433)
- 🐞 修复 `Table` 过滤器和 `Transfer` 复选框无法点击的问题。[#10452](https://github.com/ant-design/ant-design/issues/10452)
- 🐞 修复 `Cascader` `displayRender` 里的链接无法点击的问题。[#10433](https://github.com/ant-design/ant-design/issues/10433)
- 🐞 修复 `Button` ref 不兼容问题。[#10405](https://github.com/ant-design/ant-design/issues/10405)
- 🐞 修复 `Table` 过滤器在复选框上不起作用。[#10452](https://github.com/ant-design/ant-design/issues/10452)
- 🐞 修复 `Form` 表单项校验位置高度时出现抖动问题。[#10445](https://github.com/ant-design/ant-design/issues/10445)
- 🌟 设置 `Layout` 宽度时,允许使用任何的 CSS 单位。 [#10479](https://github.com/ant-design/ant-design/pull/10479)
@@ -442,11 +501,11 @@ timeline: true
`2017-12-04`
更多内容见 [Ant Design 3.0 发布公告](https://medium.com/ant-design/announcing-ant-design-3-0-70e3e65eca0c)
更多内容见 [Ant Design 3.0 发布公告](https://medium.com/ant-design/announcing-ant-design-3-0-70e3e65eca0c)
### 主要变化
- 全新的[色彩系统](https://ant.design/docs/spec/colors-cn#Color-Palettes),组件主色由 `#108EE9` 改为 `#1890FF`』,新主色我们称之为『拂晓蓝』。
- 全新的[色彩系统](https://ant.design/docs/spec/colors-cn#Color-Palettes),组件主色由『`#108EE9`』改为『`#1890FF`』,新主色我们称之为『拂晓蓝』。
- 全新的视觉样式和组件尺寸,更现代更美观。
- 基础字体大小由 `12px` 增大到 `14px`
- 默认语言由中文改为英文。
@@ -458,6 +517,8 @@ timeline: true
### 不兼容改动
> 如果你从 2.x 升级到 3.x建议直接升级到 3.x 的最新版本。
此版本有部分不兼容的改动,升级时确保修改相应的使用代码。另外由于人肉查找代码中的废弃用法过于低效,所以我们提供了 [antd-migration-helper](https://github.com/ant-design/antd-migration-helper) 用于扫描代码中的废弃用法。
- Card 的 `noHovering` 属性重命名为 `hoverable`,且默认值改为 `true`
@@ -504,7 +565,7 @@ timeline: true
- Form 下的表单控件不再默认为 `size="large"`。
- `Input.Search` 默认的 🔍 图标只作为装饰,不再响应用户交互。需要添加可交互按钮请使用 `enterButton`。
- UMD 版本的 `dist/antd.js` 不再包含 moment使用的时候需要自己引入 moment。
- UMD 版本的 `dist/antd.js` 不再包含 moment使用的时候需要自己引入 moment。
```diff
<html>
<head>

View File

@@ -8,7 +8,8 @@
[![](https://img.shields.io/travis/ant-design/ant-design.svg?style=flat-square)](https://travis-ci.org/ant-design/ant-design)
[![Codecov](https://img.shields.io/codecov/c/github/ant-design/ant-design/master.svg?style=flat-square)](https://codecov.io/gh/ant-design/ant-design/branch/master)
[![Dependency Status](https://img.shields.io/gemnasium/react-component/trigger.svg?style=flat-square)](https://gemnasium.com/ant-design/ant-design)
[![bitHound [![Dependencies](https://img.shields.io/david/ant-design/ant-design.svg)](https://david-dm.org/ant-design/ant-design)
[![DevDependencies](https://img.shields.io/david/dev/ant-design/ant-design.svg)](https://david-dm.org/ant-design/ant-design#info=devDependencies&view=list)
[![npm package](https://img.shields.io/npm/v/antd.svg?style=flat-square)](https://www.npmjs.org/package/antd)
[![NPM downloads](http://img.shields.io/npm/dm/antd.svg?style=flat-square)](http://www.npmtrends.com/antd)

View File

@@ -8,7 +8,8 @@
[![](https://img.shields.io/travis/ant-design/ant-design.svg?style=flat-square)](https://travis-ci.org/ant-design/ant-design)
[![Codecov](https://img.shields.io/codecov/c/github/ant-design/ant-design/master.svg?style=flat-square)](https://codecov.io/gh/ant-design/ant-design/branch/master)
[![Dependency Status](https://img.shields.io/gemnasium/react-component/trigger.svg?style=flat-square)](https://gemnasium.com/ant-design/ant-design)
[![Dependencies](https://img.shields.io/david/ant-design/ant-design.svg)](https://david-dm.org/ant-design/ant-design)
[![DevDependencies](https://img.shields.io/david/dev/ant-design/ant-design.svg)](https://david-dm.org/ant-design/ant-design#info=devDependencies&view=list)
[![npm package](https://img.shields.io/npm/v/antd.svg?style=flat-square)](https://www.npmjs.org/package/antd)
[![NPM downloads](http://img.shields.io/npm/dm/antd.svg?style=flat-square)](http://www.npmtrends.com/antd)

View File

@@ -1,12 +1,18 @@
const OLD_NODE_ENV = process.env.NODE_ENV;
process.env.NODE_ENV = 'development';
const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
const antd = require('..');
describe('antd', () => {
afterAll(() => {
process.env.NODE_ENV = OLD_NODE_ENV;
});
it('exports modules correctly', () => {
expect(Object.keys(antd)).toMatchSnapshot();
});
it('should hint when import all components', () => {
it('should hint when import all components in dev mode', () => {
expect(warnSpy).toBeCalledWith(
'You are using a whole package of antd, please use https://www.npmjs.com/package/babel-plugin-import to reduce app bundle size.'
);

View File

@@ -1,46 +0,0 @@
const availablePrefixs = ['moz', 'ms', 'webkit'];
function requestAnimationFramePolyfill() {
let lastTime = 0;
return function(callback: (n: number) => void) {
const currTime = new Date().getTime();
const timeToCall = Math.max(0, 16 - (currTime - lastTime));
const id = window.setTimeout(function() { callback(currTime + timeToCall); }, timeToCall);
lastTime = currTime + timeToCall;
return id;
};
}
export default function getRequestAnimationFrame() {
if (typeof window === 'undefined') {
return () => {};
}
if (window.requestAnimationFrame) {
// https://github.com/vuejs/vue/issues/4465
return window.requestAnimationFrame.bind(window);
}
const prefix = availablePrefixs.filter(key => `${key}RequestAnimationFrame` in window)[0];
return prefix
? (window as any)[`${prefix}RequestAnimationFrame`]
: requestAnimationFramePolyfill();
}
export function cancelRequestAnimationFrame(id: number) {
if (typeof window === 'undefined') {
return null;
}
if (window.cancelAnimationFrame) {
return window.cancelAnimationFrame(id);
}
const prefix = availablePrefixs.filter(key =>
`${key}CancelAnimationFrame` in window || `${key}CancelRequestAnimationFrame` in window,
)[0];
return prefix ?
(
(window as any)[`${prefix}CancelAnimationFrame`] ||
(window as any)[`${prefix}CancelRequestAnimationFrame`]
).call(this, id) : clearTimeout(id);
}

View File

@@ -1,24 +0,0 @@
let animation: boolean;
function isCssAnimationSupported() {
if (animation !== undefined) {
return animation;
}
const domPrefixes = 'Webkit Moz O ms Khtml'.split(' ');
const elm = document.createElement('div');
if (elm.style.animationName !== undefined) {
animation = true;
}
if (animation !== undefined) {
for (let i = 0; i < domPrefixes.length; i++) {
if ((elm.style as any)[`${domPrefixes[i]}AnimationName`] !== undefined) {
animation = true;
break;
}
}
}
animation = animation || false;
return animation;
}
export default isCssAnimationSupported;

View File

@@ -1,7 +1,5 @@
import cssAnimation from 'css-animation';
import getRequestAnimationFrame, { cancelRequestAnimationFrame } from './getRequestAnimationFrame';
const reqAnimFrame = getRequestAnimationFrame();
import raf from 'raf';
function animate(node: HTMLElement, show: boolean, done: () => void) {
let height: number;
@@ -19,16 +17,16 @@ function animate(node: HTMLElement, show: boolean, done: () => void) {
},
active() {
if (requestAnimationFrameId) {
cancelRequestAnimationFrame(requestAnimationFrameId);
raf.cancel(requestAnimationFrameId);
}
requestAnimationFrameId = reqAnimFrame(() => {
requestAnimationFrameId = raf(() => {
node.style.height = `${show ? height : 0}px`;
node.style.opacity = show ? '1' : '0';
});
},
end() {
if (requestAnimationFrameId) {
cancelRequestAnimationFrame(requestAnimationFrameId);
raf.cancel(requestAnimationFrameId);
}
node.style.height = '';
node.style.opacity = '';

View File

@@ -1,6 +1,4 @@
import getRequestAnimationFrame, { cancelRequestAnimationFrame } from '../_util/getRequestAnimationFrame';
const reqAnimFrame = getRequestAnimationFrame();
import raf from 'raf';
export default function throttleByAnimationFrame(fn: (...args: any[]) => void) {
let requestId: number | null;
@@ -12,11 +10,11 @@ export default function throttleByAnimationFrame(fn: (...args: any[]) => void) {
const throttled = (...args: any[]) => {
if (requestId == null) {
requestId = reqAnimFrame(later(args));
requestId = raf(later(args));
}
};
(throttled as any).cancel = () => cancelRequestAnimationFrame(requestId!);
(throttled as any).cancel = () => raf.cancel(requestId!);
return throttled;
}

View File

@@ -1,3 +1 @@
export type Diff<T extends string, U extends string> = ({ [P in T]: P } &
{ [P in U]: never } & { [x: string]: never })[T];
export type Omit<T, K extends keyof T> = Pick<T, Diff<keyof T, K>>;
export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;

View File

@@ -7,7 +7,6 @@ const events = {};
class AffixMounter extends React.Component {
componentDidMount() {
this.container.scrollTop = 100;
this.container.addEventListener = jest.fn().mockImplementation((event, cb) => {
events[event] = cb;
});
@@ -34,6 +33,7 @@ class AffixMounter extends React.Component {
<Affix
target={() => this.container}
ref={ele => this.affix = ele}
{...this.props}
>
<Button type="primary" >
Fixed at the top of container
@@ -46,6 +46,8 @@ class AffixMounter extends React.Component {
}
describe('Affix Render', () => {
let wrapper;
beforeAll(() => {
jest.useFakeTimers();
});
@@ -54,23 +56,48 @@ describe('Affix Render', () => {
jest.useRealTimers();
});
it('Anchor render perfectly', () => {
document.body.innerHTML = '<div id="mounter" />';
const wrapper = mount(<AffixMounter />, { attachTo: document.getElementById('mounter') });
jest.runAllTimers();
const scrollTo = (top) => {
wrapper.instance().affix.fixedNode.parentNode.getBoundingClientRect = jest.fn(() => {
return {
bottom: 100, height: 28, left: 0, right: 0, top: -50, width: 195,
bottom: 100, height: 28, left: 0, right: 0, top: 50 - top, width: 195,
};
});
wrapper.instance().container.scrollTop = top;
events.scroll({
type: 'scroll',
});
jest.runAllTimers();
};
it('Anchor render perfectly', () => {
document.body.innerHTML = '<div id="mounter" />';
wrapper = mount(<AffixMounter />, { attachTo: document.getElementById('mounter') });
jest.runAllTimers();
scrollTo(0);
expect(wrapper.instance().affix.state.affixStyle).toBe(null);
scrollTo(100);
expect(wrapper.instance().affix.state.affixStyle).not.toBe(null);
scrollTo(0);
expect(wrapper.instance().affix.state.affixStyle).toBe(null);
});
it('support offsetBottom', () => {
document.body.innerHTML = '<div id="mounter" />';
wrapper = mount(<AffixMounter offsetBottom={0} />, { attachTo: document.getElementById('mounter') });
jest.runAllTimers();
scrollTo(0);
expect(wrapper.instance().affix.state.affixStyle).not.toBe(null);
scrollTo(100);
expect(wrapper.instance().affix.state.affixStyle).toBe(null);
scrollTo(0);
expect(wrapper.instance().affix.state.affixStyle).not.toBe(null);
});
});

View File

@@ -38,8 +38,7 @@ function getOffset(element: HTMLElement, target: HTMLElement | Window | null) {
function noop() {}
function getDefaultTarget() {
return typeof window !== 'undefined' ?
window : null;
return typeof window !== 'undefined' ? window : null;
}
// Affix
@@ -145,7 +144,9 @@ export default class Affix extends React.Component<AffixProps, AffixState> {
const targetNode = target();
// Backwards support
offsetTop = offsetTop || offset;
// Fix: if offsetTop === 0, it will get undefined,
// if offsetBottom is type of number, offsetMode will be { top: false, ... }
offsetTop = typeof offsetTop === 'undefined' ? offset : offsetTop;
const scrollTop = getScroll(targetNode, true);
const affixNode = ReactDOM.findDOMNode(this) as HTMLElement;
const elemOffset = getOffset(affixNode, targetNode);

View File

@@ -0,0 +1,31 @@
import React from 'react';
import { mount } from 'enzyme';
import Alert from '..';
describe('Alert', () => {
beforeAll(() => {
jest.useFakeTimers();
});
afterAll(() => {
jest.useRealTimers();
});
it('could be closed', () => {
const onClose = jest.fn();
const afterClose = jest.fn();
const wrapper = mount(
<Alert
message="Warning Text Warning Text Warning TextW arning Text Warning Text Warning TextWarning Text"
type="warning"
closable
onClose={onClose}
afterClose={afterClose}
/>
);
wrapper.find('.ant-alert-close-icon').simulate('click');
expect(onClose).toBeCalled();
jest.runAllTimers();
expect(afterClose).toBeCalled();
});
});

View File

@@ -16,7 +16,7 @@ title: Alert
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| afterClose | 关闭动画结束后的回掉 | () => void | - |
| afterClose | 关闭动画结束后触发的回调函数 | () => void | - |
| banner | 是否用作顶部公告 | boolean | false |
| closable | 默认不显示关闭按钮 | boolean | 无 |
| closeText | 自定义关闭按钮 | string\|ReactNode | 无 |

View File

@@ -6,7 +6,7 @@ import addEventListener from 'rc-util/lib/Dom/addEventListener';
import Affix from '../affix';
import AnchorLink from './AnchorLink';
import getScroll from '../_util/getScroll';
import getRequestAnimationFrame from '../_util/getRequestAnimationFrame';
import raf from 'raf';
function getDefaultContainer() {
return window;
@@ -43,7 +43,6 @@ function easeInOutCubic(t: number, b: number, c: number, d: number) {
return cc / 2 * ((t -= 2) * t * t + 2) + b;
}
const reqAnimFrame = getRequestAnimationFrame();
const sharpMatcherRegx = /#([^#]+)$/;
function scrollTo(href: string, offsetTop = 0, getContainer: () => AnchorContainer, callback = () => { }) {
const container = getContainer();
@@ -67,12 +66,12 @@ function scrollTo(href: string, offsetTop = 0, getContainer: () => AnchorContain
(container as HTMLElement).scrollTop = nextScrollTop;
}
if (time < 450) {
reqAnimFrame(frameFunc);
raf(frameFunc);
} else {
callback();
}
};
reqAnimFrame(frameFunc);
raf(frameFunc);
history.pushState(null, '', href);
}

View File

@@ -28,7 +28,7 @@ describe('Anchor Render', () => {
expect(wrapper.instance().state.activeLink).toBe('http://www.example.com/#API');
});
it('Anchor render perfectly for complete href - scoll', () => {
it('Anchor render perfectly for complete href - scroll', () => {
let root = document.getElementById('root');
if (!root) {
root = document.createElement('div', { id: 'root' });
@@ -45,7 +45,8 @@ describe('Anchor Render', () => {
expect(wrapper.instance().state.activeLink).toBe('http://www.example.com/#API');
});
it('Anchor render perfectly for complete href - scollTo', () => {
it('Anchor render perfectly for complete href - scrollTo', async () => {
const scrollToSpy = jest.spyOn(window, 'scrollTo');
let root = document.getElementById('root');
if (!root) {
root = document.createElement('div', { id: 'root' });
@@ -60,5 +61,33 @@ describe('Anchor Render', () => {
);
wrapper.instance().handleScrollTo('##API');
expect(wrapper.instance().state.activeLink).toBe('##API');
expect(scrollToSpy).not.toHaveBeenCalled();
await new Promise(resolve => setTimeout(resolve, 50));
expect(scrollToSpy).toHaveBeenCalled();
expect(wrapper.instance().animating).toBe(true);
await new Promise(resolve => setTimeout(resolve, 500));
expect(wrapper.instance().animating).toBe(false);
});
it('should remove listener when unmount', async () => {
const wrapper = mount(
<Anchor>
<Link href="#API" title="API" />
</Anchor>
);
const removeListenerSpy = jest.spyOn(wrapper.instance().scrollEvent, 'remove');
wrapper.unmount();
expect(removeListenerSpy).toHaveBeenCalled();
});
it('should unregister link when unmount children', async () => {
const wrapper = mount(
<Anchor>
<Link href="#API" title="API" />
</Anchor>
);
expect(wrapper.instance().links).toEqual(['#API']);
wrapper.setProps({ children: null });
expect(wrapper.instance().links).toEqual([]);
});
});

View File

@@ -6,7 +6,11 @@ import Input from '../input';
import InputElement from './InputElement';
export interface DataSourceItemObject { value: string; text: string; }
export type DataSourceItemType = string | DataSourceItemObject;
export type DataSourceItemType =
string |
DataSourceItemObject |
React.ReactElement<OptionProps> |
React.ReactElement<OptGroupProps>;
export interface AutoCompleteInputProps {
onChange?: React.FormEventHandler<any>;

View File

@@ -75,7 +75,7 @@ export default class Avatar extends React.Component<AvatarProps, AvatarState> {
render() {
const {
prefixCls, shape, size, src, icon, className, ...others,
prefixCls, shape, size, src, icon, className, ...others
} = this.props;
const sizeCls = classNames({

View File

@@ -4,9 +4,7 @@ import addEventListener from 'rc-util/lib/Dom/addEventListener';
import classNames from 'classnames';
import omit from 'omit.js';
import getScroll from '../_util/getScroll';
import getRequestAnimationFrame from '../_util/getRequestAnimationFrame';
const reqAnimFrame = getRequestAnimationFrame();
import raf from 'raf';
const easeInOutCubic = (t: number, b: number, c: number, d: number) => {
const cc = c - b;
@@ -64,10 +62,10 @@ export default class BackTop extends React.Component<BackTopProps, any> {
const time = timestamp - startTime;
this.setScrollTop(easeInOutCubic(time, scrollTop, 0, 450));
if (time < 450) {
reqAnimFrame(frameFunc);
raf(frameFunc);
}
};
reqAnimFrame(frameFunc);
raf(frameFunc);
(this.props.onClick || noop)(e);
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +1,23 @@
import React from 'react';
import { mount } from 'enzyme';
import { mount, render } from 'enzyme';
import Badge from '../index';
import Tooltip from '../../tooltip';
describe('Badge', () => {
test('badge dot not scaling count > 9', () => {
beforeEach(() => {
jest.useFakeTimers();
});
afterEach(() => {
jest.useRealTimers();
});
it('badge dot not scaling count > 9', () => {
const badge = mount(<Badge count={10} dot />);
expect(badge.find('.ant-card-multiple-words').length).toBe(0);
});
test('badge dot not showing count == 0', () => {
it('badge dot not showing count == 0', () => {
const badge = mount(<Badge count={0} dot />);
expect(badge.find('.ant-badge-dot').length).toBe(0);
});
@@ -17,4 +26,40 @@ describe('Badge', () => {
const badge = mount(<Badge count={10} title="Custom title" />);
expect(badge.find('.ant-scroll-number').getDOMNode().attributes.getNamedItem('title').value).toEqual('Custom title');
});
// https://github.com/ant-design/ant-design/issues/10626
it('should be composable with Tooltip', () => {
const wrapper = mount(
<Tooltip title="Fix the error">
<Badge status="error" />
</Tooltip>
);
wrapper.find('Badge').simulate('mouseenter');
jest.runAllTimers();
expect(wrapper.instance().tooltip.props.visible).toBe(true);
});
it('should render when count is changed', () => {
const wrapper = mount(<Badge count={9} />);
wrapper.setProps({ count: 10 });
jest.runAllTimers();
expect(wrapper).toMatchSnapshot();
wrapper.setProps({ count: 11 });
jest.runAllTimers();
expect(wrapper).toMatchSnapshot();
wrapper.setProps({ count: 11 });
jest.runAllTimers();
expect(wrapper).toMatchSnapshot();
wrapper.setProps({ count: 10 });
jest.runAllTimers();
expect(wrapper).toMatchSnapshot();
jest.runAllTimers();
wrapper.setProps({ count: 9 });
expect(wrapper).toMatchSnapshot();
});
it('should be compatible with borderColor style', () => {
const wrapper = render(<Badge count={4} style={{ backgroundColor: '#fff', color: '#999', borderColor: '#d9d9d9' }} />);
expect(wrapper).toMatchSnapshot();
});
});

View File

@@ -59,7 +59,7 @@ export default class Badge extends React.Component<BadgeProps, any> {
text,
offset,
title,
...restProps,
...restProps
} = this.props;
let displayCount = (count as number) > (overflowCount as number) ? `${overflowCount}+` : count;
const isZero = displayCount === '0' || displayCount === 0;
@@ -92,7 +92,7 @@ export default class Badge extends React.Component<BadgeProps, any> {
// <Badge status="success" />
if (!children && status) {
return (
<span className={badgeCls} style={styleWithOffset}>
<span {...restProps} className={badgeCls} style={styleWithOffset}>
<span className={statusCls} />
<span className={`${prefixCls}-status-text`}>{text}</span>
</span>
@@ -107,6 +107,7 @@ export default class Badge extends React.Component<BadgeProps, any> {
count={displayCount}
title={title || count}
style={styleWithOffset}
key="scrollNumber"
/>
);

View File

@@ -0,0 +1,170 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`react router react router 3 1`] = `
<Breadcrumb
params={
Object {
"id": 1,
}
}
prefixCls="ant-breadcrumb"
routes={
Array [
Object {
"breadcrumbName": "Home",
"childRoutes": Array [
Object {
"breadcrumbName": "Application List",
"childRoutes": Array [
Object {
"breadcrumbName": "Application:id",
"childRoutes": Array [
Object {
"breadcrumbName": "Detail",
"name": "detail",
"path": "detail",
},
],
"name": "app",
"path": ":id",
},
],
"name": "apps",
"path": "apps",
},
],
"name": "home",
"path": "/",
},
Object {
"breadcrumbName": "Application List",
"childRoutes": Array [
Object {
"breadcrumbName": "Application:id",
"childRoutes": Array [
Object {
"breadcrumbName": "Detail",
"name": "detail",
"path": "detail",
},
],
"name": "app",
"path": ":id",
},
],
"name": "apps",
"path": "apps",
},
Object {
"breadcrumbName": "Application:id",
"childRoutes": Array [
Object {
"breadcrumbName": "Detail",
"name": "detail",
"path": "detail",
},
],
"name": "app",
"path": ":id",
},
Object {
"breadcrumbName": "Detail",
"name": "detail",
"path": "detail",
},
]
}
separator="/"
>
<div
className="ant-breadcrumb"
>
<BreadcrumbItem
key="Home"
prefixCls="ant-breadcrumb"
separator="/"
>
<span>
<span
className="ant-breadcrumb-link"
>
<a
href="#/"
>
Home
</a>
</span>
<span
className="ant-breadcrumb-separator"
>
/
</span>
</span>
</BreadcrumbItem>
<BreadcrumbItem
key="Application List"
prefixCls="ant-breadcrumb"
separator="/"
>
<span>
<span
className="ant-breadcrumb-link"
>
<a
href="#/apps"
>
Application List
</a>
</span>
<span
className="ant-breadcrumb-separator"
>
/
</span>
</span>
</BreadcrumbItem>
<BreadcrumbItem
key="Application:id"
prefixCls="ant-breadcrumb"
separator="/"
>
<span>
<span
className="ant-breadcrumb-link"
>
<a
href="#/apps/1"
>
Application1
</a>
</span>
<span
className="ant-breadcrumb-separator"
>
/
</span>
</span>
</BreadcrumbItem>
<BreadcrumbItem
key="Detail"
prefixCls="ant-breadcrumb"
separator="/"
>
<span>
<span
className="ant-breadcrumb-link"
>
<span>
Detail
</span>
</span>
<span
className="ant-breadcrumb-separator"
>
/
</span>
</span>
</BreadcrumbItem>
</div>
</Breadcrumb>
`;

View File

@@ -0,0 +1,150 @@
import React from 'react';
import { Route, Switch, Link, withRouter, MemoryRouter } from 'react-router-dom';
import { mount } from 'enzyme';
import Breadcrumb from '../index';
const Apps = () => (
<ul className="app-list">
<li>
<Link to="/apps/1">Application1</Link><Link to="/apps/1/detail">Detail</Link>
</li>
<li>
<Link to="/apps/2">Application2</Link><Link to="/apps/2/detail">Detail</Link>
</li>
</ul>
);
const breadcrumbNameMap = {
'/apps': 'Application List',
'/apps/1': 'Application1',
'/apps/2': 'Application2',
'/apps/1/detail': 'Detail',
'/apps/2/detail': 'Detail',
};
const Home = withRouter((props) => {
const { location, history } = props;
const pathSnippets = location.pathname.split('/').filter(i => i);
const extraBreadcrumbItems = pathSnippets.map((_, index) => {
const url = `/${pathSnippets.slice(0, index + 1).join('/')}`;
return (
<Breadcrumb.Item key={url}>
<Link to={url}>
{breadcrumbNameMap[url]}
</Link>
</Breadcrumb.Item>
);
});
const breadcrumbItems = [(
<Breadcrumb.Item key="home">
<Link to="/">Home</Link>
</Breadcrumb.Item>
)].concat(extraBreadcrumbItems);
return (
<div className="demo">
<div className="demo-nav">
<a onClick={() => history.push('/')}>Home</a>
<a onClick={() => history.push('/apps')}>Application List</a>
</div>
<Switch>
<Route path="/apps" component={Apps} />
<Route render={() => <span>Home Page</span>} />
</Switch>
<Breadcrumb>
{breadcrumbItems}
</Breadcrumb>
</div>
);
});
describe('react router', () => {
beforeAll(() => {
jest.useFakeTimers();
});
afterAll(() => {
jest.useRealTimers();
});
// https://github.com/airbnb/enzyme/issues/875
it('react router 4', () => {
const wrapper = mount(
<MemoryRouter initialEntries={['/']} initialIndex={0}>
<Home />
</MemoryRouter>
);
expect(wrapper.find('BreadcrumbItem').length).toBe(1);
expect(wrapper.find('BreadcrumbItem .ant-breadcrumb-link').at(0).text()).toBe('Home');
wrapper.find('.demo-nav a').at(1).simulate('click');
expect(wrapper.find('BreadcrumbItem').length).toBe(2);
expect(wrapper.find('BreadcrumbItem .ant-breadcrumb-link').at(1).text()).toBe('Application List');
});
it('react router 3', () => {
const routes = [{
name: 'home',
breadcrumbName: 'Home',
path: '/',
childRoutes: [
{
name: 'apps',
breadcrumbName: 'Application List',
path: 'apps',
childRoutes: [
{
name: 'app',
breadcrumbName: 'Application:id',
path: ':id',
childRoutes: [
{
name: 'detail',
breadcrumbName: 'Detail',
path: 'detail',
},
],
},
],
},
],
},
{
name: 'apps',
breadcrumbName: 'Application List',
path: 'apps',
childRoutes: [
{
name: 'app',
breadcrumbName: 'Application:id',
path: ':id',
childRoutes: [
{
name: 'detail',
breadcrumbName: 'Detail',
path: 'detail',
},
],
},
],
},
{
name: 'app',
breadcrumbName: 'Application:id',
path: ':id',
childRoutes: [
{
name: 'detail',
breadcrumbName: 'Detail',
path: 'detail',
},
],
},
{
name: 'detail',
breadcrumbName: 'Detail',
path: 'detail',
}];
const wrapper = mount(
<Breadcrumb routes={routes} params={{ id: 1 }} />
);
expect(wrapper).toMatchSnapshot();
});
});

View File

@@ -211,24 +211,6 @@ exports[`renders ./components/button/demo/disabled.md correctly 1`] = `
</span>
</button>
<br />
<button
class="ant-btn ant-btn-background-ghost"
type="button"
>
<span>
Ghost
</span>
</button>
<button
class="ant-btn ant-btn-background-ghost"
disabled=""
type="button"
>
<span>
Ghost(disabled)
</span>
</button>
<br />
<button
class="ant-btn ant-btn-dashed"
type="button"
@@ -246,6 +228,27 @@ exports[`renders ./components/button/demo/disabled.md correctly 1`] = `
Dashed(disabled)
</span>
</button>
<div
style="padding:8px 8px 0 8px;background:rgb(190, 200, 200)"
>
<button
class="ant-btn ant-btn-background-ghost"
type="button"
>
<span>
Ghost
</span>
</button>
<button
class="ant-btn ant-btn-background-ghost"
disabled=""
type="button"
>
<span>
Ghost(disabled)
</span>
</button>
</div>
</div>
`;

View File

@@ -4,7 +4,6 @@ import PropTypes from 'prop-types';
import classNames from 'classnames';
import omit from 'omit.js';
import Icon from '../icon';
import { Omit } from '../_util/type';
import Group from './button-group';
const rxTwoCNChar = /^[\u4e00-\u9fa5]{2}$/;
@@ -39,7 +38,7 @@ export type ButtonType = 'default' | 'primary' | 'ghost' | 'dashed' | 'danger';
export type ButtonShape = 'circle' | 'circle-outline';
export type ButtonSize = 'small' | 'default' | 'large';
export interface BaseButtonProps<T> extends Omit<React.HTMLProps<T>, 'ref' | 'size'> {
export interface BaseButtonProps {
type?: ButtonType;
htmlType?: string;
icon?: string;
@@ -51,11 +50,9 @@ export interface BaseButtonProps<T> extends Omit<React.HTMLProps<T>, 'ref' | 'si
ghost?: boolean;
}
export interface AnchorButtonProps extends BaseButtonProps<HTMLAnchorElement> {
href: string;
}
export type AnchorButtonProps = BaseButtonProps & React.AnchorHTMLAttributes<HTMLAnchorElement>;
export interface NativeButtonProps extends BaseButtonProps<HTMLButtonElement> {}
export type NativeButtonProps = BaseButtonProps & React.ButtonHTMLAttributes<HTMLButtonElement>;
export type ButtonProps = AnchorButtonProps | NativeButtonProps;
@@ -160,7 +157,7 @@ export default class Button extends React.Component<ButtonProps, any> {
render() {
const {
type, shape, size, className, htmlType, children, icon, prefixCls, ghost, ...others,
type, shape, size, className, htmlType, children, icon, prefixCls, ghost, ...others
} = this.props;
const { loading, clicked, hasTwoCNChar } = this.state;

View File

@@ -24,11 +24,12 @@ ReactDOM.render(
<Button>Default</Button>
<Button disabled>Default(disabled)</Button>
<br />
<Button ghost>Ghost</Button>
<Button ghost disabled>Ghost(disabled)</Button>
<br />
<Button type="dashed">Dashed</Button>
<Button type="dashed" disabled>Dashed(disabled)</Button>
<div style={{ padding: '8px 8px 0 8px', background: 'rgb(190, 200, 200)' }}>
<Button ghost>Ghost</Button>
<Button ghost disabled>Ghost(disabled)</Button>
</div>
</div>,
mountNode
);

View File

@@ -250,11 +250,16 @@
.@{btnClassName} + &,
span + .@{btnClassName},
.@{btnClassName} + span,
> span + span,
& + .@{btnClassName},
& + & {
margin-left: -1px;
}
.@{btnClassName}-primary + .@{btnClassName}:not(.@{btnClassName}-primary):not([disabled]) {
border-left-color: transparent;
}
.@{btnClassName}:not(:first-child):not(:last-child) {
border-radius: 0;
}

View File

@@ -236,7 +236,7 @@ exports[`renders ./components/calendar/demo/basic.md correctly 1`] = `
</div>
</td>
<td
class="ant-fullcalendar-cell ant-fullcalendar-last-month-cell"
class="ant-fullcalendar-cell ant-fullcalendar-last-month-cell ant-fullcalendar-last-day-of-month"
role="gridcell"
title="October 31, 2016"
>
@@ -796,7 +796,7 @@ exports[`renders ./components/calendar/demo/basic.md correctly 1`] = `
</div>
</td>
<td
class="ant-fullcalendar-cell"
class="ant-fullcalendar-cell ant-fullcalendar-last-day-of-month"
role="gridcell"
title="November 30, 2016"
>
@@ -1245,7 +1245,7 @@ exports[`renders ./components/calendar/demo/card.md correctly 1`] = `
</div>
</td>
<td
class="ant-fullcalendar-cell ant-fullcalendar-last-month-cell"
class="ant-fullcalendar-cell ant-fullcalendar-last-month-cell ant-fullcalendar-last-day-of-month"
role="gridcell"
title="October 31, 2016"
>
@@ -1805,7 +1805,7 @@ exports[`renders ./components/calendar/demo/card.md correctly 1`] = `
</div>
</td>
<td
class="ant-fullcalendar-cell"
class="ant-fullcalendar-cell ant-fullcalendar-last-day-of-month"
role="gridcell"
title="November 30, 2016"
>
@@ -2256,7 +2256,7 @@ exports[`renders ./components/calendar/demo/notice-calendar.md correctly 1`] = `
</div>
</td>
<td
class="ant-fullcalendar-cell ant-fullcalendar-last-month-cell"
class="ant-fullcalendar-cell ant-fullcalendar-last-month-cell ant-fullcalendar-last-day-of-month"
role="gridcell"
title="October 31, 2016"
>
@@ -3093,7 +3093,7 @@ exports[`renders ./components/calendar/demo/notice-calendar.md correctly 1`] = `
</div>
</td>
<td
class="ant-fullcalendar-cell"
class="ant-fullcalendar-cell ant-fullcalendar-last-day-of-month"
role="gridcell"
title="November 30, 2016"
>
@@ -4211,7 +4211,7 @@ exports[`renders ./components/calendar/demo/select.md correctly 1`] = `
</div>
</td>
<td
class="ant-fullcalendar-cell"
class="ant-fullcalendar-cell ant-fullcalendar-last-day-of-month"
role="gridcell"
title="January 31, 2017"
>

View File

@@ -235,7 +235,7 @@
}
&-fullscreen &-content {
height: 90px;
height: 88px;
overflow-y: auto;
position: static;
width: auto;

View File

@@ -134,7 +134,7 @@ export default class Card extends React.Component<CardProps, CardState> {
render() {
const {
prefixCls = 'ant-card', className, extra, bodyStyle = {}, noHovering, hoverable, title, loading,
bordered = true, type, cover, actions, tabList, children, activeTabKey, defaultActiveTabKey, ...others,
bordered = true, type, cover, actions, tabList, children, activeTabKey, defaultActiveTabKey, ...others
} = this.props;
const classString = classNames(prefixCls, className, {

View File

@@ -3,6 +3,14 @@ import { mount } from 'enzyme';
import Carousel from '..';
describe('Carousel', () => {
beforeAll(() => {
jest.useFakeTimers();
});
afterAll(() => {
jest.useRealTimers();
});
it('should has innerSlider', () => {
const wrapper = mount(<Carousel><div /></Carousel>);
const { innerSlider } = wrapper.instance();
@@ -10,4 +18,42 @@ describe('Carousel', () => {
expect(innerSlider).toBe(innerSliderFromRefs);
expect(typeof innerSlider.slickNext).toBe('function');
});
it('should has prev, next and go function', () => {
const wrapper = mount(<Carousel><div>1</div><div>2</div><div>3</div></Carousel>);
const { prev, next, goTo } = wrapper.instance();
expect(typeof prev).toBe('function');
expect(typeof next).toBe('function');
expect(typeof goTo).toBe('function');
expect(wrapper.instance().slick.innerSlider.state.currentSlide).toBe(0);
wrapper.instance().goTo(2);
jest.runAllTimers();
expect(wrapper.instance().slick.innerSlider.state.currentSlide).toBe(2);
wrapper.instance().prev();
jest.runAllTimers();
expect(wrapper.instance().slick.innerSlider.state.currentSlide).toBe(1);
wrapper.instance().next();
jest.runAllTimers();
expect(wrapper.instance().slick.innerSlider.state.currentSlide).toBe(2);
});
it('should trigger autoPlay after window resize', async () => {
jest.useRealTimers();
const wrapper = mount(<Carousel autoplay><div>1</div><div>2</div><div>3</div></Carousel>);
const spy = jest.spyOn(wrapper.instance().slick.innerSlider, 'autoPlay');
window.resizeTo(1000);
expect(spy).not.toBeCalled();
await new Promise(resolve => setTimeout(resolve, 500));
expect(spy).toBeCalled();
});
it('cancel resize listener when unmount', async () => {
const wrapper = mount(<Carousel autoplay><div>1</div><div>2</div><div>3</div></Carousel>);
const onWindowResized = wrapper.instance().onWindowResized;
const spy = jest.spyOn(wrapper.instance().onWindowResized, 'cancel');
const spy2 = jest.spyOn(window, 'removeEventListener');
wrapper.unmount();
expect(spy).toBeCalled();
expect(spy2).toBeCalledWith('resize', onWindowResized);
});
});

View File

@@ -211,7 +211,7 @@ exports[`renders ./components/cascader/demo/lazy.md correctly 1`] = `
exports[`renders ./components/cascader/demo/search.md correctly 1`] = `
<span
class="ant-cascader-picker"
class="ant-cascader-picker ant-cascader-picker-show-search"
tabindex="0"
>
<span

View File

@@ -215,6 +215,632 @@ exports[`Cascader popup correctly with defaultValue 1`] = `
</div>
`;
exports[`Cascader should highlight keyword and filter when search in Cascader 1`] = `
<Popup
action={
Array [
"click",
]
}
align={
Object {
"offset": Array [
0,
4,
],
"overflow": Object {
"adjustX": 1,
"adjustY": 1,
},
"points": Array [
"tl",
"bl",
],
}
}
className=""
destroyPopupOnHide={false}
getClassNameFromAlign={[Function]}
getRootDomNode={[Function]}
mask={false}
onAlign={[Function]}
prefixCls="ant-cascader-menus"
style={Object {}}
transitionName="slide-up"
visible={true}
>
<div>
<Animate
animation={Object {}}
component=""
componentProps={Object {}}
exclusive={true}
onAppear={[Function]}
onEnd={[Function]}
onEnter={[Function]}
onLeave={[Function]}
showProp="xVisible"
transitionAppear={true}
transitionEnter={true}
transitionLeave={true}
transitionName="slide-up"
>
<AnimateChild
animation={Object {}}
key="popup"
transitionAppear={true}
transitionEnter={true}
transitionLeave={true}
transitionName="slide-up"
>
<Align
align={
Object {
"offset": Array [
0,
4,
],
"overflow": Object {
"adjustX": 1,
"adjustY": 1,
},
"points": Array [
"tl",
"bl",
],
}
}
childrenProps={
Object {
"visible": "xVisible",
}
}
disabled={false}
key="popup"
monitorBufferTime={50}
monitorWindowResize={true}
onAlign={[Function]}
target={[Function]}
xVisible={true}
>
<PopupInner
className="ant-cascader-menus ant-cascader-menus-placement-bottomLeft "
hiddenClassName="ant-cascader-menus-hidden"
prefixCls="ant-cascader-menus"
style={Object {}}
visible={true}
>
<div
className="ant-cascader-menus ant-cascader-menus-placement-bottomLeft "
style={Object {}}
>
<LazyRenderBox
className="ant-cascader-menus-content"
visible={true}
>
<Menus
activeValue={Array []}
allowClear={true}
builtinPlacements={
Object {
"bottomLeft": Object {
"offset": Array [
0,
4,
],
"overflow": Object {
"adjustX": 1,
"adjustY": 1,
},
"points": Array [
"tl",
"bl",
],
},
"bottomRight": Object {
"offset": Array [
0,
4,
],
"overflow": Object {
"adjustX": 1,
"adjustY": 1,
},
"points": Array [
"tr",
"br",
],
},
"topLeft": Object {
"offset": Array [
0,
-4,
],
"overflow": Object {
"adjustX": 1,
"adjustY": 1,
},
"points": Array [
"bl",
"tl",
],
},
"topRight": Object {
"offset": Array [
0,
-4,
],
"overflow": Object {
"adjustX": 1,
"adjustY": 1,
},
"points": Array [
"br",
"tr",
],
},
}
}
defaultFiledNames={
Object {
"children": "children",
"label": "label",
"value": "value",
}
}
disabled={false}
dropdownMenuColumnStyle={
Object {
"width": 0,
}
}
expandTrigger="click"
filedNames={
Object {
"children": "children",
"label": "label",
"value": "value",
}
}
inputPrefixCls="ant-input"
notFoundContent="Not Found"
onChange={[Function]}
onPopupVisibleChange={[Function]}
onSelect={[Function]}
options={
Array [
Object {
"__IS_FILTERED_OPTION": true,
"disabled": false,
"label": Array [
"Jiangsu",
Array [
" / ",
"Nanjing",
],
Array [
" / ",
"Zhong Hua Men",
],
],
"path": Array [
Object {
"children": Array [
Object {
"children": Array [
Object {
"label": "Zhong Hua Men",
"value": "zhonghuamen",
},
],
"label": "Nanjing",
"value": "nanjing",
},
],
"label": "Jiangsu",
"value": "jiangsu",
},
Object {
"children": Array [
Object {
"label": "Zhong Hua Men",
"value": "zhonghuamen",
},
],
"label": "Nanjing",
"value": "nanjing",
},
Object {
"label": "Zhong Hua Men",
"value": "zhonghuamen",
},
],
"value": Array [
"jiangsu",
"nanjing",
"zhonghuamen",
],
},
Object {
"__IS_FILTERED_OPTION": true,
"disabled": false,
"label": Array [
"Zhejiang",
Array [
" / ",
Array [
"Hang",
Array [
<span
className="ant-cascader-menu-item-keyword"
>
z
</span>,
"hou",
],
],
],
Array [
" / ",
"West Lake",
],
],
"path": Array [
Object {
"children": Array [
Object {
"children": Array [
Object {
"label": "West Lake",
"value": "xihu",
},
],
"label": "Hangzhou",
"value": "hangzhou",
},
],
"label": "Zhejiang",
"value": "zhejiang",
},
Object {
"children": Array [
Object {
"label": "West Lake",
"value": "xihu",
},
],
"label": "Hangzhou",
"value": "hangzhou",
},
Object {
"label": "West Lake",
"value": "xihu",
},
],
"value": Array [
"zhejiang",
"hangzhou",
"xihu",
],
},
]
}
placeholder="Please select"
popupClassName=""
popupPlacement="bottomLeft"
popupVisible={true}
prefixCls="ant-cascader"
showSearch={
Object {
"filter": [Function],
}
}
transitionName="slide-up"
value={Array []}
visible={true}
>
<div>
<ul
className="ant-cascader-menu"
key="0"
style={
Object {
"width": 0,
}
}
>
<li
className="ant-cascader-menu-item"
key="jiangsu,nanjing,zhonghuamen"
onClick={[Function]}
title=""
>
Jiangsu
/
Nanjing
/
Zhong Hua Men
</li>
<li
className="ant-cascader-menu-item"
key="zhejiang,hangzhou,xihu"
onClick={[Function]}
title=""
>
Zhejiang
/
Hang
<span
className="ant-cascader-menu-item-keyword"
key="seperator"
>
z
</span>
hou
/
West Lake
</li>
</ul>
</div>
</Menus>
</LazyRenderBox>
</div>
</PopupInner>
</Align>
</AnimateChild>
</Animate>
</div>
</Popup>
`;
exports[`Cascader should render not found content 1`] = `
<Popup
action={
Array [
"click",
]
}
align={
Object {
"offset": Array [
0,
4,
],
"overflow": Object {
"adjustX": 1,
"adjustY": 1,
},
"points": Array [
"tl",
"bl",
],
}
}
className=""
destroyPopupOnHide={false}
getClassNameFromAlign={[Function]}
getRootDomNode={[Function]}
mask={false}
onAlign={[Function]}
prefixCls="ant-cascader-menus"
style={Object {}}
transitionName="slide-up"
visible={true}
>
<div>
<Animate
animation={Object {}}
component=""
componentProps={Object {}}
exclusive={true}
onAppear={[Function]}
onEnd={[Function]}
onEnter={[Function]}
onLeave={[Function]}
showProp="xVisible"
transitionAppear={true}
transitionEnter={true}
transitionLeave={true}
transitionName="slide-up"
>
<AnimateChild
animation={Object {}}
key="popup"
transitionAppear={true}
transitionEnter={true}
transitionLeave={true}
transitionName="slide-up"
>
<Align
align={
Object {
"offset": Array [
0,
4,
],
"overflow": Object {
"adjustX": 1,
"adjustY": 1,
},
"points": Array [
"tl",
"bl",
],
}
}
childrenProps={
Object {
"visible": "xVisible",
}
}
disabled={false}
key="popup"
monitorBufferTime={50}
monitorWindowResize={true}
onAlign={[Function]}
target={[Function]}
xVisible={true}
>
<PopupInner
className="ant-cascader-menus ant-cascader-menus-placement-bottomLeft "
hiddenClassName="ant-cascader-menus-hidden"
prefixCls="ant-cascader-menus"
style={Object {}}
visible={true}
>
<div
className="ant-cascader-menus ant-cascader-menus-placement-bottomLeft "
style={Object {}}
>
<LazyRenderBox
className="ant-cascader-menus-content"
visible={true}
>
<Menus
activeValue={Array []}
allowClear={true}
builtinPlacements={
Object {
"bottomLeft": Object {
"offset": Array [
0,
4,
],
"overflow": Object {
"adjustX": 1,
"adjustY": 1,
},
"points": Array [
"tl",
"bl",
],
},
"bottomRight": Object {
"offset": Array [
0,
4,
],
"overflow": Object {
"adjustX": 1,
"adjustY": 1,
},
"points": Array [
"tr",
"br",
],
},
"topLeft": Object {
"offset": Array [
0,
-4,
],
"overflow": Object {
"adjustX": 1,
"adjustY": 1,
},
"points": Array [
"bl",
"tl",
],
},
"topRight": Object {
"offset": Array [
0,
-4,
],
"overflow": Object {
"adjustX": 1,
"adjustY": 1,
},
"points": Array [
"br",
"tr",
],
},
}
}
defaultFiledNames={
Object {
"children": "children",
"label": "label",
"value": "value",
}
}
disabled={false}
dropdownMenuColumnStyle={
Object {
"height": "auto",
"width": 0,
}
}
expandTrigger="click"
filedNames={
Object {
"children": "children",
"label": "label",
"value": "value",
}
}
inputPrefixCls="ant-input"
notFoundContent="Not Found"
onChange={[Function]}
onPopupVisibleChange={[Function]}
onSelect={[Function]}
options={
Array [
Object {
"disabled": true,
"label": "Not Found",
"value": "ANT_CASCADER_NOT_FOUND",
},
]
}
placeholder="Please select"
popupClassName=""
popupPlacement="bottomLeft"
popupVisible={true}
prefixCls="ant-cascader"
showSearch={
Object {
"filter": [Function],
}
}
transitionName="slide-up"
value={Array []}
visible={true}
>
<div>
<ul
className="ant-cascader-menu"
key="0"
style={
Object {
"height": "auto",
"width": 0,
}
}
>
<li
className="ant-cascader-menu-item ant-cascader-menu-item-disabled"
key="ANT_CASCADER_NOT_FOUND"
onClick={[Function]}
title="Not Found"
>
Not Found
</li>
</ul>
</div>
</Menus>
</LazyRenderBox>
</div>
</PopupInner>
</Align>
</AnimateChild>
</Animate>
</div>
</Popup>
`;
exports[`Cascader support controlled mode 1`] = `
<span
class="ant-cascader-picker"

View File

@@ -28,6 +28,10 @@ const options = [{
}],
}];
function filter(inputValue, path) {
return path.some(option => (option.label).toLowerCase().indexOf(inputValue.toLowerCase()) > -1);
}
describe('Cascader', () => {
focusTest(Cascader);
@@ -39,11 +43,13 @@ describe('Cascader', () => {
});
it('popup correctly when panel is open', () => {
const onPopupVisibleChange = jest.fn();
const wrapper = mount(
<Cascader options={options} />
<Cascader options={options} onPopupVisibleChange={onPopupVisibleChange} />
);
wrapper.find('input').simulate('click');
expect(render(wrapper.find('Trigger').instance().getComponent())).toMatchSnapshot();
expect(onPopupVisibleChange).toHaveBeenCalledWith(true);
});
it('support controlled mode', () => {
@@ -64,8 +70,18 @@ describe('Cascader', () => {
expect(render(wrapper.find('Trigger').instance().getComponent())).toMatchSnapshot();
});
it('should support popupVisible', () => {
const wrapper = mount(
<Cascader options={options} defaultValue={['zhejiang', 'hangzhou']} />
);
expect(wrapper.find('Trigger').instance().getComponent().props.visible).toBe(false);
wrapper.setProps({ popupVisible: true });
expect(wrapper.find('Trigger').instance().getComponent().props.visible).toBe(true);
});
it('can be selected', () => {
const wrapper = mount(<Cascader options={options} />);
const onChange = jest.fn();
const wrapper = mount(<Cascader options={options} onChange={onChange} />);
wrapper.find('input').simulate('click');
let popupWrapper = mount(wrapper.find('Trigger').instance().getComponent());
popupWrapper.find('.ant-cascader-menu').at(0).find('.ant-cascader-menu-item').at(0)
@@ -79,6 +95,7 @@ describe('Cascader', () => {
popupWrapper.find('.ant-cascader-menu').at(2).find('.ant-cascader-menu-item').at(0)
.simulate('click');
expect(render(wrapper.find('Trigger').instance().getComponent())).toMatchSnapshot();
expect(onChange).toHaveBeenCalledWith(['zhejiang', 'hangzhou', 'xihu'], expect.anything());
});
it('backspace should work with `Cascader[showSearch]`', () => {
@@ -89,4 +106,88 @@ describe('Cascader', () => {
// Simulate onKeyDown will not trigger onChange by default, so the value is still '123'
expect(wrapper.state('inputValue')).toBe('123');
});
it('should highlight keyword and filter when search in Cascader', () => {
const wrapper = mount(<Cascader options={options} showSearch={{ filter }} />);
wrapper.find('input').simulate('click');
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();
});
it('should render not found content', () => {
const wrapper = mount(<Cascader options={options} showSearch={{ filter }} />);
wrapper.find('input').simulate('click');
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();
});
it('should support to clear selection', () => {
const wrapper = mount(<Cascader options={options} defaultValue={['zhejiang', 'hangzhou']} />);
expect(wrapper.find('.ant-cascader-picker-label').text()).toBe('Zhejiang / Hangzhou');
wrapper.find('.ant-cascader-picker-clear').at(0).simulate('click');
expect(wrapper.find('.ant-cascader-picker-label').text()).toBe('');
});
it('should close popup when clear selection', () => {
const onPopupVisibleChange = jest.fn();
const wrapper = mount(
<Cascader
options={options}
popupVisible
defaultValue={['zhejiang', 'hangzhou']}
onPopupVisibleChange={onPopupVisibleChange}
/>
);
wrapper.find('.ant-cascader-picker-clear').at(0).simulate('click');
expect(onPopupVisibleChange).toHaveBeenCalledWith(false);
});
it('should clear search input when clear selection', () => {
const wrapper = mount(
<Cascader
options={options}
defaultValue={['zhejiang', 'hangzhou']}
showSearch
/>
);
wrapper.find('input').simulate('click');
wrapper.find('input').simulate('change', { target: { value: 'xxx' } });
expect(wrapper.state('inputValue')).toBe('xxx');
wrapper.find('.ant-cascader-picker-clear').at(0).simulate('click');
expect(wrapper.state('inputValue')).toBe('');
});
it('should not trigger visible change when click search input', () => {
const onPopupVisibleChange = jest.fn();
const wrapper = mount(
<Cascader
options={options}
showSearch
onPopupVisibleChange={onPopupVisibleChange}
/>
);
wrapper.find('input').simulate('focus');
expect(onPopupVisibleChange).toHaveBeenCalledTimes(0);
wrapper.find('input').simulate('click');
expect(onPopupVisibleChange).toHaveBeenCalledTimes(1);
wrapper.find('input').simulate('click');
expect(onPopupVisibleChange).toHaveBeenCalledTimes(1);
wrapper.find('input').simulate('blur');
wrapper.setState({ popupVisible: false });
wrapper.find('input').simulate('click');
expect(onPopupVisibleChange).toHaveBeenCalledTimes(2);
});
it('should change filtered item when options are changed', () => {
const wrapper = mount(<Cascader options={options} showSearch={{ filter }} />);
wrapper.find('input').simulate('click');
wrapper.find('input').simulate('change', { target: { value: 'a' } });
expect(wrapper.find('.ant-cascader-menu-item').length).toBe(2);
wrapper.setProps({ options: [options[0]] });
expect(wrapper.find('.ant-cascader-menu-item').length).toBe(1);
});
});

View File

@@ -12,7 +12,6 @@ export interface CascaderOptionType {
label?: React.ReactNode;
disabled?: boolean;
children?: Array<CascaderOptionType>;
__IS_FILTERED_OPTION?: boolean;
[key: string]: any;
}
@@ -90,7 +89,7 @@ export interface CascaderState {
inputValue: string;
value: string[];
popupVisible: boolean | undefined;
flattenOptions: CascaderOptionType[][];
flattenOptions: CascaderOptionType[][] | undefined;
}
function highlightKeyword(str: string, keyword: string, prefixCls: string | undefined) {
@@ -119,7 +118,9 @@ function defaultRenderFilteredOption(
});
}
function defaultSortFilteredOption(a: any[], b: any[], inputValue: string, names: FilledFiledNamesType) {
function defaultSortFilteredOption(
a: CascaderOptionType[], b: CascaderOptionType[], inputValue: string, names: FilledFiledNamesType,
) {
function callback(elem: CascaderOptionType) {
return (elem[names.label] as string).indexOf(inputValue) > -1;
}
@@ -162,7 +163,8 @@ export default class Cascader extends React.Component<CascaderProps, CascaderSta
inputValue: '',
inputFocused: false,
popupVisible: props.popupVisible,
flattenOptions: props.showSearch && this.flattenTree(props.options, props.changeOnSelect, props.filedNames),
flattenOptions:
props.showSearch ? this.flattenTree(props.options, props.changeOnSelect, props.filedNames) : undefined,
};
}
@@ -180,7 +182,7 @@ export default class Cascader extends React.Component<CascaderProps, CascaderSta
}
}
handleChange = (value: any, selectedOptions: any[]) => {
handleChange = (value: any, selectedOptions: CascaderOptionType[]) => {
this.setState({ inputValue: '' });
if (selectedOptions[0].__IS_FILTERED_OPTION) {
const unwrappedValue = value[0];
@@ -217,7 +219,9 @@ export default class Cascader extends React.Component<CascaderProps, CascaderSta
// Prevent `Trigger` behaviour.
if (inputFocused || popupVisible) {
e.stopPropagation();
e.nativeEvent.stopImmediatePropagation();
if (e.nativeEvent.stopImmediatePropagation) {
e.nativeEvent.stopImmediatePropagation();
}
}
}
@@ -232,7 +236,7 @@ export default class Cascader extends React.Component<CascaderProps, CascaderSta
this.setState({ inputValue });
}
setValue = (value: string[], selectedOptions: any[] = []) => {
setValue = (value: string[], selectedOptions: CascaderOptionType[] = []) => {
if (!('value' in this.props)) {
this.setState({ value });
}
@@ -271,9 +275,9 @@ export default class Cascader extends React.Component<CascaderProps, CascaderSta
filedNames: FiledNamesType | undefined,
ancestor: CascaderOptionType[] = [],
) {
const names: FiledNamesType = getFilledFieldNames(filedNames);
let flattenOptions: any = [];
let childrenName: any = names.children;
const names: FilledFiledNamesType = getFilledFieldNames(filedNames);
let flattenOptions = [] as CascaderOptionType[][];
let childrenName = names.children;
options.forEach((option) => {
const path = ancestor.concat(option);
if (changeOnSelect || !option[childrenName] || !option[childrenName].length) {
@@ -301,18 +305,18 @@ export default class Cascader extends React.Component<CascaderProps, CascaderSta
render = defaultRenderFilteredOption,
sort = defaultSortFilteredOption,
} = showSearch as ShowSearchType;
const { flattenOptions, inputValue } = this.state;
const { flattenOptions = [], inputValue } = this.state;
const filtered = flattenOptions.filter((path) => filter(this.state.inputValue, path, names))
.sort((a, b) => sort(a, b, inputValue, names));
if (filtered.length > 0) {
return filtered.map((path: any) => {
return filtered.map((path: CascaderOptionType[]) => {
return {
__IS_FILTERED_OPTION: true,
path,
[names.label]: render(inputValue, path, prefixCls, names),
[names.value]: path.map((o: CascaderOptionType) => o[names.value]),
disabled: path.some((o: CascaderOptionType) => o.disabled),
disabled: path.some((o: CascaderOptionType) => !!o.disabled),
} as CascaderOptionType;
});
}
@@ -335,7 +339,7 @@ export default class Cascader extends React.Component<CascaderProps, CascaderSta
const { props, state } = this;
const {
prefixCls, inputPrefixCls, children, placeholder, size, disabled,
className, style, allowClear, showSearch = false, ...otherProps,
className, style, allowClear, showSearch = false, ...otherProps
} = props;
const value = state.value;
@@ -359,6 +363,7 @@ export default class Cascader extends React.Component<CascaderProps, CascaderSta
[`${prefixCls}-picker-with-value`]: state.inputValue,
[`${prefixCls}-picker-disabled`]: disabled,
[`${prefixCls}-picker-${size}`]: !!size,
[`${prefixCls}-picker-show-search`]: !!showSearch,
});
// Fix bug of https://github.com/facebook/react/pull/5004

View File

@@ -17,6 +17,10 @@
position: static;
}
&-picker-show-search &-input.@{ant-prefix}-input {
position: relative;
}
&-picker {
.reset-component;
position: relative;

View File

@@ -79,7 +79,7 @@ export default class Checkbox extends React.Component<CheckboxProps, {}> {
style,
onMouseEnter,
onMouseLeave,
...restProps,
...restProps
} = props;
const { checkboxGroup } = context;
let checkboxProps: CheckboxProps = { ...restProps };

View File

@@ -4,7 +4,7 @@ import classNames from 'classnames';
import shallowEqual from 'shallowequal';
import Checkbox from './Checkbox';
export type CheckboxValueType = string | number;
export type CheckboxValueType = string | number | boolean;
export interface CheckboxOptionType {
label: string;
@@ -121,7 +121,7 @@ export default class CheckboxGroup extends React.Component<CheckboxGroupProps, C
children = this.getOptions().map(option => (
<Checkbox
prefixCls={prefixCls}
key={option.value}
key={option.value.toString()}
disabled={'disabled' in option ? option.disabled : props.disabled}
value={option.value}
checked={state.value.indexOf(option.value) !== -1}

View File

@@ -13,7 +13,9 @@ Checkbox.
## API
### Checkbox
### Props
#### Checkbox
| Property | Description | Type | Default |
| -------- | ----------- | ---- | ------- |
@@ -21,9 +23,10 @@ Checkbox.
| checked | Specifies whether the checkbox is selected. | boolean | false |
| defaultChecked | Specifies the initial state: whether or not the checkbox is selected. | boolean | false |
| disabled | Disable checkbox | boolean | false |
| indeterminate | indeterminate checked state of checkbox | boolean | false |
| onChange | The callback function that is triggered when the state changes. | Function(e:Event) | - |
### Checkbox Group
#### Checkbox Group
| Property | Description | Type | Default |
| -------- | ----------- | ---- | ------- |
@@ -33,11 +36,11 @@ Checkbox.
| value | Used for setting the currently selected value. | string\[] | \[] |
| onChange | The callback function that is triggered when the state changes. | Function(checkedValue) | - |
## Methods
### Methods
### Checkbox
#### Checkbox
| Name | Description |
| ---- | ----------- |
| blur() | remove focus |
| focus() | get focus |
| blur() | remove focus |

View File

@@ -14,30 +14,34 @@ title: Checkbox
## API
### Checkbox
### 属性
#### Checkbox
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| autoFocus | 自动获取焦点 | boolean | false |
| checked | 指定当前是否选中 | boolean | false |
| defaultChecked | 初始是否选中 | boolean | false |
| disabled | 失效状态 | boolean | false |
| indeterminate | 设置 indeterminate 状态,只负责样式控制 | boolean | false |
| onChange | 变化时回调函数 | Function(e:Event) | - |
### Checkbox Group
#### Checkbox Group
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| defaultValue | 默认选中的选项 | string\[] | \[] |
| disabled | 整组失效 | boolean | false |
| options | 指定可选项 | string\[] | \[] |
| value | 指定选中的选项 | string\[] | \[] |
| onChange | 变化时回调函数 | Function(checkedValue) | - |
## 方法
### 方法
### Checkbox
#### Checkbox
| 名称 | 描述 |
| --- | --- |
| blur() | 移除焦点 |
| focus() | 获取焦点 |
| blur() | 移除焦点 |

View File

@@ -72,6 +72,7 @@
&-input {
position: absolute;
left: 0;
z-index: 1;
cursor: pointer;
opacity: 0;
top: 0;

View File

@@ -261,7 +261,7 @@ exports[`DatePicker prop locale should works 1`] = `
</div>
</td>
<td
class="ant-calendar-cell ant-calendar-last-month-cell"
class="ant-calendar-cell ant-calendar-last-month-cell ant-calendar-last-day-of-month"
role="gridcell"
title="December 31, 1999"
>
@@ -689,7 +689,7 @@ exports[`DatePicker prop locale should works 1`] = `
</div>
</td>
<td
class="ant-calendar-cell"
class="ant-calendar-cell ant-calendar-last-day-of-month"
role="gridcell"
title="January 31, 2000"
>

View File

@@ -221,7 +221,7 @@ exports[`RangePicker show month panel according to value 1`] = `
</div>
</td>
<td
class="ant-calendar-cell ant-calendar-last-month-cell"
class="ant-calendar-cell ant-calendar-last-month-cell ant-calendar-last-day-of-month"
role="gridcell"
title="1999年12月31日"
>
@@ -649,7 +649,7 @@ exports[`RangePicker show month panel according to value 1`] = `
role="row"
>
<td
class="ant-calendar-cell"
class="ant-calendar-cell ant-calendar-last-day-of-month"
role="gridcell"
title="2000年1月31日"
>
@@ -902,7 +902,7 @@ exports[`RangePicker show month panel according to value 1`] = `
role="row"
>
<td
class="ant-calendar-cell ant-calendar-last-month-cell"
class="ant-calendar-cell ant-calendar-last-month-cell ant-calendar-last-day-of-month"
role="gridcell"
title="2000年1月31日"
>
@@ -1299,7 +1299,7 @@ exports[`RangePicker show month panel according to value 1`] = `
</div>
</td>
<td
class="ant-calendar-cell"
class="ant-calendar-cell ant-calendar-last-day-of-month"
role="gridcell"
title="2000年2月29日"
>
@@ -1489,7 +1489,7 @@ exports[`RangePicker show month panel according to value 1`] = `
class="ant-calendar-time-picker-btn"
role="button"
>
Select time
select time
</a>
<a
class="ant-calendar-ok-btn"
@@ -1726,7 +1726,7 @@ exports[`RangePicker switch to corresponding month panel when click presetted ra
</div>
</td>
<td
class="ant-calendar-cell ant-calendar-last-month-cell"
class="ant-calendar-cell ant-calendar-last-month-cell ant-calendar-last-day-of-month"
role="gridcell"
title="1999年12月31日"
>
@@ -2154,7 +2154,7 @@ exports[`RangePicker switch to corresponding month panel when click presetted ra
role="row"
>
<td
class="ant-calendar-cell"
class="ant-calendar-cell ant-calendar-last-day-of-month"
role="gridcell"
title="2000年1月31日"
>
@@ -2407,7 +2407,7 @@ exports[`RangePicker switch to corresponding month panel when click presetted ra
role="row"
>
<td
class="ant-calendar-cell ant-calendar-last-month-cell"
class="ant-calendar-cell ant-calendar-last-month-cell ant-calendar-last-day-of-month"
role="gridcell"
title="2000年1月31日"
>
@@ -2804,7 +2804,7 @@ exports[`RangePicker switch to corresponding month panel when click presetted ra
</div>
</td>
<td
class="ant-calendar-cell"
class="ant-calendar-cell ant-calendar-last-day-of-month"
role="gridcell"
title="2000年2月29日"
>
@@ -3001,7 +3001,7 @@ exports[`RangePicker switch to corresponding month panel when click presetted ra
class="ant-calendar-time-picker-btn"
role="button"
>
Select time
select time
</a>
<a
class="ant-calendar-ok-btn"

View File

@@ -482,7 +482,7 @@ exports[`MonthPicker and WeekPicker render WeekPicker 1`] = `
</div>
</td>
<td
class="ant-calendar-cell ant-calendar-last-month-cell"
class="ant-calendar-cell ant-calendar-last-month-cell ant-calendar-last-day-of-month"
role="gridcell"
title="1999年12月31日"
>
@@ -886,7 +886,7 @@ exports[`MonthPicker and WeekPicker render WeekPicker 1`] = `
5
</td>
<td
class="ant-calendar-cell"
class="ant-calendar-cell ant-calendar-last-day-of-month"
role="gridcell"
title="2000年1月31日"
>

View File

@@ -19,13 +19,25 @@ There are four kinds of picker:
- RangePicker
- WeekPicker
### Localization
The default locale is en-US, if you need to use other languages, recommend to use internationalized components provided by us at the entrance. Look at: [LocaleProvider](http://ant.design/components/locale-provider/).
If there are special needs (only modifying single component language), Please use the property: local. Example: [default](https://github.com/ant-design/ant-design/blob/master/components/date-picker/locale/example.json).
```jsx
import locale from 'antd/lib/date-picker/locale/zh_CN';
<DatePicker locale={locale} />
```
**Note:** Part of locale of DatePicker, MonthPicker, RangePicker, WeekPicker is read from value. So, please set the locale of moment correctly.
```jsx
// The default locale is en-US, if you want to use other locale, just set locale in entry file globaly.
// import moment from 'moment';
// import 'moment/locale/zh-cn';
// moment.locale('zh-cn');
import moment from 'moment';
import 'moment/src/locale/zh-cn';
// import 'moment/locale/zh-cn'; if you are using webpack 1
<DatePicker defaultValue={moment('2015-01-01', 'YYYY-MM-DD')} />
```

View File

@@ -20,13 +20,25 @@ subtitle: 日期选择框
- RangePicker
- WeekPicker
### 国际化配置
默认配置为 en-US如果你需要设置其他语言推荐在入口处使用我们提供的国际化组件,详见:[LocaleProvider国际化](http://ant.design/components/locale-provider-cn/)。
如有特殊需求(仅修改单一组件的语言),请使用 locale 参数,参考:[默认配置](https://github.com/ant-design/ant-design/blob/master/components/date-picker/locale/example.json)。
```jsx
import locale from 'antd/lib/date-picker/locale/zh_CN';
<DatePicker locale={locale} />
```
**注意:**DatePicker、MonthPicker、RangePicker、WeekPicker 部分 locale 是从 value 中读取,所以请先正确设置 moment 的 locale。
```jsx
// 默认语言为 en-US如果你需要设置其他语言推荐在入口文件全局设置 locale
// import moment from 'moment';
// import 'moment/locale/zh-cn';
// moment.locale('zh-cn');
import moment from 'moment';
import 'moment/src/locale/zh-cn';
// import 'moment/locale/zh-cn'; if you are using webpack 1
<DatePicker defaultValue={moment('2015-01-01', 'YYYY-MM-DD')} />
```

View File

@@ -18,6 +18,8 @@ A divider line separates different content.
| Property | Description | Type | Default |
| -------- | ----------- | ---- | ------- |
| dashed | whether line is dashed | Boolean | false |
| dashed | whether line is dashed | boolean | false |
| type | direction type of divider | enum: `horizontal` `vertical` | `horizontal` |
| orientation | position of title inside divider | enum: `left` `right` `center` | `center` |
| className | className of container | string | - |
| style | style object of container | object | - |

View File

@@ -18,7 +18,7 @@ export default function Divider({
className,
children,
dashed,
...restProps,
...restProps
}: DividerProps) {
const orientationPrefix = (orientation.length > 0) ? '-' + orientation : orientation;
const classString = classNames(

View File

@@ -16,6 +16,8 @@ subtitle: 分割线
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| dashed | 是否虚线 | Boolean | false |
| dashed | 是否虚线 | boolean | false |
| type | 水平还是垂直类型 | enum: `horizontal` `vertical` | `horizontal` |
| orientation | 分割线标题的位置 | enum: `left` `right` | `center` |
| className | 分割线样式类 | string | - |
| style | 分割线样式对象 | object | - |

View File

@@ -24,7 +24,10 @@
margin: 24px 0;
clear: both;
}
&-horizontal&-with-text {
&-horizontal&-with-text,
&-horizontal&-with-text-left,
&-horizontal&-with-text-right {
display: table;
white-space: nowrap;
text-align: center;
@@ -33,7 +36,6 @@
color: @heading-color;
font-size: @font-size-lg;
margin: 16px 0;
&:before,
&:after {
content: '';
@@ -45,77 +47,43 @@
transform: translateY(50%);
}
}
&-inner-text {
display: inline-block;
padding: 0 24px;
}
&-horizontal&-with-text-left {
display: table;
white-space: nowrap;
text-align: center;
background: transparent;
font-weight: 500;
color: @heading-color;
font-size: @font-size-base;
margin: 16px 0;
&:before {
content: '';
display: table-cell;
position: relative;
top: 50%;
width: 5%;
border-top: 1px solid @border-color-split;
transform: translateY(50%);
}
&:after {
content: '';
display: table-cell;
position: relative;
top: 50%;
width: 95%;
border-top: 1px solid @border-color-split;
transform: translateY(50%);
}
&-inner-text {
&-horizontal&-with-text-left,
&-horizontal&-with-text-right {
font-size: @font-size-base;
.@{divider-prefix-cls}-inner-text {
display: inline-block;
padding: 0 10px;
}
}
&-horizontal&-with-text-left {
&:before {
top: 50%;
width: 5%;
}
&:after {
top: 50%;
width: 95%;
}
}
&-horizontal&-with-text-right {
display: table;
white-space: nowrap;
text-align: center;
background: transparent;
font-weight: 500;
color: @heading-color;
font-size: @font-size-base;
margin: 16px 0;
&:before {
content: '';
display: table-cell;
position: relative;
top: 50%;
width: 95%;
border-top: 1px solid @border-color-split;
transform: translateY(50%);
}
&:after {
content: '';
display: table-cell;
position: relative;
top: 50%;
width: 5%;
border-top: 1px solid @border-color-split;
transform: translateY(50%);
}
&-inner-text {
display: inline-block;
padding: 0 10px;
}
}
&-inner-text {
display: inline-block;
padding: 0 24px;
}
&-dashed {
background: none;
border-top: 1px dashed @border-color-split;

View File

@@ -24,7 +24,7 @@ export default class DropdownButton extends React.Component<DropdownButtonProps,
type, disabled, onClick, children,
prefixCls, className, overlay, trigger, align,
visible, onVisibleChange, placement, getPopupContainer,
...restProps,
...restProps
} = this.props;
const dropdownProps = {
@@ -35,9 +35,9 @@ export default class DropdownButton extends React.Component<DropdownButtonProps,
onVisibleChange,
placement,
getPopupContainer,
};
} as DropDownProps;
if ('visible' in this.props) {
(dropdownProps as any).visible = visible;
dropdownProps.visible = visible;
}
return (

View File

@@ -41,11 +41,13 @@ export default class Dropdown extends React.Component<DropDownProps, any> {
componentDidMount() {
const { overlay } = this.props;
const overlayProps = (overlay as any).props as any;
warning(
!overlayProps.mode || overlayProps.mode === 'vertical',
`mode="${overlayProps.mode}" is not supported for Dropdown\'s Menu.`,
);
if (overlay) {
const overlayProps = (overlay as React.ReactElement<any>).props;
warning(
!overlayProps.mode || overlayProps.mode === 'vertical',
`mode="${overlayProps.mode}" is not supported for Dropdown\'s Menu.`,
);
}
}
render() {

View File

@@ -38,7 +38,7 @@
outline: none;
position: relative;
list-style-type: none;
padding: 0;
padding: 4px 0;
margin: 0;
text-align: left;
background-color: @component-background;
@@ -102,26 +102,12 @@
}
}
&:first-child,
&:first-child > a {
border-radius: @border-radius-base @border-radius-base 0 0;
}
&:last-child,
&:last-child > a {
border-radius: 0 0 @border-radius-base @border-radius-base;
}
&:only-child,
&:only-child > a {
border-radius: @border-radius-base;
}
&-divider {
height: 1px;
overflow: hidden;
background-color: @border-color-split;
line-height: 0;
margin: 4px 0;
}
.@{dropdown-prefix-cls}-menu-submenu-arrow {
position: absolute;
@@ -138,10 +124,6 @@
&-submenu-title {
padding-right: 26px;
&:first-child,
&:last-child {
border-radius: 0;
}
}
&-submenu-vertical {
@@ -163,13 +145,6 @@
color: @disabled-color;
}
}
&-submenu:first-child &-submenu-title {
border-radius: @border-radius-base @border-radius-base 0 0;
}
&-submenu:last-child &-submenu-title {
border-radius: 0 0 @border-radius-base @border-radius-base;
}
}
&.slide-down-enter.slide-down-enter-active&-placement-bottomLeft,

View File

@@ -18,7 +18,7 @@ export interface FormCreateOption<T> {
export type FormLayout = 'horizontal' | 'inline' | 'vertical';
export interface FormProps {
export interface FormProps extends React.FormHTMLAttributes<HTMLFormElement> {
layout?: FormLayout;
form?: WrappedFormUtils;
onSubmit?: React.FormEventHandler<any>;

View File

@@ -2,6 +2,7 @@ import * as React from 'react';
import * as ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import intersperse from 'intersperse';
import Animate from 'rc-animate';
import Row from '../grid/row';
import Col, { ColProps } from '../grid/col';
@@ -65,15 +66,20 @@ export default class FormItem extends React.Component<FormItemProps, any> {
);
}
getHelpMsg() {
const props = this.props;
const onlyControl = this.getOnlyControl();
if (props.help === undefined && onlyControl) {
getHelpMessage() {
const { help } = this.props;
if (help === undefined && this.getOnlyControl()) {
const errors = this.getField().errors;
return errors ? errors.map((e: any) => e.message).join(', ') : '';
if (errors) {
return intersperse(errors.map((e: any, index: number) => (
React.isValidElement(e.message)
? React.cloneElement(e.message, { key: index })
: e.message
)), ' ');
}
return '';
}
return props.help;
return help;
}
getControls(children: React.ReactNode, recursively: boolean) {
@@ -132,7 +138,7 @@ export default class FormItem extends React.Component<FormItemProps, any> {
renderHelp() {
const prefixCls = this.props.prefixCls;
const help = this.getHelpMsg();
const help = this.getHelpMessage();
const children = help ? (
<div className={`${prefixCls}-explain`} key="help">
{help}

View File

@@ -0,0 +1,100 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Form should display custom message 1`] = `
<form
class="ant-form ant-form-horizontal"
>
<div
class="ant-row ant-form-item ant-form-item-with-help"
>
<div
class="ant-form-item-label"
>
<label
class=""
for="account"
title="Account"
>
Account
</label>
</div>
<div
class="ant-form-item-control-wrapper"
>
<div
class="ant-form-item-control has-error"
>
<span
class="ant-form-item-children"
>
<input
data-__field="[object Object]"
data-__meta="[object Object]"
id="account"
value="antd"
/>
</span>
<div
class="ant-form-explain show-help-enter"
>
<span>
Account does not exist,
<a
href="https://www.alipay.com/"
rel="noopener noreferrer"
target="_blank"
>
Forgot account?
</a>
</span>
</div>
</div>
</div>
</div>
</form>
`;
exports[`Form should display two message 1`] = `
<form
class="ant-form ant-form-horizontal"
>
<div
class="ant-row ant-form-item ant-form-item-with-help"
>
<div
class="ant-form-item-label"
>
<label
class=""
for="account"
title="Account"
>
Account
</label>
</div>
<div
class="ant-form-item-control-wrapper"
>
<div
class="ant-form-item-control has-error"
>
<span
class="ant-form-item-children"
>
<input
data-__field="[object Object]"
data-__meta="[object Object]"
id="account"
value="+=-/"
/>
</span>
<div
class="ant-form-explain show-help-enter"
>
Error message 1 Error message 2
</div>
</div>
</div>
</div>
</form>
`;

View File

@@ -0,0 +1,56 @@
import React from 'react';
import { mount } from 'enzyme';
import Form from '..';
describe('Form', () => {
it('should display two message', () => {
const rules = [{
pattern: /^\w+$/,
message: 'Error message 1',
}, {
pattern: /^\w+$/,
message: 'Error message 2',
}];
let myForm;
const Form1 = Form.create()(({ form }) => {
myForm = form;
return (
<Form>
<Form.Item label="Account">
{form.getFieldDecorator('account', { initialValue: '+=-/', rules })(<input />)}
</Form.Item>
</Form>
);
});
const wrapper = mount(<Form1 />);
myForm.validateFields();
wrapper.update();
expect(wrapper.render()).toMatchSnapshot();
});
it('should display custom message', () => {
const rules = [{
pattern: /^$/,
message: (<span>Account does not exist, <a rel="noopener noreferrer" href="https://www.alipay.com/" target="_blank">Forgot account?</a></span>),
}];
let myForm;
const Form1 = Form.create()(({ form }) => {
myForm = form;
return (
<Form>
<Form.Item label="Account">
{form.getFieldDecorator('account', { initialValue: 'antd', rules })(<input />)}
</Form.Item>
</Form>
);
});
const wrapper = mount(<Form1 />);
myForm.validateFields();
wrapper.update();
expect(wrapper.render()).toMatchSnapshot();
});
});

View File

@@ -147,7 +147,7 @@ Note:
| enum | validate a value from a list of possible values | string | - |
| len | validate an exact length of a field | number | - |
| max | validate a max length of a field | number | - |
| message | validation error message | string | - |
| message | validation error message | string\|ReactNode | - |
| min | validate a min length of a field | number | - |
| pattern | validate from a regular expression | RegExp | - |
| required | indicates whether field is required | boolean | `false` |

View File

@@ -148,7 +148,7 @@ CustomizedForm = Form.create({})(CustomizedForm);
| enum | 枚举类型 | string | - |
| len | 字段长度 | number | - |
| max | 最大长度 | number | - |
| message | 校验文案 | string | - |
| message | 校验文案 | string\|ReactNode | - |
| min | 最小长度 | number | - |
| pattern | 正则表达式校验 | RegExp | - |
| required | 是否必选 | boolean | `false` |

View File

@@ -22,17 +22,10 @@ import classNames from 'classnames';
import PropTypes from 'prop-types';
export type Breakpoint = 'xxl' | 'xl' | 'lg' | 'md' | 'sm' | 'xs';
export type BreakpointMap = {
xs?: string;
sm?: string;
md?: string;
lg?: string;
xl?: string;
xxl?: string
};
export type BreakpointMap = Partial<Record<Breakpoint, string>>;
export interface RowProps extends React.HTMLAttributes<HTMLDivElement> {
gutter?: number | BreakpointMap;
gutter?: number | Partial<Record<Breakpoint, number>>;
type?: 'flex';
align?: 'top' | 'middle' | 'bottom';
justify?: 'start' | 'end' | 'center' | 'space-around' | 'space-between';
@@ -122,7 +115,7 @@ export default class Row extends React.Component<RowProps, RowState> {
render() {
const {
type, justify, align, className, style, children,
prefixCls = 'ant-row', ...others,
prefixCls = 'ant-row', ...others
} = this.props;
const gutter = this.getGutter();
const classes = classNames({

View File

@@ -2,6 +2,7 @@
// this file is not used if use https://github.com/ant-design/babel-plugin-import
const ENV = process.env.NODE_ENV;
if (ENV !== 'production' &&
ENV !== 'test' &&
typeof console !== 'undefined' &&
console.warn &&
typeof window !== 'undefined') {

View File

@@ -2,7 +2,12 @@ import * as React from 'react';
import classNames from 'classnames';
import RcInputNumber from 'rc-input-number';
export interface InputNumberProps {
import { Omit } from '../_util/type';
// omitting this attrs because they conflicts with the ones defined in InputNumberProps
export type OmitAttrs = 'defaultValue' | 'onChange' | 'size';
export interface InputNumberProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, OmitAttrs> {
prefixCls?: string;
min?: number;
max?: number;
@@ -10,7 +15,6 @@ export interface InputNumberProps {
step?: number | string;
defaultValue?: number;
tabIndex?: number;
onKeyDown?: React.FormEventHandler<any>;
onChange?: (value: number | string | undefined) => void;
disabled?: boolean;
size?: 'large' | 'small' | 'default';

View File

@@ -5,46 +5,23 @@ import omit from 'omit.js';
import Group from './Group';
import Search from './Search';
import TextArea from './TextArea';
import { Omit } from '../_util/type';
function fixControlledValue(value: undefined | null | string) {
function fixControlledValue<T>(value: T) {
if (typeof value === 'undefined' || value === null) {
return '';
}
return value;
}
export interface AbstractInputProps {
export interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size' | 'prefix'> {
prefixCls?: string;
className?: string;
defaultValue?: any;
value?: any;
tabIndex?: number;
style?: React.CSSProperties;
}
export interface InputProps extends AbstractInputProps {
placeholder?: string;
type?: string;
id?: number | string;
name?: string;
size?: 'large' | 'default' | 'small';
maxLength?: number | string;
disabled?: boolean;
readOnly?: boolean;
onPressEnter?: React.KeyboardEventHandler<HTMLInputElement>;
addonBefore?: React.ReactNode;
addonAfter?: React.ReactNode;
onPressEnter?: React.FormEventHandler<HTMLInputElement>;
onKeyDown?: React.FormEventHandler<HTMLInputElement>;
onKeyUp?: React.FormEventHandler<HTMLInputElement>;
onChange?: React.ChangeEventHandler<HTMLInputElement>;
onClick?: React.FormEventHandler<HTMLInputElement>;
onFocus?: React.FormEventHandler<HTMLInputElement>;
onBlur?: React.FormEventHandler<HTMLInputElement>;
autoComplete?: string;
prefix?: React.ReactNode;
suffix?: React.ReactNode;
spellCheck?: boolean;
autoFocus?: boolean;
}
export default class Input extends React.Component<InputProps, any> {

View File

@@ -41,31 +41,31 @@ export default class Search extends React.Component<SearchProps, any> {
getButtonOrIcon() {
const { enterButton, prefixCls, size, disabled } = this.props;
if (!enterButton) {
return <Icon className={`${prefixCls}-icon`} type="search" key="searchIcon" />;
}
const enterButtonAsElement = enterButton as React.ReactElement<any>;
if (enterButtonAsElement.type === Button || enterButtonAsElement.type === 'button') {
return React.cloneElement(enterButtonAsElement, enterButtonAsElement.type === Button ? {
let node;
if (!enterButton) {
node = <Icon className={`${prefixCls}-icon`} type="search" key="searchIcon" />;
} else if (enterButtonAsElement.type === Button || enterButtonAsElement.type === 'button') {
node = React.cloneElement(enterButtonAsElement, enterButtonAsElement.type === Button ? {
className: `${prefixCls}-button`,
size,
onClick: this.onSearch,
} : {
onClick: this.onSearch,
});
} : {});
} else {
node = (
<Button
className={`${prefixCls}-button`}
type="primary"
size={size}
disabled={disabled}
key="enterButton"
>
{enterButton === true ? <Icon type="search" /> : enterButton}
</Button>
);
}
return (
<Button
className={`${prefixCls}-button`}
type="primary"
size={size}
disabled={disabled}
onClick={this.onSearch}
key="enterButton"
>
{enterButton === true ? <Icon type="search" /> : enterButton}
</Button>
);
return React.cloneElement(node, {
onClick: this.onSearch,
});
}
render() {

View File

@@ -1,7 +1,6 @@
import * as React from 'react';
import omit from 'omit.js';
import classNames from 'classnames';
import { AbstractInputProps } from './Input';
import calculateNodeHeight from './calculateNodeHeight';
function onNextFrame(cb: () => void) {
@@ -24,9 +23,10 @@ export interface AutoSizeType {
maxRows?: number;
}
export interface TextAreaProps extends AbstractInputProps {
export interface TextAreaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
prefixCls?: string;
autosize?: boolean | AutoSizeType;
onPressEnter?: React.FormEventHandler<any>;
onPressEnter?: React.KeyboardEventHandler<HTMLTextAreaElement>;
}
export interface TextAreaState {

View File

@@ -27,4 +27,64 @@ describe('Input.Search', () => {
);
expect(wrapper.find('.ant-btn-primary[disabled]')).toHaveLength(1);
});
it('should trigger onSearch when click search icon', () => {
const onSearch = jest.fn();
const wrapper = mount(
<Search defaultValue="search text" onSearch={onSearch} />
);
wrapper.find('Icon').simulate('click');
expect(onSearch).toHaveBeenCalledTimes(1);
expect(onSearch).toBeCalledWith('search text');
});
it('should trigger onSearch when click search button', () => {
const onSearch = jest.fn();
const wrapper = mount(
<Search defaultValue="search text" enterButton onSearch={onSearch} />
);
wrapper.find('Button').simulate('click');
expect(onSearch).toHaveBeenCalledTimes(1);
expect(onSearch).toBeCalledWith('search text');
});
it('should trigger onSearch when click search button with text', () => {
const onSearch = jest.fn();
const wrapper = mount(
<Search defaultValue="search text" enterButton="button text" onSearch={onSearch} />
);
wrapper.find('Button').simulate('click');
expect(onSearch).toHaveBeenCalledTimes(1);
expect(onSearch).toBeCalledWith('search text');
});
it('should trigger onSearch when click search button with customize button', () => {
const onSearch = jest.fn();
const wrapper = mount(
<Search defaultValue="search text" enterButton={<Button>antd button</Button>} onSearch={onSearch} />
);
wrapper.find('Button').simulate('click');
expect(onSearch).toHaveBeenCalledTimes(1);
expect(onSearch).toBeCalledWith('search text');
});
it('should trigger onSearch when click search button of native', () => {
const onSearch = jest.fn();
const wrapper = mount(
<Search defaultValue="search text" enterButton={<button>antd button</button>} onSearch={onSearch} />
);
wrapper.find('button').simulate('click');
expect(onSearch).toHaveBeenCalledTimes(1);
expect(onSearch).toBeCalledWith('search text');
});
it('should trigger onSearch when press enter', () => {
const onSearch = jest.fn();
const wrapper = mount(
<Search defaultValue="search text" onSearch={onSearch} />
);
wrapper.find('input').simulate('keydown', { key: 'Enter', keyCode: 13 });
expect(onSearch).toHaveBeenCalledTimes(1);
expect(onSearch).toBeCalledWith('search text');
});
});

View File

@@ -34,6 +34,7 @@ exports[`Input.Search should support suffix 1`] = `
"suffix",
<Icon
className="ant-input-search-icon"
onClick={[Function]}
type="search"
/>,
]
@@ -57,10 +58,12 @@ exports[`Input.Search should support suffix 1`] = `
<Icon
className="ant-input-search-icon"
key="searchIcon"
onClick={[Function]}
type="search"
>
<i
className="anticon anticon-search ant-input-search-icon"
onClick={[Function]}
/>
</Icon>
</span>

View File

@@ -31,7 +31,12 @@ ReactDOM.render(
enterButton
/>
<br /><br />
<Search placeholder="input search text" enterButton="Search" size="large" />
<Search
placeholder="input search text"
enterButton="Search"
size="large"
onSearch={value => console.log(value)}
/>
</div>
, mountNode);
````

View File

@@ -9,13 +9,11 @@ title:
我们为 `<Input />` 输入框定义了三种尺寸(大、默认、小),高度分别为 `40px``32px``24px`
注意: 在表单里面,我们只使用大尺寸的输入框。
## en-US
There are three sizes of an Input box: `large` (40px)、`default` (32px) and `small` (24px).
Note: Inside of forms, only the large size is used.
````jsx
import { Input } from 'antd';

View File

@@ -21,11 +21,13 @@
border-color: ~`colorPalette("@{color}", 5)`;
outline: 0;
box-shadow: 0 0 @outline-blur-size @outline-width fade(@color, 20%);
border-right-width: 1px !important;
}
// == when hoverd
.hover(@color: @input-hover-border-color) {
border-color: ~`colorPalette("@{color}", 5)`;
border-right-width: 1px !important;
}
.disabled() {
@@ -135,6 +137,11 @@
margin-bottom: 0;
&:focus {
z-index: 1; // Fix https://gw.alipayobjects.com/zos/rmsportal/DHNpoqfMXSfrSnlZvhsJ.png
border-right-width: 1px;
}
&:hover {
z-index: 1;
border-right-width: 1px;
}
}
@@ -267,7 +274,6 @@
// Undo float for .ant-input-group .ant-input
.@{inputClass} {
float: none;
z-index: auto;
}
// reset border for Select, DatePicker, AutoComplete, Cascader, Mention, TimePicker

View File

@@ -7,8 +7,12 @@
.@{search-prefix} {
&-icon {
pointer-events: none;
color: @text-color-secondary;
cursor: pointer;
transition: all .3s;
&:hover {
color: #333;
}
}
&:not(&-small) > .@{ant-prefix}-input-suffix {

View File

@@ -31,6 +31,8 @@ const dimensionMap = {
export type CollapseType = 'clickTrigger' | 'responsive';
export type SiderTheme = 'light' | 'dark';
export interface SiderProps extends React.HTMLAttributes<HTMLDivElement> {
prefixCls?: string;
collapsible?: boolean;
@@ -42,6 +44,7 @@ export interface SiderProps extends React.HTMLAttributes<HTMLDivElement> {
width?: number | string;
collapsedWidth?: number | string;
breakpoint?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl';
theme?: SiderTheme;
}
export interface SiderState {
@@ -73,6 +76,7 @@ export default class Sider extends React.Component<SiderProps, SiderState> {
width: 200,
collapsedWidth: 80,
style: {},
theme: 'dark' as SiderTheme,
};
static childContextTypes = {
@@ -174,9 +178,9 @@ export default class Sider extends React.Component<SiderProps, SiderState> {
}
render() {
const { prefixCls, className,
const { prefixCls, className, theme,
collapsible, reverseArrow, trigger, style, width, collapsedWidth,
...others,
...others
} = this.props;
const divProps = omit(others, ['collapsed',
'defaultCollapsed', 'onCollapse', 'breakpoint']);
@@ -210,7 +214,7 @@ export default class Sider extends React.Component<SiderProps, SiderState> {
minWidth: siderWidth, // https://github.com/ant-design/ant-design/issues/6349
width: siderWidth,
};
const siderCls = classNames(className, prefixCls, {
const siderCls = classNames(className, prefixCls, `${prefixCls}-${theme}`, {
[`${prefixCls}-collapsed`]: !!this.state.collapsed,
[`${prefixCls}-has-trigger`]: collapsible && trigger !== null && !zeroWidthTrigger,
[`${prefixCls}-below`]: !!this.state.below,

View File

@@ -33,7 +33,7 @@ exports[`renders ./components/layout/demo/basic.md correctly 1`] = `
class="ant-layout"
>
<div
class="ant-layout-sider"
class="ant-layout-sider ant-layout-sider-dark"
style="flex:0 0 200px;max-width:200px;min-width:200px;width:200px"
>
<div
@@ -71,7 +71,7 @@ exports[`renders ./components/layout/demo/basic.md correctly 1`] = `
Content
</div>
<div
class="ant-layout-sider"
class="ant-layout-sider ant-layout-sider-dark"
style="flex:0 0 200px;max-width:200px;min-width:200px;width:200px"
>
<div
@@ -91,7 +91,7 @@ exports[`renders ./components/layout/demo/basic.md correctly 1`] = `
class="ant-layout"
>
<div
class="ant-layout-sider"
class="ant-layout-sider ant-layout-sider-dark"
style="flex:0 0 200px;max-width:200px;min-width:200px;width:200px"
>
<div
@@ -128,7 +128,7 @@ exports[`renders ./components/layout/demo/custom-trigger.md correctly 1`] = `
class="ant-layout"
>
<div
class="ant-layout-sider"
class="ant-layout-sider ant-layout-sider-dark"
style="flex:0 0 200px;max-width:200px;min-width:200px;width:200px"
>
<div
@@ -207,7 +207,7 @@ exports[`renders ./components/layout/demo/fixed.md correctly 1`] = `
>
<div
class="ant-layout-header"
style="position:fixed;width:100%"
style="position:fixed;z-index:1;width:100%"
>
<div
class="logo"
@@ -302,7 +302,7 @@ exports[`renders ./components/layout/demo/fixed-sider.md correctly 1`] = `
class="ant-layout"
>
<div
class="ant-layout-sider"
class="ant-layout-sider ant-layout-sider-dark"
style="overflow:auto;height:100vh;position:fixed;left:0;flex:0 0 200px;max-width:200px;min-width:200px;width:200px"
>
<div
@@ -557,7 +557,7 @@ exports[`renders ./components/layout/demo/responsive.md correctly 1`] = `
class="ant-layout"
>
<div
class="ant-layout-sider"
class="ant-layout-sider ant-layout-sider-dark"
style="flex:0 0 200px;max-width:200px;min-width:200px;width:200px"
>
<div
@@ -662,7 +662,7 @@ exports[`renders ./components/layout/demo/side.md correctly 1`] = `
style="min-height:100vh"
>
<div
class="ant-layout-sider ant-layout-sider-has-trigger"
class="ant-layout-sider ant-layout-sider-dark ant-layout-sider-has-trigger"
style="flex:0 0 200px;max-width:200px;min-width:200px;width:200px"
>
<div
@@ -1006,7 +1006,7 @@ exports[`renders ./components/layout/demo/top-side.md correctly 1`] = `
style="padding:24px 0;background:#fff"
>
<div
class="ant-layout-sider"
class="ant-layout-sider ant-layout-sider-dark"
style="background:#fff;flex:0 0 200px;max-width:200px;min-width:200px;width:200px"
>
<div
@@ -1176,7 +1176,7 @@ exports[`renders ./components/layout/demo/top-side-2.md correctly 1`] = `
class="ant-layout"
>
<div
class="ant-layout-sider"
class="ant-layout-sider ant-layout-sider-dark"
style="background:#fff;flex:0 0 200px;max-width:200px;min-width:200px;width:200px"
>
<div

View File

@@ -55,4 +55,18 @@ describe('Layout', () => {
);
expect(wrapper.find('.ant-layout-sider').hasClass('ant-layout-sider-zero-width')).toBe(true);
});
it('detect ant-layout-sider-dark as default theme', async () => {
const wrapper = mount(
<Sider>Sider</Sider>
);
expect(wrapper.find('.ant-layout-sider').hasClass('ant-layout-sider-dark'));
});
it('detect ant-layout-sider-light when set light theme', async () => {
const wrapper = mount(
<Sider theme="light">Sider</Sider>
);
expect(wrapper.find('.ant-layout-sider').hasClass('ant-layout-sider-light'));
});
});

View File

@@ -20,7 +20,7 @@ const { Header, Content, Footer } = Layout;
ReactDOM.render(
<Layout>
<Header style={{ position: 'fixed', width: '100%' }}>
<Header style={{ position: 'fixed', zIndex: 1, width: '100%' }}>
<div className="logo" />
<Menu
theme="dark"

View File

@@ -98,6 +98,7 @@ The sidebar.
| trigger | specify the customized trigger, set to null to hide the trigger | string\|ReactNode | - |
| width | width of the sidebar | number\|string | 200 |
| onCollapse | the callback function, executed by clicking the trigger or activating the responsive layout | (collapsed, type) => {} | - |
| theme | color theme of the sidebar | string: `light` `dark` | `dark` |
#### breakpoint width

View File

@@ -99,6 +99,7 @@ title: Layout
| trigger | 自定义 trigger设置为 null 时隐藏 trigger | string\|ReactNode | - |
| width | 宽度 | number\|string | 200 |
| onCollapse | 展开-收起时的回调函数,有点击 trigger 以及响应式反馈两种方式可以触发 | (collapsed, type) => {} | - |
| theme | 主题颜色 | string: `light` `dark` | `dark` |
#### breakpoint width

View File

@@ -110,3 +110,5 @@
}
}
}
@import './light';

View File

@@ -0,0 +1,11 @@
.@{layout-prefix-cls} {
&-sider {
&-light {
background: @layout-sider-background-light;
}
&-light > &-trigger {
color: @layout-trigger-color-light;
background: @layout-trigger-background-light;
}
}
}

View File

@@ -31,7 +31,7 @@ export const Meta = (props: ListItemMetaProps) => {
avatar,
title,
description,
...others,
...others
} = props;
const classString = classNames(`${prefixCls}-item-meta`, className);

View File

@@ -126,4 +126,15 @@ describe('List.pagination', () => {
.hasClass('ant-pagination-item-active')
).toBe(true);
});
it('specify the position of pagination', () => {
const wrapper = mount(createList({ pagination: { position: 'top' } }));
expect(wrapper.find('.ant-list').childAt(0).find('.ant-pagination')).toHaveLength(1);
wrapper.setProps({ pagination: { position: 'bottom' } });
expect(wrapper.find('.ant-list').children().last().find('.ant-pagination')).toHaveLength(1);
wrapper.setProps({ pagination: { position: 'both' } });
expect(wrapper.find('.ant-pagination')).toHaveLength(2);
expect(wrapper.find('.ant-list').childAt(0).find('.ant-pagination')).toHaveLength(1);
expect(wrapper.find('.ant-list').children().last().find('.ant-pagination')).toHaveLength(1);
});
});

View File

@@ -1,7 +1,7 @@
---
category: Components
type: Data Display
title: List
title: List
cols: 1
---
@@ -28,6 +28,16 @@ A list can be used to display content related to a single subject. The content c
| pagination | Pagination [config](https://ant.design/components/pagination/), hide it by setting it to false | boolean \| object | false |
| split | Toggles rendering of the split under the list item | boolean | true |
### pagination
Properties for pagination.
| Property | Description | Type | Default |
| -------- | ----------- | ---- | ------- |
| position | specify the position of `Pagination` | 'top' \| 'bottom' \| 'both' | 'bottom' |
More about pagination, please check [`Pagination`](/components/pagination/).
### List grid props
| Property | Description | Type | Default |

View File

@@ -6,7 +6,7 @@ import LocaleReceiver from '../locale-provider/LocaleReceiver';
import defaultLocale from '../locale-provider/default';
import Spin from '../spin';
import Pagination from '../pagination';
import Pagination, { PaginationConfig } from '../pagination';
import { Row } from '../grid';
import Item from './Item';
@@ -49,7 +49,7 @@ export interface ListProps {
itemLayout?: string;
loading?: boolean | SpinProps;
loadMore?: React.ReactNode;
pagination?: any;
pagination?: PaginationConfig;
prefixCls?: string;
rowKey?: any;
renderItem: any;
@@ -162,7 +162,7 @@ export default class List extends React.Component<ListProps> {
footer,
loading,
locale,
...rest,
...rest
} = this.props;
let loadingProp = loading;
@@ -200,8 +200,9 @@ export default class List extends React.Component<ListProps> {
...this.defaultPaginationProps,
total: dataSource.length,
current: paginationCurrent,
...pagination,
...pagination || {},
};
const largestPage = Math.ceil(
paginationProps.total / paginationProps.pageSize,
);
@@ -258,15 +259,18 @@ export default class List extends React.Component<ListProps> {
);
}
const paginationPosition = paginationProps.position || 'bottom';
return (
<div className={classString} {...rest}>
{(paginationPosition === 'top' || paginationPosition === 'both') && paginationContent}
{header && <div className={`${prefixCls}-header`}>{header}</div>}
<Spin {...loadingProp}>
{childrenContent}
{children}
</Spin>
{footer && <div className={`${prefixCls}-footer`}>{footer}</div>}
{loadMore || paginationContent}
{loadMore || (paginationPosition === 'bottom' || paginationPosition === 'both') && paginationContent}
</div>
);
}

View File

@@ -1,7 +1,7 @@
---
category: Components
type: Data Display
title: List
title: List
subtitle: 列表
cols: 1
---
@@ -30,6 +30,16 @@ cols: 1
| size | list 的尺寸 | `default` \| `middle` \| `small` | `default` |
| split | 是否展示分割线 | boolean | true |
### pagination
分页的配置项。
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| position | 指定分页显示的位置 | 'top' \| 'bottom' \| 'both' | 'bottom' |
更多配置项,请查看 [`Pagination`](/components/pagination/)。
### List grid props
| 参数 | 说明 | 类型 | 默认值 |

View File

@@ -703,7 +703,7 @@ exports[`renders ./components/locale-provider/demo/all.md correctly 1`] = `
</div>
</td>
<td
class="ant-fullcalendar-cell ant-fullcalendar-last-month-cell"
class="ant-fullcalendar-cell ant-fullcalendar-last-month-cell ant-fullcalendar-last-day-of-month"
role="gridcell"
title="October 31, 2016"
>
@@ -1263,7 +1263,7 @@ exports[`renders ./components/locale-provider/demo/all.md correctly 1`] = `
</div>
</td>
<td
class="ant-fullcalendar-cell"
class="ant-fullcalendar-cell ant-fullcalendar-last-day-of-month"
role="gridcell"
title="November 30, 2016"
>

View File

@@ -14,7 +14,8 @@ title: LocaleProvider
```jsx
import { LocaleProvider } from 'antd';
import fr_FR from 'antd/lib/locale-provider/fr_FR';
import 'moment/locale/fr';
import 'moment/src/locale/fr';
// import 'moment/locale/fr'; if you are using webpack 1
...

View File

@@ -15,7 +15,8 @@ LocaleProvider 使用 React 的 [context](https://facebook.github.io/react/docs/
```jsx
import { LocaleProvider } from 'antd';
import zh_CN from 'antd/lib/locale-provider/zh_CN';
import 'moment/locale/zh-cn';
import 'moment/src/locale/zh-cn';
// import 'moment/locale/zh-cn'; if you are using webpack 1
...

View File

@@ -29,8 +29,8 @@ export default {
Transfer: {
notFoundContent: 'Ничего не найдено',
searchPlaceholder: 'Введите название для поиска',
itemUnit: 'item',
itemsUnit: 'items',
itemUnit: 'элем.',
itemsUnit: 'элем.',
},
Select: {
notFoundContent: 'Ничего не найдено',

View File

@@ -0,0 +1,804 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders ./components/mention/demo/async.md correctly 1`] = `
<div
class="ant-mention-wrapper"
style="width:100%"
>
<div
class="ant-mention-editor oneline"
style="width:100%"
>
<div
class="ant-mention-toolbar"
/>
<div
class="ant-mention-editor-wrapper"
style="width:100%"
>
<div
class="DraftEditor-root"
>
<div
class="DraftEditor-editorContainer"
>
<div
aria-describedby="placeholder-123"
class="notranslate public-DraftEditor-content"
contenteditable="true"
role="textbox"
spellcheck="false"
style="outline:none;user-select:text;-webkit-user-select:text;white-space:pre-wrap;word-wrap:break-word"
>
<div
data-contents="true"
>
<div
class=""
data-block="true"
data-editor="123"
data-offset-key="123-0-0"
>
<div
class="public-DraftStyleDefault-block public-DraftStyleDefault-ltr"
data-offset-key="123-0-0"
>
<span
data-offset-key="123-0-0"
>
<br
data-text="true"
/>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
`;
exports[`renders ./components/mention/demo/avatar.md correctly 1`] = `
<div
class="ant-mention-wrapper"
style="width:100%"
>
<div
class="ant-mention-editor oneline"
style="width:100%"
>
<div
class="ant-mention-toolbar"
/>
<div
class="ant-mention-editor-wrapper"
style="width:100%"
>
<div
class="DraftEditor-root"
>
<div
class="DraftEditor-editorContainer"
>
<div
aria-describedby="placeholder-123"
class="notranslate public-DraftEditor-content"
contenteditable="true"
role="textbox"
spellcheck="false"
style="outline:none;user-select:text;-webkit-user-select:text;white-space:pre-wrap;word-wrap:break-word"
>
<div
data-contents="true"
>
<div
class=""
data-block="true"
data-editor="123"
data-offset-key="123-0-0"
>
<div
class="public-DraftStyleDefault-block public-DraftStyleDefault-ltr"
data-offset-key="123-0-0"
>
<span
data-offset-key="123-0-0"
>
<br
data-text="true"
/>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
`;
exports[`renders ./components/mention/demo/basic.md correctly 1`] = `
<div
class="ant-mention-wrapper"
style="width:100%"
>
<div
class="ant-mention-editor oneline"
style="width:100%"
>
<div
class="ant-mention-toolbar"
/>
<div
class="ant-mention-editor-wrapper"
style="width:100%"
>
<div
class="DraftEditor-root"
>
<div
class="DraftEditor-editorContainer"
>
<div
aria-describedby="placeholder-123"
class="notranslate public-DraftEditor-content"
contenteditable="true"
role="textbox"
spellcheck="false"
style="outline:none;user-select:text;-webkit-user-select:text;white-space:pre-wrap;word-wrap:break-word"
>
<div
data-contents="true"
>
<div
class=""
data-block="true"
data-editor="123"
data-offset-key="123-0-0"
>
<div
class="public-DraftStyleDefault-block public-DraftStyleDefault-ltr"
data-offset-key="123-0-0"
>
<span>
<span
data-offset-key="123-0-0"
>
<span
data-text="true"
>
@afc163
</span>
</span>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
`;
exports[`renders ./components/mention/demo/controllder-simple.md correctly 1`] = `
<div
class="ant-mention-wrapper"
>
<div
class="ant-mention-editor oneline"
>
<div
class="ant-mention-toolbar"
/>
<div
class="ant-mention-editor-wrapper"
>
<div
class="DraftEditor-root"
>
<div
class="DraftEditor-editorContainer"
>
<div
aria-describedby="placeholder-123"
class="notranslate public-DraftEditor-content"
contenteditable="true"
role="textbox"
spellcheck="false"
style="outline:none;user-select:text;-webkit-user-select:text;white-space:pre-wrap;word-wrap:break-word"
>
<div
data-contents="true"
>
<div
class=""
data-block="true"
data-editor="123"
data-offset-key="123-0-0"
>
<div
class="public-DraftStyleDefault-block public-DraftStyleDefault-ltr"
data-offset-key="123-0-0"
>
<span>
<span
data-offset-key="123-0-0"
>
<span
data-text="true"
>
@afc163
</span>
</span>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
`;
exports[`renders ./components/mention/demo/controlled.md correctly 1`] = `
<form
class="ant-form ant-form-horizontal"
>
<div
class="ant-row ant-form-item"
>
<div
class="ant-col-6 ant-form-item-label"
>
<label
class=""
for="control-mention"
title="Top coders"
>
Top coders
</label>
</div>
<div
class="ant-col-16 ant-form-item-control-wrapper"
>
<div
class="ant-form-item-control has-success"
>
<span
class="ant-form-item-children"
>
<div
class="ant-mention-wrapper"
>
<div
class="ant-mention-editor oneline"
>
<div
class="ant-mention-toolbar"
/>
<div
class="ant-mention-editor-wrapper"
>
<div
class="DraftEditor-root"
>
<div
class="DraftEditor-editorContainer"
>
<div
aria-describedby="placeholder-123"
class="notranslate public-DraftEditor-content"
contenteditable="true"
role="textbox"
spellcheck="false"
style="outline:none;user-select:text;-webkit-user-select:text;white-space:pre-wrap;word-wrap:break-word"
>
<div
data-contents="true"
>
<div
class=""
data-block="true"
data-editor="123"
data-offset-key="123-0-0"
>
<div
class="public-DraftStyleDefault-block public-DraftStyleDefault-ltr"
data-offset-key="123-0-0"
>
<span>
<span
data-offset-key="123-0-0"
>
<span
data-text="true"
>
@afc163
</span>
</span>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</span>
</div>
</div>
</div>
<div
class="ant-row ant-form-item"
>
<div
class="ant-col-14 ant-col-offset-6 ant-form-item-control-wrapper"
>
<div
class="ant-form-item-control"
>
<span
class="ant-form-item-children"
>
<button
class="ant-btn ant-btn-primary"
type="button"
>
<span>
Submit
</span>
</button>
   
<button
class="ant-btn"
type="button"
>
<span>
Reset
</span>
</button>
</span>
</div>
</div>
</div>
</form>
`;
exports[`renders ./components/mention/demo/custom-tag.md correctly 1`] = `
<div
class="ant-mention-wrapper"
style="width:100%"
>
<div
class="ant-mention-editor oneline"
style="width:100%"
>
<div
class="ant-mention-toolbar"
/>
<div
class="ant-mention-editor-wrapper"
style="width:100%"
>
<div
class="DraftEditor-root"
>
<div
class="public-DraftEditorPlaceholder-root"
>
<div
class="public-DraftEditorPlaceholder-inner"
id="placeholder-123"
style="white-space:pre-wrap"
>
@someone
</div>
</div>
<div
class="DraftEditor-editorContainer"
>
<div
aria-describedby="placeholder-123"
class="notranslate public-DraftEditor-content"
contenteditable="true"
role="textbox"
spellcheck="false"
style="outline:none;user-select:text;-webkit-user-select:text;white-space:pre-wrap;word-wrap:break-word"
>
<div
data-contents="true"
>
<div
class=""
data-block="true"
data-editor="123"
data-offset-key="123-0-0"
>
<div
class="public-DraftStyleDefault-block public-DraftStyleDefault-ltr"
data-offset-key="123-0-0"
>
<span
data-offset-key="123-0-0"
>
<br
data-text="true"
/>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
`;
exports[`renders ./components/mention/demo/multilines.md correctly 1`] = `
<div
class="ant-mention-wrapper multilines"
style="width:100%;height:100px"
>
<div
class="ant-mention-editor"
style="width:100%;height:100px"
>
<div
class="ant-mention-toolbar"
/>
<div
class="ant-mention-editor-wrapper"
style="width:100%;height:100px"
>
<div
class="DraftEditor-root"
>
<div
class="DraftEditor-editorContainer"
>
<div
aria-describedby="placeholder-123"
class="notranslate public-DraftEditor-content"
contenteditable="true"
role="textbox"
spellcheck="false"
style="outline:none;user-select:text;-webkit-user-select:text;white-space:pre-wrap;word-wrap:break-word"
>
<div
data-contents="true"
>
<div
class=""
data-block="true"
data-editor="123"
data-offset-key="123-0-0"
>
<div
class="public-DraftStyleDefault-block public-DraftStyleDefault-ltr"
data-offset-key="123-0-0"
>
<span
data-offset-key="123-0-0"
>
<br
data-text="true"
/>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
`;
exports[`renders ./components/mention/demo/multiple-trigger.md correctly 1`] = `
<div
class="ant-mention-wrapper"
style="width:100%"
>
<div
class="ant-mention-editor oneline"
style="width:100%"
>
<div
class="ant-mention-toolbar"
/>
<div
class="ant-mention-editor-wrapper"
style="width:100%"
>
<div
class="DraftEditor-root"
>
<div
class="public-DraftEditorPlaceholder-root"
>
<div
class="public-DraftEditorPlaceholder-inner"
id="placeholder-123"
style="white-space:pre-wrap"
>
input @ to mention people, # to mention tag
</div>
</div>
<div
class="DraftEditor-editorContainer"
>
<div
aria-describedby="placeholder-123"
class="notranslate public-DraftEditor-content"
contenteditable="true"
role="textbox"
spellcheck="false"
style="outline:none;user-select:text;-webkit-user-select:text;white-space:pre-wrap;word-wrap:break-word"
>
<div
data-contents="true"
>
<div
class=""
data-block="true"
data-editor="123"
data-offset-key="123-0-0"
>
<div
class="public-DraftStyleDefault-block public-DraftStyleDefault-ltr"
data-offset-key="123-0-0"
>
<span
data-offset-key="123-0-0"
>
<br
data-text="true"
/>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
`;
exports[`renders ./components/mention/demo/placement.md correctly 1`] = `
<div
class="ant-mention-placement-top ant-mention-wrapper"
style="width:100%"
>
<div
class="ant-mention-editor oneline"
style="width:100%"
>
<div
class="ant-mention-toolbar"
/>
<div
class="ant-mention-editor-wrapper"
style="width:100%"
>
<div
class="DraftEditor-root"
>
<div
class="DraftEditor-editorContainer"
>
<div
aria-describedby="placeholder-123"
class="notranslate public-DraftEditor-content"
contenteditable="true"
role="textbox"
spellcheck="false"
style="outline:none;user-select:text;-webkit-user-select:text;white-space:pre-wrap;word-wrap:break-word"
>
<div
data-contents="true"
>
<div
class=""
data-block="true"
data-editor="123"
data-offset-key="123-0-0"
>
<div
class="public-DraftStyleDefault-block public-DraftStyleDefault-ltr"
data-offset-key="123-0-0"
>
<span
data-offset-key="123-0-0"
>
<br
data-text="true"
/>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
`;
exports[`renders ./components/mention/demo/popupContainer.md correctly 1`] = `
<button
class="ant-btn ant-btn-primary"
type="button"
>
<span>
Click Me
</span>
</button>
`;
exports[`renders ./components/mention/demo/readonly.md correctly 1`] = `
<div>
<div
style="margin-bottom:10px"
>
<div
class="ant-mention-wrapper disabled"
style="width:100%"
>
<div
class="ant-mention-editor readonly oneline"
style="width:100%"
>
<div
class="ant-mention-toolbar"
/>
<div
class="ant-mention-editor-wrapper"
style="width:100%"
>
<div
class="DraftEditor-root"
>
<div
class="public-DraftEditorPlaceholder-root"
>
<div
class="public-DraftEditorPlaceholder-inner"
id="placeholder-123"
style="white-space:pre-wrap"
>
this is disabled Mention
</div>
</div>
<div
class="DraftEditor-editorContainer"
>
<div
aria-describedby="placeholder-123"
class="public-DraftEditor-content"
contenteditable="false"
spellcheck="false"
style="outline:none;user-select:text;-webkit-user-select:text;white-space:pre-wrap;word-wrap:break-word"
>
<div
data-contents="true"
>
<div
class=""
data-block="true"
data-editor="123"
data-offset-key="123-0-0"
>
<div
class="public-DraftStyleDefault-block public-DraftStyleDefault-ltr"
data-offset-key="123-0-0"
>
<span
data-offset-key="123-0-0"
>
<br
data-text="true"
/>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
<input
style="width:0;opacity:0;border:0;position:absolute;left:0;top:0"
/>
</div>
</div>
</div>
</div>
<div
class="ant-mention-wrapper readonly"
style="width:100%"
>
<div
class="ant-mention-editor readonly oneline"
style="width:100%"
>
<div
class="ant-mention-toolbar"
/>
<div
class="ant-mention-editor-wrapper"
style="width:100%"
>
<div
class="DraftEditor-root"
>
<div
class="public-DraftEditorPlaceholder-root"
>
<div
class="public-DraftEditorPlaceholder-inner"
id="placeholder-123"
style="white-space:pre-wrap"
>
this is readOnly Mention
</div>
</div>
<div
class="DraftEditor-editorContainer"
>
<div
aria-describedby="placeholder-123"
class="public-DraftEditor-content"
contenteditable="false"
spellcheck="false"
style="outline:none;user-select:text;-webkit-user-select:text;white-space:pre-wrap;word-wrap:break-word"
>
<div
data-contents="true"
>
<div
class=""
data-block="true"
data-editor="123"
data-offset-key="123-0-0"
>
<div
class="public-DraftStyleDefault-block public-DraftStyleDefault-ltr"
data-offset-key="123-0-0"
>
<span
data-offset-key="123-0-0"
>
<br
data-text="true"
/>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
<input
style="width:0;opacity:0;border:0;position:absolute;left:0;top:0"
/>
</div>
</div>
</div>
</div>
`;

View File

@@ -1,3 +1,5 @@
import demoTest from '../../../tests/shared/demoTest';
demoTest('mention', { skip: true });
jest.mock('draft-js/lib/generateRandomKey', () => () => '123');
demoTest('mention', { skip: process.env.LIB_DIR === 'dist' });

View File

@@ -0,0 +1,61 @@
import React from 'react';
import { mount } from 'enzyme';
import Mention from '..';
const { toContentState } = Mention;
describe('Mention', () => {
beforeAll(() => {
jest.useFakeTimers();
});
afterAll(() => {
jest.useRealTimers();
});
it('should has focus function', () => {
const handleFocus = jest.fn();
const wrapper = mount(
<Mention
defaultValue={toContentState('@afc163')}
onFocus={handleFocus}
suggestions={['afc163', 'benjycui', 'yiminghe', 'RaoHai', '中文', 'にほんご']}
/>
);
wrapper.instance().focus();
jest.runAllTimers();
expect(handleFocus).toBeCalled();
});
it('basic suggestion', () => {
const handleSearch = jest.fn();
const wrapper = mount(
<Mention
suggestions={['afc163', 'raohai']}
onSearchChange={handleSearch}
/>
);
wrapper.find('DraftEditorContents').simulate('focus');
const ed = wrapper.find('.public-DraftEditor-content');
ed.simulate('beforeInput', { data: '@a' });
jest.runAllTimers();
expect(handleSearch).toBeCalledWith('a', '@');
});
it('change suggestions', () => {
const container = mount(<div id="container" />);
const wrapper = mount(
<Mention suggestions={['afc163', 'raohai']} getSuggestionContainer={() => container.getDOMNode()} />
);
wrapper.find('DraftEditorContents').simulate('focus');
const ed = wrapper.find('.public-DraftEditor-content');
ed.simulate('beforeInput', { data: '@' });
jest.runAllTimers();
expect(container.getDOMNode().querySelectorAll('.ant-mention-dropdown-item').length).toBe(2);
expect(container.getDOMNode().querySelectorAll('.ant-mention-dropdown-item')[0].innerHTML).toBe('afc163');
wrapper.setState({ suggestions: ['yesmeck', 'yiminghe', 'lucy'] });
jest.runAllTimers();
expect(container.getDOMNode().querySelectorAll('.ant-mention-dropdown-item').length).toBe(3);
expect(container.getDOMNode().querySelectorAll('.ant-mention-dropdown-item')[0].innerHTML).toBe('yesmeck');
});
});

View File

@@ -7,6 +7,8 @@ class SubMenu extends React.Component<any, any> {
static contextTypes = {
antdMenuTheme: PropTypes.string,
};
// fix issue:https://github.com/ant-design/ant-design/issues/8666
static isSubMenu = 1;
private subMenu: any;
onKeyDown = (e: React.MouseEvent<HTMLElement>) => {
this.subMenu.onKeyDown(e);

View File

@@ -14,6 +14,23 @@ describe('Menu', () => {
jest.useRealTimers();
});
it('If has select nested submenu item ,the menu items on the grandfather level should be highlight', () => {
const wrapper = mount(
<Menu defaultSelectedKeys={['1-3-2']} mode="vertical">
<SubMenu key="1" title="submenu1">
<Menu.Item key="1-1">Option 1</Menu.Item>
<Menu.Item key="1-2">Option 2</Menu.Item>
<SubMenu key="1-3" title="submenu1-3">
<Menu.Item key="1-3-1">Option 3</Menu.Item>
<Menu.Item key="1-3-2">Option 4</Menu.Item>
</SubMenu>
</SubMenu>
<Menu.Item key="2">menu2</Menu.Item>
</Menu>
);
expect(wrapper.find('.ant-menu-submenu-selected').length).toBe(1);
});
it('should accept defaultOpenKeys in mode horizontal', () => {
const wrapper = mount(
<Menu defaultOpenKeys={['1']} mode="horizontal">

View File

@@ -52,6 +52,7 @@ export interface MenuProps {
subMenuCloseDelay?: number;
subMenuOpenDelay?: number;
getPopupContainer?: (triggerNode: Element) => HTMLElement;
focusable?: boolean;
}
export interface MenuState {
@@ -63,10 +64,10 @@ export default class Menu extends React.Component<MenuProps, MenuState> {
static Item = Item;
static SubMenu = SubMenu;
static ItemGroup = ItemGroup;
static defaultProps = {
static defaultProps: Partial<MenuProps> = {
prefixCls: 'ant-menu',
className: '',
theme: 'light' as MenuTheme, // or dark
theme: 'light', // or dark
focusable: false,
};
static childContextTypes = {

View File

@@ -279,14 +279,19 @@
}
}
> .@{menu-prefix-cls}-item > a {
display: block;
color: @menu-item-color;
&:hover {
color: @menu-highlight-color;
> .@{menu-prefix-cls}-item {
> a {
display: block;
color: @menu-item-color;
&:hover {
color: @menu-highlight-color;
}
&:before {
bottom: -2px;
}
}
&:before {
bottom: -2px;
&-selected > a {
color: @menu-highlight-color;
}
}

View File

@@ -61,3 +61,14 @@ exports[`renders ./components/message/demo/other.md correctly 1`] = `
</button>
</div>
`;
exports[`renders ./components/message/demo/thenable.md correctly 1`] = `
<button
class="ant-btn"
type="button"
>
<span>
Display a sequence of message
</span>
</button>
`;

View File

@@ -85,6 +85,17 @@ describe('message', () => {
});
});
it('should be called like promise', () => {
jest.useRealTimers();
const defaultDuration = 3;
const now = Date.now();
message.info('whatever').then(() => {
// calculate the approximately duration value
const aboutDuration = parseInt((Date.now() - now) / 1000, 10);
expect(aboutDuration).toBe(defaultDuration);
});
});
// https://github.com/ant-design/ant-design/issues/8201
it('should hide message correctly', () => {
let hide;

View File

@@ -0,0 +1,28 @@
---
order: 5
title:
zh-CN: Promise 接口
en-US: Promise interface
---
## zh-CN
可以通过 then 接口在关闭后运行 callback 。以上用例将在每个 message 将要结束时通过 then 显示新的 message 。
## en-US
`message` provides promise interface for `onClose`. The above example will display a new message when old message is about to finish.
````jsx
import { message, Button } from 'antd';
const success = () => {
message.loading('Action in progress..', 2.5)
.then(() => message.success('Loading finished', 2.5))
.then(() => message.info('Loading finished is finished', 2.5));
};
ReactDOM.render(
<Button onClick={success}>Display a sequence of message</Button>
, mountNode);
````

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