Compare commits

...

122 Commits
2.1.0 ... 2.2.0

Author SHA1 Message Date
Benjy Cui
3ea914721d bump 2.2.0 2016-10-28 18:31:44 +08:00
Benjy Cui
0a962b19ad docs: add change log for 2.2.0 (#3640) 2016-10-28 18:30:17 +08:00
afc163
3add760d42 Merge branch 'master' of github.com:ant-design/ant-design 2016-10-28 18:15:01 +08:00
afc163
c05df5ffd1 Add some new icons 2016-10-28 17:54:22 +08:00
afc163
393e51cab6 Add hover style for Slider handler 2016-10-28 17:42:33 +08:00
偏右
836a058c57 Update ISSUE_TEMPLATE.md 2016-10-28 16:49:36 +08:00
afc163
842b6636a3 support Alert[style] and Alert[className] 2016-10-28 16:42:26 +08:00
Benjy Cui
a3ec948dcd css: the style should follow design 2016-10-28 15:18:29 +08:00
Benjy Cui
d70ff98f9f fix: large size should be set by JS, not CSS, close: #3630 2016-10-28 14:25:09 +08:00
Benjy Cui
6bd75f2666 fix: dropdown menu should not show while disabled, close: #3535 2016-10-28 14:07:46 +08:00
Wei Zhu
f8d2aeefc3 refactor: Replace react-addons-pure-render-mixin with rc-util/lib/PureRenderMixin (#3627) 2016-10-28 13:56:23 +08:00
Benjy Cui
52e3511192 docs: add demo for using time-related in form, close: #3610 2016-10-28 11:30:25 +08:00
ddcat1115
9d218860b5 修复firefox下无数据且固定表头时ant-table-body占高度的问题 (#3632) 2016-10-28 11:14:37 +08:00
Wei Zhu
d3bb55b825 Merge pull request #3628 from ant-design/feat-allowClear
feat: add DatePicker[allowClear], close: #3618
2016-10-28 10:59:07 +08:00
Benjy Cui
d57827f87c fix: empty string should be treat as inexisting, close: #3613 2016-10-28 10:50:55 +08:00
Benjy Cui
eeb6ab5a01 docs: update docs for DatePicker and so on 2016-10-28 10:32:09 +08:00
Benjy Cui
f7e480ad53 feat: add DatePicker[allowClear], close: #3618 2016-10-28 10:10:02 +08:00
偏右
b240494dd5 typo 2016-10-27 21:20:28 +08:00
Benjy Cui
55e9e83be0 Revert "feat: 给message组件添加stack全局配置 #3543 (#3548)"
This reverts commit 818deacfee.
2016-10-27 17:39:46 +08:00
Benjy Cui
ca2e9c6dc2 Revert "fix: should cache correctly"
This reverts commit 75423ed4b1.
2016-10-27 17:39:28 +08:00
Benjy Cui
7860d74725 docs: update advance search form demo, ref: #3558 2016-10-27 17:14:53 +08:00
偏右
0e3d40e6d9 Update ISSUE_TEMPLATE.md 2016-10-27 13:17:09 +08:00
Benjy Cui
55c22a7232 fix: style bug in slider 2016-10-27 11:57:46 +08:00
Benjy Cui
835dc2fb52 docs: update form in modal demo, ref: #3594 2016-10-27 11:44:45 +08:00
afc163
2026449976 fix some props missing documentation 2016-10-27 11:10:19 +08:00
Benjy Cui
6bf99c1819 docs: update advanced search demo, ref: #3594 2016-10-27 10:26:12 +08:00
Benjy Cui
6cd841ef31 docs: add demo for registration, ref: #3594 2016-10-27 09:45:53 +08:00
feng zhi hao
90fbd4da51 types: add datasource generics type in Table (#3603) 2016-10-26 18:26:26 +08:00
Wei Zhu
a62c958a15 Hide inactive pane by set opacity to 0, fix #3304 (#3604) 2016-10-26 18:24:53 +08:00
Benjy Cui
7b76906924 docs: add normal login form, ref: #3594 2016-10-26 17:15:30 +08:00
Benjy Cui
3c49a90980 docs: update demo, ref: #3594 2016-10-26 16:42:57 +08:00
afc163
0f503101af Merge branch 'master' of github.com:ant-design/ant-design 2016-10-26 16:27:58 +08:00
afc163
527949df04 Fix Button and Input vertical-align bug 2016-10-26 16:27:01 +08:00
Benjy Cui
f599a24228 docs: update demo style 2016-10-26 15:33:45 +08:00
afc163
55efef3220 Add Icon[type="bulb"] 2016-10-26 14:26:57 +08:00
Benjy Cui
75423ed4b1 fix: should cache correctly 2016-10-26 11:05:00 +08:00
yeliex
818deacfee feat: 给message组件添加stack全局配置 #3543 (#3548) 2016-10-26 09:33:44 +08:00
Benjy Cui
fed19bbcb5 fix: TimePicker[format] should have default value 2016-10-26 09:25:42 +08:00
Marius Ileana
84c4139023 table / index.en-US.md - small updates (#3584)
small typo and updates
2016-10-25 21:10:31 +08:00
陆离
d051d94af4 feat: RangePicker disabledTime (#3568)
* RangePicker disabledTime

* update API document of RangePicker
2016-10-25 17:39:17 +08:00
Benjy Cui
a3388aa840 chore: upgrade node version in CI 2016-10-25 14:45:23 +08:00
Cody Chan
9d2b48b511 docs: Fix 404 error (#3552) 2016-10-24 18:42:18 +08:00
Benjy Cui
b8fb60079c test: fix test case 2016-10-24 17:02:03 +08:00
Benjy Cui
e9111a855f refactor: remove propTypes in private components 2016-10-24 16:51:53 +08:00
Benjy Cui
08e21e0a2f refactor: close: #3490 2016-10-24 16:30:38 +08:00
Benjy Cui
4878258f6c refactor: ref: #3490 2016-10-24 12:04:26 +08:00
afc163
1da5490ab8 Fix badge initial position jump bug 2016-10-24 11:48:25 +08:00
afc163
ba227bbe54 fix Select[onSearch] overflow scroll 2016-10-24 11:34:50 +08:00
afc163
12e1735255 fix badge[style] 2016-10-24 11:34:12 +08:00
afc163
84b70ac140 fix key={0} in demo, close #3546 2016-10-24 11:06:31 +08:00
afc163
8a7d59241d Merge branch 'master' of github.com:ant-design/ant-design 2016-10-22 17:35:40 +08:00
afc163
831533d139 update doc 2016-10-22 17:29:00 +08:00
ddcat1115
23331e8594 Menu 样式调整 (#3533) 2016-10-22 13:30:59 +08:00
afc163
915f343de3 update select check style 2016-10-21 20:21:40 +08:00
afc163
49256c59c9 Merge branch 'master' of github.com:ant-design/ant-design 2016-10-21 20:20:03 +08:00
afc163
3bb4b6ea7c fix icon spin style, close #3536 2016-10-21 20:18:47 +08:00
Benjy Cui
66f6de79ce refactor: Alert, Backtop, AutoComplete 2016-10-21 18:02:37 +08:00
Benjy Cui
8268bfdd9e refactor: udpate Affix to work with strictNullCheck 2016-10-21 17:44:34 +08:00
Benjy Cui
0c848a5cd2 style: make clickable larger to improve UX 2016-10-21 16:46:30 +08:00
feng zhi hao
0257e02e65 optimize declaration (#3531) 2016-10-21 16:27:26 +08:00
afc163
355f82231c fix select style 2016-10-21 15:36:07 +08:00
Benjy Cui
6343e6b763 docs: update demo 2016-10-21 15:18:13 +08:00
Benjy Cui
1ed434a695 fix: should support Input[addon] in Form[inline], close: #3524 2016-10-21 15:04:55 +08:00
afc163
af3c1aac96 update switch animation ease 2016-10-21 13:09:29 +08:00
afc163
7a115c6c4b fix switch line-height 2016-10-21 12:22:20 +08:00
afc163
9e322ea445 remove unused demo 2016-10-21 12:20:14 +08:00
afc163
1700ae6078 better way to fix #3523 2016-10-21 12:19:34 +08:00
afc163
1be129fa50 Merge branch 'master' of github.com:ant-design/ant-design 2016-10-21 11:46:12 +08:00
afc163
a0c96783c0 fix DatePicker align 2016-10-21 11:45:57 +08:00
Benjy Cui
0aca663092 fix: should throw warning only once, ref: #3491 2016-10-21 11:17:59 +08:00
ddcat1115
7483254df6 Switch 宽度自适应 inner 内容 (#3516) 2016-10-21 11:09:24 +08:00
afc163
ea6a84d9cf fix DatePicker[showTime] onChange, close #3523 2016-10-20 22:11:55 +08:00
afc163
1e5264bad7 fix tslint 2016-10-20 22:10:46 +08:00
afc163
f262f1ab99 update CHANGELOG 2016-10-20 21:43:44 +08:00
afc163
d12cb17804 Fix broken TreeSelect[showSearch] style, close #3520 2016-10-20 21:28:50 +08:00
afc163
4fe28ec298 fix markdown style 2016-10-20 21:00:36 +08:00
yiminghe
9178108906 optimize d.ts 2016-10-20 20:12:46 +08:00
yiminghe
c2d3f16dfb update tslint 2016-10-20 19:19:16 +08:00
Benjy Cui
3112b0d7ca site: support debug mode for demo, close: #3506 2016-10-20 17:45:38 +08:00
Benjy Cui
d5edcb9ef0 feat: support deep-level form control, close: #3212 (#3491) 2016-10-20 16:24:48 +08:00
Benjy Cui
a9fff1be5b docs: update links 2016-10-20 14:49:51 +08:00
Benjy Cui
5d4d9f5cea style: update code style 2016-10-20 14:48:13 +08:00
afc163
97bc13426f fix overflow selected value in Select (#3481) 2016-10-20 14:18:07 +08:00
陆离
05c6d09eab docs: add controllerd sample (#3504)
* add controllerd sample

* lint
2016-10-20 13:51:44 +08:00
afc163
58d98a7802 add Cascader[getPopupContainer] to document, #1503 2016-10-20 12:18:53 +08:00
afc163
7a6b21d02b Merge branch 'master' of github.com:ant-design/ant-design 2016-10-20 12:04:53 +08:00
afc163
d38c5a43da fix about #3481 2016-10-20 11:59:38 +08:00
Benjy Cui
dc78317688 docs: update docs of table, close: #3469 2016-10-20 11:33:53 +08:00
Benjy Cui
3c99097bc8 fix: allow override fileNameProp, close: #3497 2016-10-20 11:28:05 +08:00
afc163
2482b4b760 not limit min-width of Popover without title 2016-10-20 11:23:30 +08:00
afc163
0b29ee6fee continue fix for #3481, also fix multiple select large and small size style 2016-10-19 20:32:14 +08:00
yiminghe
8afe3965c1 upgrade ts 2.0 2016-10-19 17:52:23 +08:00
Benjy Cui
5179ffbbe1 site: support demo[only] 2016-10-19 17:39:25 +08:00
afc163
140997b033 Merge branch 'master' of github.com:ant-design/ant-design 2016-10-19 14:28:38 +08:00
afc163
ff5d9f6029 Fix select vertical-align and refactor its style, close #3481 2016-10-19 14:27:38 +08:00
zilong
6ceef46129 docs: update doc for Table (#3483)
* update Table en doc: fix header content mismatched

* update doc for Table: add description for props related to expand behavior
2016-10-19 14:06:36 +08:00
Benjy Cui
f747f10676 docs: update link and add tags 2016-10-19 14:04:46 +08:00
Benjy Cui
f8b46ad06a docs: update recommended way to ask questions, close: #2320 2016-10-19 12:19:30 +08:00
afc163
9fe859a31f typo #3473 2016-10-19 11:29:14 +08:00
Benjy Cui
39cf0899f5 fix: DatePicker should be vertical-align: middle, close: #3481 2016-10-19 11:22:10 +08:00
Benjy Cui
f52dcbfb37 chore: add warning for invalid usage, close: #3475 2016-10-19 09:45:46 +08:00
afc163
be02817433 fix RadioButton style inside FormItem 2016-10-18 22:26:57 +08:00
afc163
55c2223366 update form docs, #3473 2016-10-18 21:12:52 +08:00
afc163
a223c7bdba Merge branch 'master' of github.com:ant-design/ant-design 2016-10-18 18:20:11 +08:00
afc163
d0a6fa47a9 Fix cascader defaultValue typo, close #3470 2016-10-18 18:19:13 +08:00
afc163
6f8f7de69e update code style 2016-10-18 18:10:41 +08:00
feng zhi hao
6bcd489c50 chore: optimize DatePicker`s declaration (#3468) 2016-10-18 15:20:26 +08:00
Benjy Cui
9ac21d010b docs: add demo for show image in-place, close: #3319 2016-10-18 15:16:25 +08:00
yiminghe
58e0228e86 optimize getFieldProps warning 2016-10-18 12:22:26 +08:00
Benjy Cui
13d48aa1e5 site: show locale in url, close: #3456 2016-10-18 12:04:09 +08:00
Albert Zheng
23dd825afd 【Please review】Fixes for supporting TypeScript 2.0.3 (#3439)
* Fixes for supporting TypeScript 2.0.3

* Fixes for supporting TypeScript 2.0.3. Issue is #3358
2016-10-18 11:55:00 +08:00
Benjy Cui
c082e1b1d1 site: extract common code as utility function 2016-10-18 11:18:25 +08:00
kvetoslavnovak
9ed9fb053a docs: Transfer - heading not wide enough for English (#3466) 2016-10-18 09:45:37 +08:00
afc163
2fe4590887 update site markdown style 2016-10-18 00:18:03 +08:00
afc163
512796b7fe update table demo doc 2016-10-17 20:52:27 +08:00
afc163
806df6e912 update table fixed demos 2016-10-17 20:43:00 +08:00
C
b38d1afe5f Update package.json (#3454) 2016-10-17 11:53:49 +08:00
Benjy Cui
71772260da docs: add link for dora 2016-10-17 09:42:21 +08:00
Benjy Cui
62d2687d6d docs: update README to review easier 2016-10-17 09:37:55 +08:00
Peter Dave Hello
2a12545694 docs: Add CDNJS version badge in readme (#3447) 2016-10-17 09:34:36 +08:00
edgji
6851c8ce3e deps: update rc-upload to latest (#3450) 2016-10-17 09:33:02 +08:00
afc163
0920efb87f update changelog 2016-10-16 16:21:56 +08:00
165 changed files with 1956 additions and 4598 deletions

View File

@@ -1,6 +1,14 @@
<!-- Issue Template -->
<!-- 请按照下列格式报告问题,务必提供复现步骤,否则恕难解决,感谢您的支持。-->
<!--
antd 的用法咨询,建议通过以下渠道,官方 issues 目前没有足够精力提供此类咨询服务:
1. [Stack Overflow](http://stackoverflow.com/questions/tagged/antd)
2. [Segment Fault](https://segmentfault.com/t/antd)(中文)
3. [Gitter](https://gitter.im/ant-design/ant-design)
如果是报告 bug请按照下列格式书写并务必提供复现步骤否则恕难解决感谢您的支持。
-->
#### 发生问题的环境是:
@@ -10,17 +18,17 @@
- 操作系统及其版本:
- 浏览器及其版本:
#### 您做了什么?
#### 您做了什么?请提供尽可能详细的重现步骤。
<!-- 如:引入 antd 了 Button -->
#### 您期待的结果是
#### 您期待的结果是:
<!-- 如:像官网一样正常显示 -->
#### 实际上的结果是
#### 实际上的结果是:
<!-- 如:样式错位了 -->
<!-- 如:样式错位了,最好提供截图 -->
#### 可重现的在线演示

View File

@@ -3,4 +3,4 @@ sudo: false
language: node_js
node_js:
- "5"
- "6"

View File

@@ -9,6 +9,48 @@ If you want to read change logs before `2.0.0`, please visit [GitHub](https://gi
---
## 2.2.0
`2016-10-28`
* Supports TypeScript@2.0. [@AlbertZheng](https://github.com/AlbertZheng) [#3358](https://github.com/ant-design/ant-design/issues/3358)
* Not rely on specific version of React now. [#3627](https://github.com/ant-design/ant-design/pull/3627)
* Alert supports `className` `style`.
* DatePicker & MonthPicker & RangePicker allow developers to set whether to show the clear button. [#3618](https://github.com/ant-design/ant-design/issues/3618)
* Form.Item can generate `validateStatus` & `help` for nested form control automatically. [#3212](https://github.com/ant-design/ant-design/issues/3212)
* RangePicker can set some hours or minutes or seconds to be not selectable. [#](https://ant.design/components/date-picker/#components-date-picker-demo-disabled-date)
* Switch
* The width of Switch will resize automatically, according to `checkedChildren/unCheckedChildren`. [#3380](https://github.com/ant-design/ant-design/issues/3380)
* Improve the switch animation.
* Upload can [customized request](https://github.com/react-component/upload#customrequest) now. [@edgji](https://github.com/edgji)
* Icon
* New icons `bulb` `select` `like-o` `dislike-o`.
* Adjust existing icons `loading` `like` `dislike`.
* Improve the TypeScript definition of Card & DatePicker & Icon & Table. [@infeng](https://github.com/infeng) [3468](https://github.com/ant-design/ant-design/pull/3468) [#3603](https://github.com/ant-design/ant-design/pull/3603) [#3531](https://github.com/ant-design/ant-design/pull/3531)
* Fix Cascader `defaultValue` should work. [#3470](https://github.com/ant-design/ant-design/issues/3470)
* Fix the alignment of Button & Input & DatePicker & Select. [#3481](https://github.com/ant-design/ant-design/issues/3481)
* DatePicker
* Fix wrong timing of triggering `onChange` while `DatePicker[showTime]` is set. [#3523](https://github.com/ant-design/ant-design/issues/3523)
* Fix `Dropdown.Button[disabled]` doesn't works for behaviour. [#3535](https://github.com/ant-design/ant-design/issues/3535)
* Menu
* Fix errors in SSR, thanks to [@xpcode](https://github.com/xpcode) to find the solution. [#2061](https://github.com/ant-design/ant-design/issues/2061) [#2406](https://github.com/ant-design/ant-design/issues/2406) [#3293](https://github.com/ant-design/ant-design/issues/3293)
* Fix children don't support `null`. [#3599](https://github.com/ant-design/ant-design/issues/3599)
* Fix loading status animation for message.[#3536](https://github.com/ant-design/ant-design/issues/3536)
* Form
* Fix style issue while using `Form[inline]` and `Input[addonBefore|addonAfter]` together. [#3524](https://github.com/ant-design/ant-design/issues/3524)
* Fix style issue for Radio.Button in Form.Item.
* Fix style issue for search button in Form.Item. [#3630](https://github.com/ant-design/ant-design/issues/3630)
* Fix Form.Item should not treat no user input as validate success. [#3613](https://github.com/ant-design/ant-design/issues/3613)
* Should not limit the min width of Popover while `Popover[title]` is not set.
* Table
* Fix style of fixed header of Table while `dataSource` is empty.[#3567](https://github.com/ant-design/ant-design/issues/3567)
* Fix Table will overlap SubMenu while `dataSource` is empty. [#3521](https://github.com/ant-design/ant-design/issues/3521)
* Tabs
* Height of header of `Tabs[type="card|editable-card"]` should follow design.
* Fix height of TabPane should follow height of its content. [#3304](https://github.com/ant-design/ant-design/issues/3304)
* Fix style of `TreeSelect[showSearch]`. [#3520](https://github.com/ant-design/ant-design/issues/3520)
## 2.1.0
`2016-10-16`
@@ -108,7 +150,7 @@ There are some breaking changes in `antd@2.0.0`, and you need to modify your cod
// send data to server
}
```
* For the value of time-related components becomes an instance of `moment`, you should replace `type='date'` with `type='object'` in form validation.
* For the value of time-related components becomes an instance of `moment`, you should replace `type: 'date'` with `type: 'object'` in form validation.
* The `format` of time-related components is changed from [gregorian-calendar-format](https://github.com/yiminghe/gregorian-calendar-format#api) to [moment format](http://momentjs.com/docs/#/parsing/string-format/) now, for instance the format `yyyy-MM-dd` should change to `YYYY-MM-DD`.
* `linkRender` and `nameRender` of Breadcrumb are removed, please use `itemRender`.
* `onClose` and `onOpen` of Menu are removed, please use `onOpenChange`. As being totally different, please check [this demo](http://beta.ant.design/components/menu/#components-menu-demo-sider-current) first.

View File

@@ -9,12 +9,54 @@ timeline: true
---
## 2.2.0
`2016-10-28`
* 支持 TypeScript@2.0。[@AlbertZheng](https://github.com/AlbertZheng) [#3358](https://github.com/ant-design/ant-design/issues/3358)
* 不再强依赖于 React 特定版本。[#3627](https://github.com/ant-design/ant-design/pull/3627)
* Alert 支持 `className` `style` 属性。
* DatePicker MonthPicker RangePicker 现在允许设置是否显示清除按钮。[#3618](https://github.com/ant-design/ant-design/issues/3618)
* Form.Item 现在可以感知深层嵌套的表单域,以自动为其生成错误信息和状态。[#3212](https://github.com/ant-design/ant-design/issues/3212)
* RangePicker 现在可以设置不可选的时间。[#](https://ant.design/components/date-picker/#components-date-picker-demo-disabled-date)
* Switch
* 宽度现在会随着 `checkedChildren/unCheckedChildren` 自动调整。[#3380](https://github.com/ant-design/ant-design/issues/3380)
* 优化切换动画。
* Upload 现在可以 [自定义上传方式](https://github.com/react-component/upload#customrequest)。[@edgji](https://github.com/edgji)
* Icon
* 新增 `bulb` `select` `like-o` `dislike-o`
* 调整 `loading` `like` `dislike`
* 优化 Card DatePicker Icon Table 的 TypeScript 定义。[@infeng](https://github.com/infeng) [3468](https://github.com/ant-design/ant-design/pull/3468) [#3603](https://github.com/ant-design/ant-design/pull/3603) [#3531](https://github.com/ant-design/ant-design/pull/3531)
* 修复 Cascader `defaultValue` 失效的问题。[#3470](https://github.com/ant-design/ant-design/issues/3470)
* 修复在一行内同时使用 Button Input DatePicker Select 时对齐的问题。[#3481](https://github.com/ant-design/ant-design/issues/3481)
* DatePicker
* 修复设置 `DatePicker[showTime]``onChange` 事件触发时机问题。[#3523](https://github.com/ant-design/ant-design/issues/3523)
* 修复 Dropdown.Button disabled 后仍然响应操作的问题。[#3535](https://github.com/ant-design/ant-design/issues/3535)
* Menu
* 修复服务端渲染问题,感谢 [@xpcode](https://github.com/xpcode) 定位问题。[#2061](https://github.com/ant-design/ant-design/issues/2061) [#2406](https://github.com/ant-design/ant-design/issues/2406) [#3293](https://github.com/ant-design/ant-design/issues/3293)
* 修复 children 不能为 `null` 的问题。[#3599](https://github.com/ant-design/ant-design/issues/3599)
* 修复 message 加载状态无动画的问题。[#3536](https://github.com/ant-design/ant-design/issues/3536)
* Form
* 修复 `Form[inline]``Input[addonBefore|addonAfter]` 一起使用时的样式问题。[#3524](https://github.com/ant-design/ant-design/issues/3524)
* 修复 Form.Item 内 Radio.Button 样式问题。
* 修复 Form.Item 内搜索按钮的样式问题。[#3630](https://github.com/ant-design/ant-design/issues/3630)
* 修复用户无输入时 Form.Item 识别为校验成功的问题。[#3613](https://github.com/ant-design/ant-design/issues/3613)
*`Popover[title]` 没有设置时,不再限制 Popover 的最小宽度。
* Table
* 修复固定表头在没有数据情况下的样式问题。[#3567](https://github.com/ant-design/ant-design/issues/3567)
* 修复无数据时会覆盖 SubMenu 的问题。[#3521](https://github.com/ant-design/ant-design/issues/3521)
* Tabs
* 修复卡片叶签头部高度与设计稿不一致的问题。
* 修复 TabPane 的高度会被同级 TabPane 撑高的问题。[#3304](https://github.com/ant-design/ant-design/issues/3304)
* 修复 `TreeSelect[showSearch]` 样式问题。[#3520](https://github.com/ant-design/ant-design/issues/3520)
## 2.1.0
`2016-10-16`
- Icon 现在支持旋转动画。
- Tabs 现在可以禁用切换动画。
- Tabs 现在可以禁用切换动画。[#3324](https://github.com/ant-design/ant-design/issues/3324)
- 新增西班牙语的 localization 支持。@Danjavia
- 更新俄语的 localization 文案。@plandem
- 新增 AutoComplete[onSelect] 回调。
@@ -37,12 +79,12 @@ timeline: true
- 修复 Popover 箭头样式问题。
- 修复 Popover 和 Popconfirm 的 `arrowPointAtCenter` 无效的问题。
- Select
- 修复样式重复引入的问题。
- 修复样式重复引入的问题。[#3376](https://github.com/ant-design/ant-design/issues/3376)
- 修复 `notFoundContent` 无法置空的问题。[#3345](https://github.com/ant-design/ant-design/issues/3345)
- 修复 Table 内使用 Select[showSearch] 后宽度会跳动的问题。[#3413](https://github.com/ant-design/ant-design/issues/3413)
- 修复 Table 边框线与页头页脚冲突的问题。[#3301](https://github.com/ant-design/ant-design/issues/3301)
- 修复 TabPane 高度不随内容变化的问题。[#3377](https://github.com/ant-design/ant-design/issues/3377)
- 修复 Transfer[titles] 不受 LocaleProvider 控制的问题。
- 修复 Transfer[titles] 不受 LocaleProvider 控制的问题。[#3264](https://github.com/ant-design/ant-design/pull/3264)
- Upload
- 修复用户自定义 `onRemove` 事件会覆盖默认行为的问题。[#3317](https://github.com/ant-design/ant-design/issues/3317)
- 修复图片卡片样式问题。[#3316](https://github.com/ant-design/ant-design/issues/3316)
@@ -107,7 +149,7 @@ timeline: true
}
```
* 时间类组件与表单校验一起使用时,`type='date'` 改为 `type='object'`。
* 时间类组件与表单校验一起使用时,`type: 'date'` 改为 `type: 'object'`。
* 时间类组件的 `format` 属性也发生了变化,从 [gregorian-calendar-format 的格式](https://github.com/yiminghe/gregorian-calendar-format#api) 变化为与 [moment 的格式](http://momentjs.com/docs/#/parsing/string-format/),例如原来的 `yyyy-MM-dd` 将变为 `YYYY-MM-DD`。
* Breadcrumb 移除 `linkRender` 和 `nameRender`,请使用 `itemRender`。
* Menu 移除 `onClose` `onOpen`,请使用 `onOpenChange`。API 差异较大,请先研究 [demo](http://beta.ant.design/components/menu/#components-menu-demo-sider-current)。

View File

@@ -4,7 +4,13 @@
</a>
</p>
# Ant Design [![](https://img.shields.io/travis/ant-design/ant-design.svg?style=flat-square)](https://travis-ci.org/ant-design/ant-design) [![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)](https://npmjs.org/package/antd) [![Dependency Status](https://david-dm.org/ant-design/ant-design.svg?style=flat-square)](https://david-dm.org/ant-design/ant-design) [![Join the chat at https://gitter.im/ant-design/ant-design](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ant-design/ant-design?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
# Ant Design
[![](https://img.shields.io/travis/ant-design/ant-design.svg?style=flat-square)](https://travis-ci.org/ant-design/ant-design)
[![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)](https://npmjs.org/package/antd)
[![CDNJS](https://img.shields.io/cdnjs/v/antd.svg?style=flat-square)](https://cdnjs.com/libraries/antd)
[![Dependency Status](https://david-dm.org/ant-design/ant-design.svg?style=flat-square)](https://david-dm.org/ant-design/ant-design)
[![Join the chat at https://gitter.im/ant-design/ant-design](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ant-design/ant-design?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
一套企业级的 UI 设计语言和 React 实现。
@@ -13,7 +19,7 @@
- 提炼和服务企业级中后台产品的交互语言和视觉风格。
- [React Component](http://react-component.github.io/badgeboard/) 基础上精心封装的高质量 UI 组件。
- 使用 TypeScript 构建,提供完整的类型定义文件。
- 基于 npm + webpack + babel + dora + [dva](https://github.com/dvajs/dva) 的企业级业务开发框架。
- 基于 npm + webpack + babel + [dora](https://github.com/dora-js/dora) + [dva](https://github.com/dvajs/dva) 的企业级业务开发框架。
## 安装

View File

@@ -4,7 +4,13 @@
</a>
</p>
# Ant Design [![](https://img.shields.io/travis/ant-design/ant-design.svg?style=flat-square)](https://travis-ci.org/ant-design/ant-design) [![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)](https://npmjs.org/package/antd) [![Dependency Status](https://david-dm.org/ant-design/ant-design.svg?style=flat-square)](https://david-dm.org/ant-design/ant-design) [![Join the chat at https://gitter.im/ant-design/ant-design](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ant-design/ant-design?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
# Ant Design
[![](https://img.shields.io/travis/ant-design/ant-design.svg?style=flat-square)](https://travis-ci.org/ant-design/ant-design)
[![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)](https://npmjs.org/package/antd)
[![CDNJS](https://img.shields.io/cdnjs/v/antd.svg?style=flat-square)](https://cdnjs.com/libraries/antd)
[![Dependency Status](https://david-dm.org/ant-design/ant-design.svg?style=flat-square)](https://david-dm.org/ant-design/ant-design)
[![Join the chat at https://gitter.im/ant-design/ant-design](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ant-design/ant-design?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
An enterprise-class UI design language and React-based implementation.
@@ -13,7 +19,7 @@ An enterprise-class UI design language and React-based implementation.
- An enterprise-class design language and high quality UI.
- Graceful UI components out of the box, base on [React Component](http://react-component.github.io/badgeboard/).
- Writen in TypeScript with complete define types.
- A npm + webpack + babel + dora + [dva](https://github.com/dvajs/dva) development framework.
- A npm + webpack + babel + [dora](https://github.com/dora-js/dora) + [dva](https://github.com/dvajs/dva) development framework.
## Install

View File

@@ -1,13 +1,9 @@
import assign from 'object-assign';
export default function getLocale(props, context, component, getDefaultLocale) {
let locale = null;
if (context && context.antLocale && context.antLocale[component]) {
locale = context.antLocale[component];
} else {
locale = getDefaultLocale();
}
// 统一合并为完整的 Locale
export default function getLocale(props, context, componentName, getDefaultLocale) {
const locale = context && context.antLocale && context.antLocale[componentName] ?
context.antLocale[componentName] : getDefaultLocale();
const result = assign({}, locale, props.locale);
result.lang = assign({}, locale.lang, props.locale.lang);
return result;

View File

@@ -1,4 +1,4 @@
export default function getScroll(target, top) {
export default function getScroll(target, top): number {
if (typeof window === 'undefined') {
return 0;
}

View File

@@ -1,6 +1,6 @@
export default function splitObject(obj, parts): Array<any> {
let left = {};
let right = {};
const left = {};
const right = {};
Object.keys(obj).forEach((k) => {
if (parts.indexOf(k) !== -1) {
left[k] = obj[k];

View File

@@ -6,13 +6,13 @@ import shallowequal from 'shallowequal';
import omit from 'omit.js';
import getScroll from '../_util/getScroll';
function getTargetRect(target): any {
function getTargetRect(target): ClientRect {
return target !== window ?
target.getBoundingClientRect() :
{ top: 0, left: 0, bottom: 0 };
}
function getOffset(element, target) {
function getOffset(element: HTMLElement, target) {
const elemRect = element.getBoundingClientRect();
const targetRect = getTargetRect(target);
@@ -31,6 +31,13 @@ function getOffset(element, target) {
};
}
function noop() {}
function getDefaultTarget() {
return typeof window !== 'undefined' ?
window : null;
};
// Affix
export interface AffixProps {
/**
@@ -42,7 +49,7 @@ export interface AffixProps {
offsetBottom?: number;
style?: React.CSSProperties;
/** 固定状态改变时触发的回调函数 */
onChange?: (affixed?: boolean) => any;
onChange?: (affixed?: boolean) => void;
/** 设置 Affix 需要监听其滚动事件的元素,值为一个返回对应 DOM 元素的函数 */
target?: () => Window | HTMLElement;
prefixCls?: string;
@@ -55,19 +62,9 @@ export default class Affix extends React.Component<AffixProps, any> {
target: React.PropTypes.func,
};
static defaultProps = {
target() {
return typeof window !== 'undefined' ?
window : null;
},
onChange() {},
prefixCls: 'ant-affix',
};
scrollEvent: any;
resizeEvent: any;
refs: {
[key: string]: any;
fixedNode: HTMLElement;
};
@@ -80,7 +77,7 @@ export default class Affix extends React.Component<AffixProps, any> {
}
setAffixStyle(e, affixStyle) {
const { onChange, target } = this.props;
const { onChange = noop, target = getDefaultTarget } = this.props;
const originalAffixStyle = this.state.affixStyle;
const isWindow = target() === window;
if (e.type === 'scroll' && originalAffixStyle && affixStyle && isWindow) {
@@ -110,7 +107,7 @@ export default class Affix extends React.Component<AffixProps, any> {
}
updatePosition = (e) => {
let { offsetTop, offsetBottom, offset, target } = this.props;
let { offsetTop, offsetBottom, offset, target = getDefaultTarget } = this.props;
const targetNode = target();
// Backwards support
@@ -124,8 +121,8 @@ export default class Affix extends React.Component<AffixProps, any> {
};
const offsetMode = {
top: null as boolean,
bottom: null as boolean,
top: false,
bottom: false,
};
// Default to `offsetTop=0`.
if (typeof offsetTop !== 'number' && typeof offsetBottom !== 'number') {
@@ -174,7 +171,7 @@ export default class Affix extends React.Component<AffixProps, any> {
}
componentDidMount() {
const target = this.props.target;
const target = this.props.target || getDefaultTarget;
this.setTargetEventListeners(target);
}
@@ -208,7 +205,7 @@ export default class Affix extends React.Component<AffixProps, any> {
render() {
const className = classNames({
[this.props.prefixCls]: this.state.affixStyle,
[this.props.prefixCls || 'ant-affix']: this.state.affixStyle,
});
const props = omit(this.props, ['prefixCls', 'offsetTop', 'offsetBottom', 'target']);

19
components/alert/index.tsx Normal file → Executable file
View File

@@ -4,6 +4,8 @@ import Animate from 'rc-animate';
import Icon from '../icon';
import classNames from 'classnames';
function noop() {}
export interface AlertProps {
/**
* Type of Alert styles, options:`success`, `info`, `warning`, `error`
@@ -18,19 +20,17 @@ export interface AlertProps {
/** Additional content of Alert */
description?: React.ReactNode;
/** Callback when close Alert */
onClose?: (event) => void;
onClose?: React.MouseEventHandler<any>;
/** Whether to show icon */
showIcon?: boolean;
style?: React.CSSProperties;
prefixCls?: string;
className?: string;
banner?: boolean;
}
export default class Alert extends React.Component<AlertProps, any> {
static defaultProps = {
prefixCls: 'ant-alert',
showIcon: false,
onClose() {},
type: 'info',
};
constructor(props) {
@@ -51,7 +51,7 @@ export default class Alert extends React.Component<AlertProps, any> {
this.setState({
closing: false,
});
this.props.onClose(e);
(this.props.onClose || noop)(e);
}
animationEnd = () => {
this.setState({
@@ -61,7 +61,8 @@ export default class Alert extends React.Component<AlertProps, any> {
}
render() {
let {
closable, description, type, prefixCls, message, closeText, showIcon, banner,
closable, description, type, prefixCls = 'ant-alert', message, closeText, showIcon, banner,
className = '', style,
} = this.props;
// banner模式默认有 Icon
@@ -99,6 +100,7 @@ export default class Alert extends React.Component<AlertProps, any> {
[`${prefixCls}-with-description`]: !!description,
[`${prefixCls}-no-icon`]: !showIcon,
[`${prefixCls}-banner`]: !!banner,
[className]: !!className,
});
// closeable when closeText is assigned
@@ -107,12 +109,13 @@ export default class Alert extends React.Component<AlertProps, any> {
}
return this.state.closed ? null : (
<Animate component=""
<Animate
component=""
showProp="data-show"
transitionName={`${prefixCls}-slide-up`}
onEnd={this.animationEnd}
>
<div data-show={this.state.closing} className={alertCls}>
<div data-show={this.state.closing} className={alertCls} style={style}>
{showIcon ? <Icon className={`${prefixCls}-icon`} type={iconType} /> : null}
<span className={`${prefixCls}-message`}>{message}</span>
<span className={`${prefixCls}-description`}>{description}</span>

13
components/auto-complete/index.tsx Normal file → Executable file
View File

@@ -1,5 +1,6 @@
import React from 'react';
import Select, { Option, OptGroup } from '../select';
import Select, { OptionProps, OptGroupProps } from '../select';
import { Option, OptGroup } from 'rc-select';
import classNames from 'classnames';
export interface SelectedValue {
@@ -23,13 +24,13 @@ export interface AutoCompleteProps {
defaultValue?: string | Array<any> | SelectedValue | Array<SelectedValue>;
value?: string | Array<any> | SelectedValue | Array<SelectedValue>;
allowClear?: boolean;
onChange?: (value) => void;
onChange?: (value: string | Array<any> | SelectedValue | Array<SelectedValue>) => void;
disabled?: boolean;
}
export default class AutoComplete extends React.Component<AutoCompleteProps, any> {
static Option = Option;
static OptGroup = OptGroup;
static Option = Option as React.ClassicComponentClass<OptionProps>;
static OptGroup = OptGroup as React.ClassicComponentClass<OptGroupProps>;
static defaultProps = {
prefixCls: 'ant-select',
@@ -45,7 +46,7 @@ export default class AutoComplete extends React.Component<AutoCompleteProps, any
render() {
let {
size, className, notFoundContent, prefixCls, optionLabelProp, dataSource, children,
size, className = '', notFoundContent, prefixCls, optionLabelProp, dataSource, children,
} = this.props;
const cls = classNames({
@@ -55,7 +56,7 @@ export default class AutoComplete extends React.Component<AutoCompleteProps, any
[`${prefixCls}-show-search`]: true,
});
const options = children || (dataSource ? dataSource.map((item, index) => {
const options = children || (dataSource ? dataSource.map((item) => {
switch (typeof item) {
case 'string':
return <Option key={item}>{item}</Option>;

27
components/back-top/index.tsx Normal file → Executable file
View File

@@ -1,9 +1,9 @@
import React from 'react';
import Animate from 'rc-animate';
import Icon from '../icon';
import addEventListener from 'rc-util/lib/Dom/addEventListener';
import classNames from 'classnames';
import omit from 'omit.js';
import Icon from '../icon';
import getScroll from '../_util/getScroll';
import getRequestAnimationFrame from '../_util/getRequestAnimationFrame';
@@ -23,9 +23,16 @@ const easeInOutCubic = (t, b, c, d) => {
}
};
function noop() {}
function getDefaultTarget() {
return typeof window !== 'undefined' ?
window : null;
}
export interface BackTopProps {
visibilityHeight?: number;
onClick?: (event) => void;
onClick?: React.MouseEventHandler<any>;
target?: () => HTMLElement | Window;
prefixCls?: string;
className?: string;
@@ -34,13 +41,7 @@ export interface BackTopProps {
export default class BackTop extends React.Component<BackTopProps, any> {
static defaultProps = {
onClick() {},
visibilityHeight: 400,
target() {
return typeof window !== 'undefined' ?
window : null;
},
prefixCls: 'ant-back-top',
};
scrollEvent: any;
@@ -64,11 +65,11 @@ export default class BackTop extends React.Component<BackTopProps, any> {
}
};
reqAnimFrame(frameFunc);
this.props.onClick(e);
(this.props.onClick || noop)(e);
}
setScrollTop(value) {
const targetNode = this.props.target();
const targetNode = (this.props.target || getDefaultTarget)();
if (targetNode === window) {
document.body.scrollTop = value;
document.documentElement.scrollTop = value;
@@ -78,7 +79,7 @@ export default class BackTop extends React.Component<BackTopProps, any> {
}
handleScroll = () => {
const { visibilityHeight, target } = this.props;
const { visibilityHeight, target = getDefaultTarget } = this.props;
const scrollTop = getScroll(target(), true);
this.setState({
visible: scrollTop > visibilityHeight,
@@ -87,7 +88,7 @@ export default class BackTop extends React.Component<BackTopProps, any> {
componentDidMount() {
this.handleScroll();
this.scrollEvent = addEventListener(this.props.target(), 'scroll', this.handleScroll);
this.scrollEvent = addEventListener((this.props.target || getDefaultTarget)(), 'scroll', this.handleScroll);
}
componentWillUnmount() {
@@ -97,7 +98,7 @@ export default class BackTop extends React.Component<BackTopProps, any> {
}
render() {
const { prefixCls, className, children } = this.props;
const { prefixCls = 'ant-back-top', className = '', children } = this.props;
const classString = classNames({
[prefixCls]: true,
[className]: !!className,

View File

@@ -13,26 +13,25 @@ function getNumberArray(num) {
.map(i => Number(i)) : [];
}
export default class ScrollNumber extends Component<any, any> {
export interface ScrollNumberProps {
prefixCls?: string;
className?: string;
count?: string | number;
component?: string;
onAnimated?: Function;
height?: number;
style: React.CSSProperties;
}
export default class ScrollNumber extends Component<ScrollNumberProps, any> {
static defaultProps = {
prefixCls: 'ant-scroll-number',
count: null,
component: 'sup',
onAnimated() {
},
height: 18,
};
static propTypes = {
count: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.number,
]),
component: React.PropTypes.string,
onAnimated: React.PropTypes.func,
height: React.PropTypes.number,
};
lastCount: any;
constructor(props) {
@@ -85,7 +84,10 @@ export default class ScrollNumber extends Component<any, any> {
animateStarted: false,
count: nextProps.count,
}, () => {
this.props.onAnimated();
const onAnimated = this.props.onAnimated;
if (onAnimated) {
onAnimated();
}
});
}, 5);
});
@@ -93,10 +95,10 @@ export default class ScrollNumber extends Component<any, any> {
}
renderNumberList(position) {
const childrenToReturn = [];
const childrenToReturn: React.ReactElement<any>[] = [];
for (let i = 0; i < 30; i++) {
const currentClassName = (position === i) ? 'current' : null;
childrenToReturn.push(<p key={i} className={currentClassName}>{i % 10}</p>);
const currentClassName = (position === i) ? 'current' : '';
childrenToReturn.push(<p key={i.toString()} className={currentClassName}>{i % 10}</p>);
}
return childrenToReturn;
}
@@ -138,7 +140,7 @@ export default class ScrollNumber extends Component<any, any> {
className: `${this.props.prefixCls} ${this.props.className}`,
});
return createElement(
this.props.component,
this.props.component || 'sup',
props,
this.renderNumberElement()
);

View File

@@ -2,6 +2,7 @@ import React from 'react';
import Animate from 'rc-animate';
import ScrollNumber from './ScrollNumber';
import classNames from 'classnames';
import warning from 'warning';
import splitObject from '../_util/splitObject';
export interface BadgeProps {
@@ -64,6 +65,10 @@ export default class Badge extends React.Component<BadgeProps, any> {
[`${prefixCls}-not-a-wrapper`]: !children,
});
warning(
!(children && status),
'`Badge[children]` and `Badge[status]` cannot be used at the same time.'
);
// <Badge status="success" />
if (!children && status) {
const statusCls = classNames({
@@ -79,7 +84,7 @@ export default class Badge extends React.Component<BadgeProps, any> {
}
return (
<span className={badgeCls} title={count} style={null} {...restProps}>
<span {...restProps} className={badgeCls} title={count}>
{children}
<Animate
component=""

View File

@@ -95,7 +95,7 @@
top: auto;
display: block;
position: relative;
transform: translateX(0);
transform: none!important;
}
}

29
components/breadcrumb/Breadcrumb.tsx Normal file → Executable file
View File

@@ -8,11 +8,11 @@ export interface BreadcrumbProps {
routes?: Array<any>;
params?: Object;
separator?: string | React.ReactNode;
itemRender?: (route, params, routes, paths) => React.ReactNode;
itemRender?: (route: any, params: any, routes: Array<any>, paths: Array<string>) => React.ReactNode;
style?: React.CSSProperties;
};
function getBreadcrumbName(route, params, routes) {
function getBreadcrumbName(route, params) {
if (!route.breadcrumbName) {
return null;
}
@@ -24,19 +24,20 @@ function getBreadcrumbName(route, params, routes) {
return name;
}
function defaultItemRender(route, params, routes, paths) {
const isLastItem = routes.indexOf(route) === routes.length - 1;
const name = getBreadcrumbName(route, params);
return isLastItem
? <span>{name}</span>
: <a href={`#/${paths.join('/')}`}>{name}</a>;
}
export default class Breadcrumb extends React.Component<BreadcrumbProps, any> {
static Item: any;
static defaultProps = {
prefixCls: 'ant-breadcrumb',
separator: '/',
itemRender: (route, params, routes, paths) => {
const isLastItem = routes.indexOf(route) === routes.length - 1;
const name = getBreadcrumbName(route, params, routes);
return isLastItem
? <span>{name}</span>
: <a href={`#/${paths.join('/')}`}>{name}</a>;
},
};
static propTypes = {
@@ -62,12 +63,12 @@ export default class Breadcrumb extends React.Component<BreadcrumbProps, any> {
render() {
let crumbs;
const { separator, prefixCls, routes, params, children, itemRender } = this.props;
const { separator, prefixCls, routes, params = {}, children, itemRender = defaultItemRender } = this.props;
if (routes && routes.length > 0) {
const paths = [];
crumbs = routes.map((route, i) => {
const paths: string[] = [];
crumbs = routes.map((route) => {
route.path = route.path || '';
let path = route.path.replace(/^\//, '');
let path: string = route.path.replace(/^\//, '');
Object.keys(params).forEach(key => {
path = path.replace(`:${key}`, params[key]);
});
@@ -83,7 +84,7 @@ export default class Breadcrumb extends React.Component<BreadcrumbProps, any> {
}
return null;
});
} else {
} else if (children) {
crumbs = React.Children.map(children, (element: any, index) => {
return cloneElement(element, {
separator,

View File

@@ -34,8 +34,8 @@ export interface ButtonProps {
icon?: string;
shape?: ButtonShape;
size?: ButtonSize;
onClick?: React.FormEventHandler;
onMouseUp?: React.FormEventHandler;
onClick?: React.FormEventHandler<any>;
onMouseUp?: React.FormEventHandler<any>;
loading?: boolean;
disabled?: boolean;
style?: React.CSSProperties;
@@ -48,7 +48,6 @@ export default class Button extends React.Component<ButtonProps, any> {
static defaultProps = {
prefixCls: 'ant-btn',
onClick() {},
loading: false,
};
@@ -87,7 +86,10 @@ export default class Button extends React.Component<ButtonProps, any> {
clearTimeout(this.timeout);
this.timeout = setTimeout(() => this.clearButton(buttonNode), 500);
this.props.onClick(e);
const onClick = this.props.onClick;
if (onClick) {
onClick(e);
}
}
// Handle auto focus when click button in Chrome

View File

@@ -77,7 +77,6 @@
vertical-align: middle;
> .@{btnClassName} {
position: relative;
float: left;
&:hover,
&:focus,
&:active,
@@ -106,7 +105,6 @@
margin-bottom: 0;
font-weight: @btn-font-weight;
text-align: center;
vertical-align: middle;
touch-action: manipulation;
cursor: pointer;
background-image: none;

View File

@@ -1,12 +1,10 @@
import React from 'react';
import { PropTypes } from 'react';
import moment from 'moment';
import { PREFIX_CLS } from './Constants';
import Select from '../select';
import { Group, Button } from '../radio';
const Option = Select.Option;
function noop() {}
export interface HeaderProps {
prefixCls?: string;
locale?: any;
@@ -24,21 +22,6 @@ export default class Header extends React.Component<HeaderProps, any> {
prefixCls: `${PREFIX_CLS}-header`,
yearSelectOffset: 10,
yearSelectTotal: 20,
onValueChange: noop,
onTypeChange: noop,
};
static propTypes = {
value: PropTypes.object,
locale: PropTypes.object,
yearSelectOffset: PropTypes.number,
yearSelectTotal: PropTypes.number,
onValueChange: PropTypes.func,
onTypeChange: PropTypes.func,
prefixCls: PropTypes.string,
selectPrefixCls: PropTypes.string,
type: PropTypes.string,
fullscreen: PropTypes.bool,
};
getYearSelectElement(year) {
@@ -47,13 +30,13 @@ export default class Header extends React.Component<HeaderProps, any> {
const end = start + yearSelectTotal;
const suffix = locale.year === '年' ? '年' : '';
const options = [];
const options: React.ReactElement<any>[] = [];
for (let index = start; index < end; index++) {
options.push(<Option key={`${index}`}>{index + suffix}</Option>);
}
return (
<Select
size={fullscreen ? null : 'small'}
size={fullscreen ? 'default' : 'small'}
dropdownMatchSelectWidth={false}
className={`${prefixCls}-year-select`}
onChange={this.onYearChange}
@@ -64,10 +47,10 @@ export default class Header extends React.Component<HeaderProps, any> {
);
}
getMonthsLocale(value) {
getMonthsLocale(value: moment.Moment) {
const current = value.clone();
const localeData = value.localeData();
const months = [];
const months: any[] = [];
for (let i = 0; i < 12; i++) {
current.month(i);
months.push(localeData.monthsShort(current));
@@ -78,7 +61,7 @@ export default class Header extends React.Component<HeaderProps, any> {
getMonthSelectElement(month, months) {
const props = this.props;
const { prefixCls, fullscreen } = props;
const options = [];
const options: React.ReactElement<any>[] = [];
for (let index = 0; index < 12; index++) {
options.push(<Option key={`${index}`}>{months[index]}</Option>);
@@ -86,7 +69,7 @@ export default class Header extends React.Component<HeaderProps, any> {
return (
<Select
size={fullscreen ? null : 'small'}
size={fullscreen ? 'default' : 'small'}
dropdownMatchSelectWidth={false}
className={`${prefixCls}-month-select`}
value={String(month)}
@@ -100,17 +83,27 @@ export default class Header extends React.Component<HeaderProps, any> {
onYearChange = (year) => {
const newValue = this.props.value.clone();
newValue.year(parseInt(year, 10));
this.props.onValueChange(newValue);
const onValueChange = this.props.onValueChange;
if (onValueChange) {
onValueChange(newValue);
}
}
onMonthChange = (month) => {
const newValue = this.props.value.clone();
newValue.month(parseInt(month, 10));
this.props.onValueChange(newValue);
const onValueChange = this.props.onValueChange;
if (onValueChange) {
onValueChange(newValue);
}
}
onTypeChange = (e) => {
this.props.onTypeChange(e.target.value);
const onTypeChange = this.props.onTypeChange;
if (onTypeChange) {
onTypeChange(e.target.value);
}
}
render() {

View File

@@ -38,12 +38,9 @@ export interface CalendarProps {
export default class Calendar extends React.Component<CalendarProps, any> {
static defaultProps = {
monthCellRender: noop,
dateCellRender: noop,
locale: {},
fullscreen: true,
prefixCls: PREFIX_CLS,
onPanelChange: noop,
mode: 'month',
};
@@ -82,28 +79,28 @@ export default class Calendar extends React.Component<CalendarProps, any> {
}
monthCellRender = (value) => {
const prefixCls = this.props.prefixCls;
const { prefixCls, monthCellRender = noop as Function } = this.props;
return (
<div className={`${prefixCls}-month`}>
<div className={`${prefixCls}-value`}>
{value.localeData().monthsShort(value)}
</div>
<div className={`${prefixCls}-content`}>
{this.props.monthCellRender(value)}
{monthCellRender(value)}
</div>
</div>
);
}
dateCellRender = (value) => {
const prefixCls = this.props.prefixCls;
const { prefixCls, dateCellRender = noop as Function } = this.props;
return (
<div className={`${prefixCls}-date`}>
<div className={`${prefixCls}-value`}>
{zerofixed(value.date())}
</div>
<div className={`${prefixCls}-content`}>
{this.props.dateCellRender(value)}
{dateCellRender(value)}
</div>
</div>
);
@@ -113,14 +110,20 @@ export default class Calendar extends React.Component<CalendarProps, any> {
if (!('value' in this.props) && this.state.value !== value) {
this.setState({ value });
}
this.props.onPanelChange(value, this.state.mode);
const onPanelChange = this.props.onPanelChange;
if (onPanelChange) {
onPanelChange(value, this.state.mode);
}
}
setType = (type) => {
const mode = (type === 'date') ? 'month' : 'year';
if (this.state.mode !== mode) {
this.setState({ mode });
this.props.onPanelChange(this.state.value, mode);
const onPanelChange = this.props.onPanelChange;
if (onPanelChange) {
onPanelChange(this.state.value, mode);
}
}
}
@@ -130,7 +133,7 @@ export default class Calendar extends React.Component<CalendarProps, any> {
const { prefixCls, style, className, fullscreen } = props;
const type = (mode === 'year') ? 'month' : 'date';
const locale = getLocale(
this.props, this.context, 'Calendar',
props, this.context, 'Calendar',
() => require('./locale/zh_CN')
);

View File

@@ -11,6 +11,7 @@ export interface CardProps {
loading?: boolean;
children?: any;
id?: string;
className?: string;
}
export default (props: CardProps) => {

View File

@@ -38,6 +38,7 @@ Cascade selection box.
| changeOnSelect | change value on each selection if set to true, see above demo for details | boolean | false |
| showSearch | Whether show search input in single mode. | Boolean or Object | false |
| notFoundContent | Specify content to show when no result matches. | String | 'Not Found' |
| getPopupContainer | Parent Node which the selector should be rendered to. Default to `body`. When position issues happen, try to modify it into scrollable content and position it relative.[example](http://codepen.io/anon/pen/xVBOVQ?editors=001) | Function(triggerNode) | () => document.body |
Fields in `showSearch`:

View File

@@ -89,6 +89,8 @@ function defaultSortFilteredOption(a, b, inputValue) {
return a.findIndex(callback) - b.findIndex(callback);
}
const defaultDisplayRender = label => label.join(' / ');
export default class Cascader extends React.Component<CascaderProps, any> {
static defaultProps = {
prefixCls: 'ant-cascader',
@@ -96,14 +98,11 @@ export default class Cascader extends React.Component<CascaderProps, any> {
placeholder: 'Please select',
transitionName: 'slide-up',
popupPlacement: 'bottomLeft',
onChange() {},
options: [],
displayRender: label => label.join(' / '),
disabled: false,
allowClear: true,
showSearch: false,
notFoundContent: 'Not Found',
onPopupVisibleChange() {},
};
cachedOptions: CascaderOptionType[];
@@ -117,7 +116,7 @@ export default class Cascader extends React.Component<CascaderProps, any> {
constructor(props) {
super(props);
this.state = {
value: props.value || props.defautValue || [],
value: props.value || props.defaultValue || [],
inputValue: '',
inputFocused: false,
popupVisible: false,
@@ -146,7 +145,11 @@ export default class Cascader extends React.Component<CascaderProps, any> {
inputFocused: popupVisible,
inputValue: popupVisible ? this.state.inputValue : '',
});
this.props.onPopupVisibleChange(popupVisible);
const onPopupVisibleChange = this.props.onPopupVisibleChange;
if (onPopupVisibleChange) {
onPopupVisibleChange(popupVisible);
}
}
handleInputBlur = () => {
@@ -173,11 +176,14 @@ export default class Cascader extends React.Component<CascaderProps, any> {
if (!('value' in this.props)) {
this.setState({ value });
}
this.props.onChange(value, selectedOptions);
const onChange = this.props.onChange;
if (onChange) {
onChange(value, selectedOptions);
}
}
getLabel() {
const { options, displayRender } = this.props;
const { options, displayRender = defaultDisplayRender as Function } = this.props;
const value = this.state.value;
const unwrappedValue = Array.isArray(value[0]) ? value[0] : value;
const selectedOptions = arrayTreeFilter(options, (o, level) => o.value === unwrappedValue[level]);
@@ -197,7 +203,7 @@ export default class Cascader extends React.Component<CascaderProps, any> {
}
flattenTree(options, changeOnSelect, ancestor = []) {
let flattenOptions = [];
let flattenOptions: any = [];
options.forEach((option) => {
const path = ancestor.concat(option);
if (changeOnSelect || !option.children) {
@@ -293,10 +299,7 @@ export default class Cascader extends React.Component<CascaderProps, any> {
this.cachedOptions = options;
}
const dropdownMenuColumnStyle = {
width: undefined,
height: undefined,
};
const dropdownMenuColumnStyle: { width?: number, height?: string } = {};
const isNotFound = (options || []).length === 1 && options[0].value === 'ANT_CASCADER_NOT_FOUND';
if (isNotFound) {
dropdownMenuColumnStyle.height = 'auto'; // Height of one row.
@@ -307,7 +310,8 @@ export default class Cascader extends React.Component<CascaderProps, any> {
dropdownMenuColumnStyle.width = this.refs.input.refs.input.offsetWidth;
}
return (
<RcCascader {...props}
<RcCascader
{...props}
options={options}
value={value}
popupVisible={state.popupVisible}
@@ -320,7 +324,8 @@ export default class Cascader extends React.Component<CascaderProps, any> {
style={style}
className={pickerCls}
>
<Input {...inputProps}
<Input
{...inputProps}
ref="input"
placeholder={value && value.length > 0 ? null : placeholder}
className={`${prefixCls}-input ${sizeCls}`}
@@ -328,11 +333,13 @@ export default class Cascader extends React.Component<CascaderProps, any> {
disabled={disabled}
readOnly={!showSearch}
autoComplete="off"
onClick={showSearch ? this.handleInputClick : null}
onBlur={showSearch ? this.handleInputBlur : null}
onChange={showSearch ? this.handleInputChange : null}
onClick={showSearch ? this.handleInputClick : undefined}
onBlur={showSearch ? this.handleInputBlur : undefined}
onChange={showSearch ? this.handleInputChange : undefined}
/>
<span className={`${prefixCls}-picker-label`}>{this.getLabel()}</span>
<span className={`${prefixCls}-picker-label`}>
{this.getLabel()}
</span>
{clearIcon}
<Icon type="down" className={arrowCls} />
</span>

View File

@@ -39,6 +39,7 @@ subtitle: 级联选择
| changeOnSelect | 当此项为 true 时,点选每级菜单选项值都会发生变化,具体见上面的演示 | Boolean | false |
| showSearch | 在选择框中显示搜索框 | Boolean | false |
| notFoundContent | 当下拉列表为空时显示的内容 | String | 'Not Found' |
| getPopupContainer | 菜单渲染父节点。默认渲染到 body 上,如果你遇到菜单滚动定位问题,试试修改为滚动的区域,并相对其定位。[示例](http://codepen.io/anon/pen/xVBOVQ?editors=001) | Function(triggerNode) | () => document.body |
`showSearch` 为对象时,其中的字段:

View File

@@ -1,6 +1,6 @@
import React from 'react';
import Checkbox from './index';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import PureRenderMixin from 'rc-util/lib/PureRenderMixin';
export interface CheckboxOptionType {
label: string;
@@ -29,7 +29,6 @@ export interface CheckboxGroupState {
export default class CheckboxGroup extends React.Component<CheckboxGroupProps, CheckboxGroupState> {
static defaultProps = {
options: [],
onChange() {},
prefixCls: 'ant-checkbox-group',
};
static propTypes = {
@@ -78,7 +77,10 @@ export default class CheckboxGroup extends React.Component<CheckboxGroupProps, C
if (!('value' in this.props)) {
this.setState({ value });
}
this.props.onChange(value);
const onChange = this.props.onChange;
if (onChange) {
onChange(value);
}
}
render() {
const { prefixCls } = this.props;

View File

@@ -2,7 +2,7 @@ import RcCheckbox from 'rc-checkbox';
import React from 'react';
import CheckboxGroup from './Group';
import classNames from 'classnames';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import PureRenderMixin from 'rc-util/lib/PureRenderMixin';
import splitObject from '../_util/splitObject';
export interface CheckboxProps {
@@ -13,7 +13,7 @@ export interface CheckboxProps {
/** indeterminate 状态,只负责样式控制 */
indeterminate?: boolean;
/** 变化时回调函数 */
onChange?: React.FormEventHandler;
onChange?: React.FormEventHandler<any>;
style?: React.CSSProperties;
disabled?: boolean;
className?: string;

View File

@@ -8,6 +8,7 @@ import Icon from '../icon';
export default class RangePicker extends React.Component<any, any> {
static defaultProps = {
prefixCls: 'ant-calendar',
allowClear: true,
};
constructor(props) {
@@ -45,7 +46,7 @@ export default class RangePicker extends React.Component<any, any> {
render() {
const props = this.props;
const { disabledDate, showTime, prefixCls, popupStyle, style, onOk, locale } = props;
const { disabledDate, disabledTime, showTime, prefixCls, popupStyle, style, onOk, locale } = props;
const state = this.state;
const calendarClassName = classNames({
@@ -77,6 +78,7 @@ export default class RangePicker extends React.Component<any, any> {
className={calendarClassName}
timePicker={props.timePicker}
disabledDate={disabledDate}
disabledTime={disabledTime}
dateInputPlaceholder={[startPlaceholder, endPlaceholder]}
locale={locale.lang}
onOk={onOk}
@@ -84,7 +86,7 @@ export default class RangePicker extends React.Component<any, any> {
/>
);
const clearIcon = (!props.disabled && state.value && (state.value[0] || state.value[1]))
const clearIcon = (!props.disabled && props.allowClear && state.value && (state.value[0] || state.value[1]))
? <Icon
type="cross-circle"
className={`${prefixCls}-picker-clear`}

View File

@@ -4,6 +4,7 @@ import MonthCalendar from 'rc-calendar/lib/MonthCalendar';
import RcDatePicker from 'rc-calendar/lib/Picker';
import classNames from 'classnames';
import assign from 'object-assign';
import omit from 'omit.js';
import Icon from '../icon';
export interface PickerProps {
@@ -13,10 +14,11 @@ export interface PickerProps {
export default function createPicker(TheCalendar) {
// use class typescript error
const CalenderWrapper = React.createClass({
const CalenderWrapper = React.createClass<any, any>({
getDefaultProps() {
return {
prefixCls: 'ant-calendar',
allowClear: true,
};
},
@@ -24,6 +26,7 @@ export default function createPicker(TheCalendar) {
const props = this.props;
return {
value: props.value || props.defaultValue,
tempValue: undefined,
};
},
@@ -50,8 +53,26 @@ export default function createPicker(TheCalendar) {
props.onChange(value, (value && value.format(props.format)) || '');
},
handleTempChange(tempValue) {
if (!('value' in this.props)) {
this.setState({ tempValue });
}
},
// Clear temp value when hide picker panel
handleOpenChange(open) {
if (!open) {
this.setState({
tempValue: undefined,
});
}
if (this.props.onOpenChange) {
this.props.onOpenChange(open);
}
},
render() {
const props = this.props;
const props = omit(this.props, ['onChange']);
const prefixCls = props.prefixCls;
const locale = props.locale;
@@ -66,22 +87,24 @@ export default function createPicker(TheCalendar) {
});
// 需要选择时间时,点击 ok 时才触发 onChange
let pickerChangeHandler: Object = {
onChange: this.handleChange,
};
let calendarHandler: Object = {
onOk: this.handleChange,
// fix https://github.com/ant-design/ant-design/issues/1902
onSelect: (value, cause) => {
if (!('value' in this.props)) {
this.setState({ value });
}
},
};
let pickerChangeHandler: Object = {};
let calendarHandler: Object = {};
if (props.showTime) {
pickerChangeHandler = {};
calendarHandler = {
onOk: this.handleChange,
// fix https://github.com/ant-design/ant-design/issues/1902
onSelect: (value, cause) => {
if (cause && cause.source === 'todayButton') {
this.handleChange(value);
} else {
this.handleTempChange(value);
}
},
};
} else {
calendarHandler = {};
pickerChangeHandler = {
onChange: this.handleChange,
};
}
const calendar = (
@@ -101,12 +124,12 @@ export default function createPicker(TheCalendar) {
);
// default width for showTime
const pickerStyle = { width: undefined };
const pickerStyle: { width?: number } = {};
if (props.showTime) {
pickerStyle.width = 180;
}
const clearIcon = (!props.disabled && this.state.value) ?
const clearIcon = (!props.disabled && props.allowClear && this.state.value) ?
<Icon type="cross-circle"
className={`${prefixCls}-picker-clear`}
onClick={this.clearSelection}
@@ -116,8 +139,9 @@ export default function createPicker(TheCalendar) {
<RcDatePicker
{...props}
{...pickerChangeHandler}
onOpenChange={this.handleOpenChange}
calendar={calendar}
value={this.state.value}
value={this.state.tempValue || this.state.value}
prefixCls={`${prefixCls}-picker-container`}
style={props.popupStyle}
>

View File

@@ -8,6 +8,7 @@ title:
## zh-CN
设置 `disabledDate` 方法,来确定不可选时段。
设置 `disabledTime` 方法,来确定 showTime 的 RangePicker 的不可选时间段。
如上例:不可选择今天之后的日期。
@@ -19,13 +20,54 @@ As in the example above: you can't select a date later than today.
````jsx
import { DatePicker } from 'antd';
const RangePicker = DatePicker.RangePicker;
function newArray(start, end) {
const result = [];
for (let i = start; i < end; i++) {
result.push(i);
}
return result;
}
const disabledDate = function (current) {
// can not select days after today
return current && current.valueOf() > Date.now();
};
ReactDOM.render(
<DatePicker disabledDate={disabledDate} />
function disabledTime(time, type) {
console.log('disabledTime', time, type);
if (type === 'start') {
return {
disabledHours() {
return newArray(0, 60).splice(4, 20);
},
disabledMinutes() {
return newArray(30, 60);
},
disabledSeconds() {
return [55, 56];
},
};
}
return {
disabledHours() {
return newArray(0, 60).splice(20, 4);
},
disabledMinutes() {
return newArray(0, 31);
},
disabledSeconds() {
return [55, 56];
},
};
}
ReactDOM.render(<div>
<DatePicker disabledDate={disabledDate} />
<br />
<RangePicker showTime disabledDate={disabledDate} disabledTime={disabledTime} />
</div>
, mountNode);
````

View File

@@ -16,8 +16,9 @@ This property provide an additional time selection. When `showTime` is an Object
````jsx
import { DatePicker } from 'antd';
function onChange(value) {
function onChange(value, dateString) {
console.log('Selected Time: ', value);
console.log('Formatted Selected Time: ', dateString);
}
ReactDOM.render(

View File

@@ -1,68 +0,0 @@
---
order: 4
hidden: true
title:
zh-CN: 日期时间选择二
en-US: To select a date, case 2
---
## zh-CN
和 <a href="/components/time-picker">时间选择框</a> 配合使用。
## en-US
Cooperate with `<a href="/components/time-picker">time-picker</a>`
````jsx
import { DatePicker, TimePicker } from 'antd';
const DateTimePicker = React.createClass({
handleChange(from, value) {
this.result = this.result || new Date();
if (!value) {
if (from === 'date') {
this.selectedDate = false;
} else {
this.selectedTime = false;
}
return;
}
if (from === 'date') {
this.result.setFullYear(value.getFullYear());
this.result.setMonth(value.getMonth());
this.result.setDate(value.getDate());
this.selectedDate = true;
} else {
this.result.setHours(value.getHours());
this.result.setMinutes(value.getMinutes());
this.result.setSeconds(value.getSeconds());
this.selectedTime = true;
}
if (this.selectedDate && this.selectedTime) {
this.props.onSelect(this.result);
}
},
handleDateChange(value) {
this.handleChange('date', value);
},
handleTimeChange(value) {
this.handleChange('time', value);
},
render() {
return (
<div>
<DatePicker onChange={this.handleDateChange} />
<TimePicker onChange={this.handleTimeChange} />
</div>
);
},
});
function onSelect(value) {
console.log('选择了时间:', value);
}
ReactDOM.render(<DateTimePicker onSelect={onSelect} />
, mountNode);
````

View File

@@ -12,7 +12,7 @@ By clicking the input box, you can select a date from a popup calendar.
## API
### DatePicker
Note: Part of locale of DatePicker, MonthPicker, RangePicker is read from value. So, please set the locale of moment correctly.
```jsx
import moment from 'moment-timezone/moment-timezone';
@@ -27,22 +27,31 @@ moment.tz.setDefault('Asia/Shanghai')
<DatePicker defaultValue={moment('2015-01-01', 'YYYY-MM-DD')} />
```
| Property | Description | Type | Default |
### Common API
The following APIs are shared by DatePicker, MonthPicker, RangePicker.
| Property | Description | Type | Default |
|--------------|----------------|----------|--------------|
| value | to set date | [moment](http://momentjs.com/) | - |
| defaultValue | to set default date | [moment](http://momentjs.com/) | - |
| format | to set the date format, refer to [moment.js](http://momentjs.com/) | String | "YYYY-MM-DD" |
| disabledDate | to specify the date that cannot be selected | function | - |
| onChange | a callback function, can be executed when the selected time is changing | function(date: moment, dateString: string) | - |
| allowClear | Whether to show clear button | bool | true |
| disabled | determine whether the DatePicker is disabled | Boolean | false |
| style | to customize the style of the input box | Object | {} |
| popupStyle | to customize the style of the popup calendar | Object | {} |
| size | determine the size of the input box, the height of `large` and `small`, are 32px and 22px respectively, while default size is 28px | String | - |
| locale | localization configuration | Object | [default](https://github.com/ant-design/ant-design/issues/424) |
| onOk | a callback function, can be executed when OK-button is clicked | function(Date value) | - |
| disabledDate | to specify the date that cannot be selected | function | - |
| getCalendarContainer | to set the container of the floating layer, while the default is to create a `div` element in `body` | function(trigger) | - |
### DatePicker
| Property | Description | Type | Default |
|--------------|----------------|----------|--------------|
| value | to set date | [moment](http://momentjs.com/) | - |
| defaultValue | to set default date | [moment](http://momentjs.com/) | - |
| format | to set the date format, refer to [moment.js](http://momentjs.com/) | String | "YYYY-MM-DD" |
| onChange | a callback function, can be executed when the selected time is changing | function(date: moment, dateString: string) | - |
| open | open state of picker | bool | - |
| onOpenChange | a callback function, can be executed whether the popup calendar is popped up or closed | function(status) | - |
| getCalendarContainer | to set the container of the floating layer, while the default is to create a `div` element in `body` | function(trigger) | - |
| showTime | to provide an additional time selection | Object/Boolean | [TimePicker Options](/components/time-picker/#api) |
### MonthPicker
@@ -52,27 +61,18 @@ moment.tz.setDefault('Asia/Shanghai')
| value | to set date | [moment](http://momentjs.com/) | - |
| defaultValue | to set default date | [moment](http://momentjs.com/) | - |
| format | to set the date format, refer to [moment.js](http://momentjs.com/) | String | "YYYY-MM" |
| disabledDate | to specify the date that cannot be selected | function | - |
| onChange | a callback function, can be executed when the selected time is changing | function(date: moment, dateString: string) | - |
| disabled | determine whether the MonthPicker is disabled | Boolean | false |
| style | to customize the style of the input box | Object | {} |
| popupStyle | to customize the style of the popup calendar | Object | {} |
| size | determine the size of the input box, the height of `large` and `small`, are 32px and 22px respectively, while default size is 28px | String | - |
| locale | localization configuration | Object | [default](https://github.com/ant-design/ant-design/issues/424) |
| getCalendarContainer | to set the container of the floating layer, while the default is to create a `div` element in `body` | function(trigger) | - |
### RangePicker
| Property | Description | Type | Default |
|--------------|----------------|----------|--------------|
| value | to set date | [moment, moment] | - |
| defaultValue | to set default date | [moment, moment] | - |
| value | to set date | [[moment](http://momentjs.com/), [moment](http://momentjs.com/)] | - |
| defaultValue | to set default date | [[moment](http://momentjs.com/), [moment](http://momentjs.com/)] | - |
| format | to set the date format | String | "YYYY-MM-DD HH:mm:ss" |
| onChange | a callback function, can be executed when the selected time is changing | function(dates: [moment, moment], dateStrings: [string, string]) | - |
| showTime | to provide an additional time selection | Object/Boolean | [TimePicker Options](/components/time-picker/#api) |
The following properties are the same with `DatePicker`: `disabled` `style` `popupStyle` `size` `locale` `showTime` `onOk` `getCalendarContainer`
| disabledTime | to specify the time that cannot be selected | function(dates: [moment, moment], partial: `'start'|'end'`) | - |
<style>
.code-box-demo .ant-calendar-picker {

21
components/date-picker/index.tsx Normal file → Executable file
View File

@@ -10,15 +10,16 @@ import Calendar from './Calendar';
import { TimePickerProps } from '../time-picker';
export interface PickerProps {
prefixCls?: string;
inputPrefixCls?: string;
format?: string;
disabled?: boolean;
allowClear?: boolean;
style?: React.CSSProperties;
popupStyle?: React.CSSProperties;
locale?: any;
size?: 'large' | 'small' | 'default';
getCalendarContainer?: (trigger) => React.ReactNode;
prefixCls?: string;
inputPrefixCls?: string;
getCalendarContainer?: (trigger: any) => React.ReactNode;
}
export interface SinglePickerProps {
@@ -32,12 +33,15 @@ export interface DatePickerProps extends PickerProps, SinglePickerProps {
showTime?: TimePickerProps | boolean;
open?: boolean;
toggleOpen?: (e: {open: boolean}) => void;
disabledDate?: (current: moment.Moment) => boolean;
onOpenChange?: (status: boolean) => void;
}
const DatePicker = wrapPicker(createPicker(RcCalendar)) as React.ClassicComponentClass<DatePickerProps>;
export interface MonthPickerProps extends PickerProps, SinglePickerProps {
disabledDate?: (current: moment.Moment) => boolean;
}
const MonthPicker = wrapPicker(createPicker(MonthCalendar), 'YYYY-MM') as React.ClassicComponentClass<MonthPickerProps>;
const MonthPicker = wrapPicker(createPicker(MonthCalendar), 'YYYY-MM');
export interface RangePickerProps extends PickerProps {
value?: [moment.Moment, moment.Moment];
@@ -48,9 +52,14 @@ export interface RangePickerProps extends PickerProps {
}
assign(DatePicker, {
RangePicker: wrapPicker(RangePicker) as React.ClassicComponentClass<RangePickerProps>,
RangePicker: wrapPicker(RangePicker),
Calendar,
MonthPicker,
});
export default DatePicker;
export interface DatePickerDecorator extends React.ClassicComponentClass<DatePickerProps> {
RangePicker: React.ClassicComponentClass<RangePickerProps>;
MonthPicker: React.ClassicComponentClass<MonthPickerProps>;
}
export default DatePicker as DatePickerDecorator;

View File

@@ -13,7 +13,7 @@ subtitle: 日期选择框
## API
### DatePicker
注意:DatePicker、MonthPicker、RangePicker 部分 locale 是从 value 中读取,所以请先正确设置 moment 的 locale。
```jsx
import moment from 'moment-timezone/moment-timezone';
@@ -28,50 +28,52 @@ moment.tz.setDefault('Asia/Shanghai')
<DatePicker defaultValue={moment('2015-01-01', 'YYYY-MM-DD')} />
```
| 参数 | 说明 | 类型 | 默认值 |
### 共同的 API
以下 API 为 DatePicker、MonthPicker、RangePicker 共享的 API。
| 参数 | 说明 | 类型 | 默认值 |
|--------------|----------------|----------|--------------|
| value | 日期 | [moment](http://momentjs.com/) | 无 |
| defaultValue | 默认日期 | [moment](http://momentjs.com/) | 无 |
| format | 展示的日期格式,配置参考 [moment.js](http://momentjs.com/) | string | "YYYY-MM-DD" |
| disabledDate | 不可选择的日期 | function | 无 |
| onChange | 时间发生变化的回调 | function(date: moment, dateString: string) | 无 |
| allowClear | 是否显示清除按钮 | bool | true |
| disabled | 禁用 | bool | false |
| style | 自定义输入框样式 | object | {} |
| popupStyle | 格外的弹出日历样式 | object | {} |
| size | 输入框大小,`large` 高度为 32px`small` 为 22px默认是 28px | string | 无 |
| locale | 国际化配置 | object | [默认配置](https://github.com/ant-design/ant-design/issues/424) |
| disabledDate | 不可选择的日期 | function | 无 |
| getCalendarContainer | 定义浮层的容器,默认为 body 上新建 div | function(trigger) | 无 |
### DatePicker
| 参数 | 说明 | 类型 | 默认值 |
|--------------|----------------|----------|--------------|
| value | 日期 | [moment](http://momentjs.com/) | 无 |
| defaultValue | 默认日期 | [moment](http://momentjs.com/) | 无 |
| format | 展示的日期格式,配置参考 [moment.js](http://momentjs.com/) | string | "YYYY-MM-DD" |
| onChange | 时间发生变化的回调 | function(date: moment, dateString: string) | 无 |
| open | 控制弹层是否展开 | bool | - |
| onOpenChange | 弹出日历和关闭日历的回调 | function(status) | 无 |
| getCalendarContainer | 定义浮层的容器,默认为 body 上新建 div | function(trigger) | 无 |
| showTime | 增加时间选择功能 | Object or Boolean | [TimePicker Options](/components/time-picker/#api) |
### MonthPicker
| 参数 | 说明 | 类型 | 默认值 |
|--------------|----------------|----------|--------------|
| value | 日期 | moment | 无 |
| defaultValue | 默认日期 | moment | 无 |
| value | 日期 | [moment](http://momentjs.com/) | 无 |
| defaultValue | 默认日期 | [moment](http://momentjs.com/) | 无 |
| format | 展示的日期格式,配置参考 [moment.js](http://momentjs.com/) | string | "YYYY-MM" |
| disabledDate | 不可选择的日期 | function | 无 |
| onChange | 时间发生变化的回调,发生在用户选择时间时 | function(date: moment, dateString: string) | 无 |
| disabled | 禁用 | bool | false |
| style | 自定义输入框样式 | object | {} |
| popupStyle | 格外的弹出日历样式 | object | {} |
| size | 输入框大小,`large` 高度为 32px`small` 为 22px默认是 28px | string | 无 |
| locale | 国际化配置 | object | [默认配置](https://github.com/ant-design/ant-design/issues/424) |
| getCalendarContainer | 定义浮层的容器,默认为 body 上新建 div | function(trigger) | 无 |
### RangePicker
| 参数 | 说明 | 类型 | 默认值 |
|--------------|----------------|----------|--------------|
| value | 日期 | [moment, moment] | 无 |
| defaultValue | 默认日期 | [moment, moment] | 无 |
| value | 日期 | [[moment](http://momentjs.com/), [moment](http://momentjs.com/)] | 无 |
| defaultValue | 默认日期 | [[moment](http://momentjs.com/), [moment](http://momentjs.com/)] | 无 |
| format | 展示的日期格式 | string | "YYYY-MM-DD HH:mm:ss" |
| onChange | 时间发生变化的回调,发生在用户选择时间时 | function(dates: [moment, moment], dateStrings: [string, string]) | 无 |
| showTime | 增加时间选择功能 | Object or Boolean | [TimePicker Options](/components/time-picker/#api) |
`disabled` `style` `popupStyle` `size` `locale` `showTime` `onOk` `getCalendarContainer` 属性与 DatePicker 的一致。
| disabledTime | 不可选择的时间 | function(dates: [moment, moment], partial: `'start'|'end'`) | 无 |
<style>
.code-box-demo .ant-calendar-picker {

View File

@@ -60,7 +60,7 @@ export default function wrapPicker(Picker, defaultFormat?) {
});
const locale = getLocale(
this.props, this.context, 'DatePicker',
props, this.context, 'DatePicker',
() => require('./locale/zh_CN')
);

View File

@@ -8,7 +8,7 @@ import splitObject from '../_util/splitObject';
export interface DropdownButtonProps {
type?: 'primary' | 'ghost' | 'dash';
onClick?: React.FormEventHandler;
onClick?: React.FormEventHandler<any>;
trigger?: 'click' | 'hover';
overlay: React.ReactNode;
visible?: boolean;
@@ -44,7 +44,7 @@ export default class DropdownButton extends React.Component<DropdownButtonProps,
return (
<ButtonGroup {...restProps} className={cls}>
<Button type={type} onClick={onClick} disabled={disabled}>{children}</Button>
<Dropdown align={align} overlay={overlay} trigger={trigger}>
<Dropdown align={align} overlay={overlay} trigger={disabled ? [] : trigger}>
<Button type={type} disabled={disabled}>
<Icon type="down" />
</Button>

42
components/form/Form.tsx Normal file → Executable file
View File

@@ -1,7 +1,7 @@
import React from 'react';
import { PropTypes } from 'react';
import classNames from 'classnames';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import PureRenderMixin from 'rc-util/lib/PureRenderMixin';
import omit from 'omit.js';
import warning from 'warning';
import assign from 'object-assign';
@@ -20,7 +20,7 @@ export interface FormProps {
inline?: boolean;
vertical?: boolean;
form?: WrappedFormUtils;
onSubmit?: React.FormEventHandler;
onSubmit?: React.FormEventHandler<any>;
style?: React.CSSProperties;
className?: string;
prefixCls?: string;
@@ -42,11 +42,9 @@ export type WrappedFormUtils = {
validateFields(options: Object, callback: (erros: any, values: any) => void): any;
validateFields(callback: (erros: any, values: any) => void): any;
/** 与 `validateFields` 相似,但校验完后,如果校验不通过的菜单域不在可见范围内,则自动滚动进可见范围 */
validateFieldsAndScroll(
fieldNames?: Array<string>,
options?: Object,
callback?: (erros: any, values: any) => void
): void;
validateFieldsAndScroll(fieldNames?: Array<string>,
options?: Object,
callback?: (erros: any, values: any) => void): void;
/** 获取某个输入控件的 Error */
getFieldError(name: string): Object[];
/** 判断一个输入控件是否在校验状态*/
@@ -62,7 +60,7 @@ export type WrappedFormUtils = {
/** 收集子节点的值的时机 */
trigger?: string;
/** 可以把 onChange 的参数转化为控件的值,例如 DatePicker 可设为:(date, dateString) => dateString */
getValueFromEvent?: (...args) => any;
getValueFromEvent?: (...args: any[]) => any;
/** 校验子节点值的时机 */
validateTrigger?: string;
/** 校验规则,参见 [async-validator](https://github.com/yiminghe/async-validator) */
@@ -83,6 +81,8 @@ export interface ComponentDecorator {
<T extends (typeof FormComponent)>(component: T): T;
}
let warnedGetFieldProps = false;
export default class Form extends React.Component<FormProps, any> {
static defaultProps = {
prefixCls: 'ant-form',
@@ -103,8 +103,9 @@ export default class Form extends React.Component<FormProps, any> {
static Item = FormItem;
static create = (options?: FormCreateOption): ComponentDecorator => {
const formWrapper = createDOMForm(assign({}, options, {
const formWrapper = createDOMForm(assign({
fieldNameProp: 'id',
}, options, {
fieldMetaProp: FIELD_META_PROP,
}));
@@ -121,16 +122,25 @@ export default class Form extends React.Component<FormProps, any> {
form: this.props.form,
};
},
render() {
const getFieldProps = this.props.form.getFieldProps;
function deprecatedGetFieldProps(name, option) {
componentWillMount() {
if (!warnedGetFieldProps) {
this.getFieldProps = this.props.form.getFieldProps;
}
},
deprecatedGetFieldProps(name, option) {
if (!warnedGetFieldProps) {
warnedGetFieldProps = true;
warning(
false,
'`getFieldProps` is deprecated and will be removed in future, please use `getFieldDecorator` instead'
'`getFieldProps` is not recommended, please use `getFieldDecorator` instead'
);
return getFieldProps(name, option);
}
this.props.form.getFieldProps = deprecatedGetFieldProps;
return this.getFieldProps(name, option);
},
render() {
if (!warnedGetFieldProps) {
this.props.form.getFieldProps = this.deprecatedGetFieldProps;
}
const withRef: any = {};
if (options && options.withRef) {
@@ -152,7 +162,7 @@ export default class Form extends React.Component<FormProps, any> {
}
render() {
const { prefixCls, className, inline, horizontal, vertical } = this.props;
const { prefixCls, className = '', inline, horizontal, vertical } = this.props;
const formClassName = classNames({
[`${prefixCls}`]: true,
[`${prefixCls}-horizontal`]: horizontal,

View File

@@ -1,6 +1,7 @@
import React from 'react';
import classNames from 'classnames';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import warning from 'warning';
import PureRenderMixin from 'rc-util/lib/PureRenderMixin';
import Row from '../row';
import Col from '../col';
import { WrappedFormUtils } from './Form';
@@ -14,7 +15,7 @@ export interface FormItemLabelColOption {
export interface FormItemProps {
prefixCls?: string;
id?: string;
label?: string | React.ReactNode;
label?: React.ReactNode;
labelCol?: FormItemLabelColOption;
wrapperCol?: FormItemLabelColOption;
help?: React.ReactNode;
@@ -25,12 +26,14 @@ export interface FormItemProps {
required?: boolean;
style?: React.CSSProperties;
colon?: boolean;
children: any;
}
export interface FormItemContext {
form: WrappedFormUtils;
}
let autoGenerateWarning = false;
export default class FormItem extends React.Component<FormItemProps, any> {
static defaultProps = {
hasFeedback: false,
@@ -58,6 +61,17 @@ export default class FormItem extends React.Component<FormItemProps, any> {
context: FormItemContext;
componentDidMount() {
if (!autoGenerateWarning && (this.getControls(this.props.children, true).length > 1)) {
autoGenerateWarning = true;
warning(
false,
'`Form.Item` cannot generate `validateStatus` and `help` automatically, ' +
'while there are more than one `getFieldDecorator` in it.'
);
}
}
shouldComponentUpdate(...args) {
return PureRenderMixin.shouldComponentUpdate.apply(this, args);
}
@@ -72,11 +86,32 @@ export default class FormItem extends React.Component<FormItemProps, any> {
return props.help;
}
getControls(children, recursively) {
let controls: React.ReactElement<any>[] = [];
const childrenArray = React.Children.toArray(children);
for (let i = 0; i < childrenArray.length; i++) {
if (!recursively && controls.length > 0) {
break;
}
const child = childrenArray[i] as React.ReactElement<any>;
if (child.type as any === FormItem) {
continue;
}
if (!child.props) {
continue;
}
if (FIELD_META_PROP in child.props) {
controls.push(child);
} else if (child.props.children) {
controls = controls.concat(this.getControls(child.props.children, recursively));
}
}
return controls;
}
getOnlyControl() {
const children = React.Children.toArray(this.props.children);
const child = children.filter((c: React.ReactElement<any>) => {
return c.props && FIELD_META_PROP in c.props;
})[0];
const child = this.getControls(this.props.children, false)[0];
return child !== undefined ? child : null;
}
@@ -112,15 +147,18 @@ export default class FormItem extends React.Component<FormItemProps, any> {
getValidateStatus() {
const { isFieldValidating, getFieldError, getFieldValue } = this.context.form;
const field = this.getId();
if (!field) {
const fieldId = this.getId();
if (!fieldId) {
return '';
}
if (isFieldValidating(field)) {
if (isFieldValidating(fieldId)) {
return 'validating';
} else if (!!getFieldError(field)) {
}
if (!!getFieldError(fieldId)) {
return 'error';
} else if (getFieldValue(field) !== undefined && getFieldValue(field) !== null) {
}
const fieldValue = getFieldValue(fieldId);
if (fieldValue !== undefined && fieldValue !== null && fieldValue !== '') {
return 'success';
}
return '';
@@ -186,7 +224,7 @@ export default class FormItem extends React.Component<FormItemProps, any> {
// remove user input colon
let label = props.label;
if (typeof label === 'string' && label.trim() !== '') {
if (typeof label === 'string' && (label as string).trim() !== '') {
label = (props.label as string).replace(/[|:]\s*$/, '');
}

View File

@@ -1,134 +0,0 @@
---
order: 10
title:
zh-CN: 高级搜索
en-US: Advanced search
---
## zh-CN
三列栅格式的表单排列方式,常用于数据表格的高级搜索。
有部分定制的样式代码,由于输入标签长度不确定,需要根据具体情况自行调整。
## en-US
Three columns layout is often used for advanced searching of data table.
Because the width of label is not fixed, you may need to adjust it by customizing its style.
````jsx
import { Form, Input, Row, Col, Button, DatePicker } from 'antd';
const FormItem = Form.Item;
ReactDOM.render(
<Form horizontal className="ant-advanced-search-form">
<Row gutter={16}>
<Col sm={8}>
<FormItem
label="Search name"
labelCol={{ span: 10 }}
wrapperCol={{ span: 14 }}
>
<Input placeholder="Please input the search name" size="default" />
</FormItem>
<FormItem
label="Long search name"
labelCol={{ span: 10 }}
wrapperCol={{ span: 14 }}
>
<DatePicker size="default" />
</FormItem>
<FormItem
label="Search name"
labelCol={{ span: 10 }}
wrapperCol={{ span: 14 }}
>
<Input placeholder="Please input the search name" size="default" />
</FormItem>
</Col>
<Col sm={8}>
<FormItem
label="Search name"
labelCol={{ span: 10 }}
wrapperCol={{ span: 14 }}
>
<Input placeholder="Please input the search name" size="default" />
</FormItem>
<FormItem
label="Long search name"
labelCol={{ span: 10 }}
wrapperCol={{ span: 14 }}
>
<DatePicker size="default" />
</FormItem>
<FormItem
label="Search name"
labelCol={{ span: 10 }}
wrapperCol={{ span: 14 }}
>
<Input placeholder="Please input the search name" size="default" />
</FormItem>
</Col>
<Col sm={8}>
<FormItem
label="Search name"
labelCol={{ span: 10 }}
wrapperCol={{ span: 14 }}
>
<Input placeholder="Please input the search name" size="default" />
</FormItem>
<FormItem
label="Long search name"
labelCol={{ span: 10 }}
wrapperCol={{ span: 14 }}
>
<DatePicker size="default" />
</FormItem>
<FormItem
label="Search name"
labelCol={{ span: 10 }}
wrapperCol={{ span: 14 }}
>
<Input placeholder="Please input the search name" size="default" />
</FormItem>
</Col>
</Row>
<Row>
<Col span={12} offset={12} style={{ textAlign: 'right' }}>
<Button type="primary" htmlType="submit">Search</Button>
<Button>Clear</Button>
</Col>
</Row>
</Form>
, mountNode);
````
````css
/* custom style */
.ant-advanced-search-form {
padding: 16px 8px;
background: #f8f8f8;
border: 1px solid #d9d9d9;
border-radius: 6px;
}
/* because the label length is variable, you may need to adjust the left edge to have the form centered */
.ant-advanced-search-form > .ant-row {
position: relative;
left: -6px;
}
.ant-advanced-search-form .ant-btn + .ant-btn {
margin-left: 8px;
}
````
<style>
#components-form-demo-advanced-search-form .ant-form-horizontal {
max-width: none;
}
</style>

View File

@@ -0,0 +1,128 @@
---
order: 3
title:
zh-CN: 高级搜索
en-US: Advanced search
---
## zh-CN
三列栅格式的表单排列方式,常用于数据表格的高级搜索。
有部分定制的样式代码,由于输入标签长度不确定,需要根据具体情况自行调整。
## en-US
Three columns layout is often used for advanced searching of data table.
Because the width of label is not fixed, you may need to adjust it by customizing its style.
````jsx
import { Form, Row, Col, Input, Button, Icon } from 'antd';
const FormItem = Form.Item;
const usualShowedChildren = 2 * 3; // row * col
const AdvancedSearchForm = Form.create()(React.createClass({
getInitialState() {
return {
expand: false,
};
},
handleSearch(e) {
e.preventDefault();
this.props.form.validateFields((err, values) => {
if (err) {
return;
}
console.log('Received values of form: ', values);
});
},
handleReset() {
this.props.form.resetFields();
},
toggle(expand) {
this.setState({ expand });
},
render() {
const { getFieldDecorator } = this.props.form;
const formItemLayout = {
labelCol: { span: 5 },
wrapperCol: { span: 19 },
};
// To generate mock Form.Item
const children = [];
for (let i = 0; i < 10; i++) {
children.push(
<Col span={8} key={i}>
<FormItem
{...formItemLayout}
label={`Field ${i}`}
>
{getFieldDecorator(`field-${i}`)(
<Input placeholder="placeholder" />
)}
</FormItem>
</Col>
);
}
const expand = this.state.expand;
const showedChildren = expand ? children.length : usualShowedChildren;
return (
<Form
horizontal
className="ant-advanced-search-form"
onSubmit={this.handleSearch}
>
<Row gutter={40}>
{children.slice(0, showedChildren)}
</Row>
<Row>
<Col span={24} style={{ textAlign: 'right' }}>
<Button type="primary" htmlType="submit">Search</Button>
<Button onClick={this.handleReset}>Clear</Button>
{
expand ? (
<a className="ant-dropdown-link" onClick={() => this.toggle(false)}>
Collapse <Icon type="up" />
</a>
) : (
<a className="ant-dropdown-link" onClick={() => this.toggle(true)}>
Expand <Icon type="down" />
</a>
)
}
</Col>
</Row>
</Form>
);
},
}));
ReactDOM.render(<AdvancedSearchForm />, mountNode);
````
````css
#components-form-demo-advanced-search .ant-advanced-search-form {
padding: 24px;
background: #f8f8f8;
border: 1px solid #d9d9d9;
border-radius: 6px;
}
#components-form-demo-advanced-search .ant-advanced-search-form .ant-btn + .ant-btn {
margin-left: 8px;
}
#components-form-demo-advanced-search .ant-advanced-search-form .ant-dropdown-link {
margin-left: 16px;
}
````
<style>
#components-form-demo-advanced-search .ant-form-horizontal {
max-width: none;
}
</style>

View File

@@ -1,98 +0,0 @@
---
order: 3
title:
zh-CN: 表单控件
en-US: Form controls
---
## zh-CN
展示所有支持的表单控件。
**注** 输入框:只有正确设置了 type 属性的输入控件才能被赋予正确的样式。
## en-US
A list off all the controls that can be used with form.
**Note**: Input control: Only if set correct type for it, then it will be set correct style.
````jsx
import { Form, Input, Select, Checkbox, Radio } from 'antd';
const FormItem = Form.Item;
const Option = Select.Option;
const RadioGroup = Radio.Group;
function handleSelectChange(value) {
console.log(`selected ${value}`);
}
ReactDOM.render(
<Form horizontal>
<FormItem
id="control-input"
label="input control"
labelCol={{ span: 6 }}
wrapperCol={{ span: 14 }}
>
<Input id="control-input" placeholder="Please enter..." />
</FormItem>
<FormItem
id="control-textarea"
label="text area"
labelCol={{ span: 6 }}
wrapperCol={{ span: 14 }}
>
<Input type="textarea" id="control-textarea" rows="3" />
</FormItem>
<FormItem
id="select"
label="Select box"
labelCol={{ span: 6 }}
wrapperCol={{ span: 14 }}
>
<Select id="select" size="large" defaultValue="lucy" style={{ width: 200 }} onChange={handleSelectChange}>
<Option value="jack">Jack</Option>
<Option value="lucy">Lucy</Option>
<Option value="disabled" disabled>disabled</Option>
<Option value="yiminghe">Yiminghe</Option>
</Select>
</FormItem>
<FormItem
label="Checkbox"
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }}
>
<Checkbox className="ant-checkbox-vertical">item 1</Checkbox>
<Checkbox className="ant-checkbox-vertical">item 2</Checkbox>
<Checkbox className="ant-checkbox-vertical" disabled>item 3 (disabled)</Checkbox>
</FormItem>
<FormItem
label="Checkbox"
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }}
>
<Checkbox className="ant-checkbox-inline">item 1</Checkbox>
<Checkbox className="ant-checkbox-inline">item 2</Checkbox>
<Checkbox className="ant-checkbox-inline">item 3</Checkbox>
</FormItem>
<FormItem
label="Radio"
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }}
>
<RadioGroup defaultValue="b">
<Radio value="a">A</Radio>
<Radio value="b">B</Radio>
<Radio value="c">C</Radio>
<Radio value="d">D</Radio>
</RadioGroup>
</FormItem>
</Form>
, mountNode);
````

View File

@@ -1,77 +1,106 @@
---
order: 14
order: 4
title:
zh-CN: 与 Modal 配合使用
en-US: With Modal
zh-CN: 弹出层中的新建表单
en-US: Form in Modal to Create
---
## zh-CN
在 Modal 中使用 Form当点击 Modal 的确定时,调用 `this.props.form.getFieldsValue` 获取表单内的值
当用户访问一个展示了某个列表的页面,想新建一项但又不想跳转页面时,可以用 Modal 弹出一个表单,用户填写必要信息后创建新的项
## en-US
If you use Form in Modal, when you click the Modal, it could invoke `this.props.form.getFieldsValue` to get values of form.
When user visit a page with a list of items, and want to create a new item. The page can popup a form in Modal, then let user fills in the form to create an item.
````jsx
import { Button, Form, Input, Modal } from 'antd';
const createForm = Form.create;
import { Button, Modal, Form, Input, Radio } from 'antd';
const FormItem = Form.Item;
let Demo = React.createClass({
const CollectionCreateForm = Form.create()(
(props) => {
const { visible, onCancel, onCreate, form } = props;
const { getFieldDecorator } = form;
return (
<Modal
visible={visible}
title="Create a new collection"
okText="Create"
onCancel={onCancel}
onOk={onCreate}
>
<Form vertical>
<FormItem label="Title">
{getFieldDecorator('title', {
rules: [{ required: true, message: 'Please input the title of collection!' }],
})(
<Input />
)}
</FormItem>
<FormItem label="Description">
{getFieldDecorator('description')(<Input type="textarea" />)}
</FormItem>
<FormItem className="collection-create-form_last-form-item">
{getFieldDecorator('modifier', {
initialValue: 'public',
})(
<Radio.Group>
<Radio value="public">Public</Radio>
<Radio value="private">Private</Radio>
</Radio.Group>
)}
</FormItem>
</Form>
</Modal>
);
}
);
const CollectionsPage = React.createClass({
getInitialState() {
return { visible: false };
},
handleSubmit() {
console.log(this.props.form.getFieldsValue());
this.hideModal();
},
showModal() {
this.setState({ visible: true });
},
hideModal() {
handleCancel() {
this.setState({ visible: false });
},
handleCreate() {
const form = this.form;
form.validateFields((err, values) => {
if (err) {
return;
}
console.log('Received values of form: ', values);
form.resetFields();
this.setState({ visible: false });
});
},
saveFormRef(form) {
this.form = form;
},
render() {
const { getFieldDecorator } = this.props.form;
const formItemLayout = {
labelCol: { span: 4 },
wrapperCol: { span: 20 },
};
return (
<div>
<Button type="primary" onClick={this.showModal}>Surprise</Button>
<Modal title="login" visible={this.state.visible} onOk={this.handleSubmit} onCancel={this.hideModal}>
<Form horizontal>
<FormItem
{...formItemLayout}
label="User name"
>
{getFieldDecorator('username')(
<Input type="text" autoComplete="off" />
)}
</FormItem>
<FormItem
{...formItemLayout}
label="Password"
>
{getFieldDecorator('password')(
<Input type="password" autoComplete="off" />
)}
</FormItem>
</Form>
</Modal>
<Button type="primary" onClick={this.showModal}>New Collection</Button>
<CollectionCreateForm
ref={this.saveFormRef}
visible={this.state.visible}
onCancel={this.handleCancel}
onCreate={this.handleCreate}
/>
</div>
);
},
});
Demo = createForm()(Demo);
ReactDOM.render(<Demo />, mountNode);
ReactDOM.render(<CollectionsPage />, mountNode);
````
````css
.collection-create-form_last-form-item {
margin-bottom: 0;
}
````

View File

@@ -1,88 +0,0 @@
---
order: 2
title:
zh-CN: 典型表单
en-US: Horizontal form
---
## zh-CN
示例展示了如何通过使用 `Form.create` 来获取和更新表单提交的数值。
## en-US
How to use `Form.create` to get and update values of form.
````jsx
import { Form, Input, Button, Checkbox, Radio, Tooltip, Icon } from 'antd';
const FormItem = Form.Item;
const RadioGroup = Radio.Group;
let Demo = React.createClass({
handleSubmit(e) {
e.preventDefault();
console.log('Received values of form:', this.props.form.getFieldsValue());
},
render() {
const { getFieldDecorator } = this.props.form;
const formItemLayout = {
labelCol: { span: 6 },
wrapperCol: { span: 14 },
};
return (
<Form horizontal onSubmit={this.handleSubmit}>
<FormItem
{...formItemLayout}
label="User name"
>
<p className="ant-form-text" id="userName" name="userName">Big eye minion</p>
</FormItem>
<FormItem
{...formItemLayout}
label="Password"
>
{getFieldDecorator('pass', { initialValue: '' })(
<Input type="password" placeholder="Please input the password" />
)}
</FormItem>
<FormItem
{...formItemLayout}
label="Gender"
>
{getFieldDecorator('gender', { initialValue: 'female' })(
<RadioGroup>
<Radio value="male">male</Radio>
<Radio value="female">female</Radio>
</RadioGroup>
)}
</FormItem>
<FormItem
{...formItemLayout}
label="remarks"
help="Please input something"
>
{getFieldDecorator('remark', { initialValue: '' })(
<Input type="textarea" placeholder="Please input something" />
)}
</FormItem>
<FormItem
{...formItemLayout}
label={<span>Sold myself <Tooltip title="I come for Qiu Xiang"><Icon type="question-circle-o" /></Tooltip></span>}
>
{getFieldDecorator('agreement', { initialValue: false, valuePropName: 'checked' })(
<Checkbox>agree</Checkbox>
)}
</FormItem>
<FormItem wrapperCol={{ span: 16, offset: 6 }} style={{ marginTop: 24 }}>
<Button type="primary" htmlType="submit">OK</Button>
</FormItem>
</Form>
);
},
});
Demo = Form.create()(Demo);
ReactDOM.render(<Demo />, mountNode);
````

View File

@@ -0,0 +1,59 @@
---
order: 0
title:
zh-CN: 水平登陆栏
en-US: Horizontal Login Form
---
## zh-CN
水平登陆栏,常用在顶部导航栏中。
## en-US
Horizontal login form is often used in navigation bar.
````jsx
import { Form, Icon, Input, Button } from 'antd';
const FormItem = Form.Item;
const HorizontalLoginForm = Form.create()(React.createClass({
handleSubmit(e) {
e.preventDefault();
this.props.form.validateFields((err, values) => {
if (err) {
return;
}
console.log('Received values of form: ', values);
});
},
render() {
const { getFieldDecorator } = this.props.form;
return (
<Form inline onSubmit={this.handleSubmit}>
<FormItem>
{getFieldDecorator('userName', {
rules: [{ required: true, message: 'Please input your username!' }],
})(
<Input addonBefore={<Icon type="user" />} placeholder="Username" />
)}
</FormItem>
<FormItem>
{getFieldDecorator('password', {
rules: [{ required: true, message: 'Please input your Password!' }],
})(
<Input addonBefore={<Icon type="lock" />} type="password" placeholder="Password" />
)}
</FormItem>
<FormItem>
<Button type="primary" htmlType="submit">Log in</Button>
</FormItem>
</Form>
);
},
}));
ReactDOM.render(<HorizontalLoginForm />, mountNode);
````

View File

@@ -1,58 +0,0 @@
---
order: 1
title:
zh-CN: 平行排列
en-US: Inline form
---
## zh-CN
行内排列,常用于登录界面。
## en-US
Inline form is often used for login.
````jsx
import { Form, Input, Button, Checkbox } from 'antd';
const FormItem = Form.Item;
let Demo = React.createClass({
handleSubmit(e) {
e.preventDefault();
console.log('Received values of form:', this.props.form.getFieldsValue());
},
render() {
const { getFieldDecorator } = this.props.form;
return (
<Form inline onSubmit={this.handleSubmit}>
<FormItem
label="Account"
>
{getFieldDecorator('userName')(
<Input placeholder="Please input the account" />
)}
</FormItem>
<FormItem
label="Password"
>
{getFieldDecorator('password')(
<Input type="password" placeholder="Please input the password" />
)}
</FormItem>
<FormItem>
{getFieldDecorator('agreement')(
<Checkbox>Remember me</Checkbox>
)}
</FormItem>
<Button type="primary" htmlType="submit">Submit</Button>
</Form>
);
},
});
Demo = Form.create()(Demo);
ReactDOM.render(<Demo />, mountNode);
````

View File

@@ -1,105 +0,0 @@
---
order: 4
title:
zh-CN: 输入框组合
en-US: Input group
---
## zh-CN
各类输入框的组合展现。
## en-US
Input group of different type input controls.
````jsx
import { Form, Input, Select, Col } from 'antd';
const FormItem = Form.Item;
const InputGroup = Input.Group;
const Option = Select.Option;
const selectAfter = (
<Select defaultValue=".com" style={{ width: 70 }}>
<Option value=".com">.com</Option>
<Option value=".jp">.jp</Option>
<Option value=".cn">.cn</Option>
<Option value=".org">.org</Option>
</Select>
);
ReactDOM.render(
<Form horizontal>
<FormItem
label="Input control"
labelCol={{ span: 6 }}
wrapperCol={{ span: 16 }}
>
<Input addonBefore="Http://" defaultValue="mysite.com" id="site1" />
</FormItem>
<FormItem
label="Input control"
labelCol={{ span: 6 }}
validateStatus="success"
wrapperCol={{ span: 16 }}
>
<Input addonBefore="Http://" addonAfter=".com" defaultValue="mysite" id="site2" />
</FormItem>
<FormItem
label="Select input control"
labelCol={{ span: 6 }}
wrapperCol={{ span: 16 }}
>
<Input addonAfter={selectAfter} placeholder="www.mysite" id="site4" />
</FormItem>
<FormItem
label="Identity number"
labelCol={{ span: 6 }}
wrapperCol={{ span: 16 }}
>
<InputGroup>
<Col span="6">
<Input id="certNo1" />
</Col>
<Col span="6">
<Input id="certNo2" />
</Col>
<Col span="6">
<Input id="certNo3" />
</Col>
<Col span="6">
<Input id="certNo4" />
</Col>
</InputGroup>
</FormItem>
<FormItem
label="Tel"
labelCol={{ span: 6 }}
wrapperCol={{ span: 16 }}
>
<InputGroup>
<Col span="4">
<Input id="tel1" defaultValue="086" />
</Col>
<Col span="2">
<p className="ant-form-split">--</p>
</Col>
<Col span="6">
<Input id="tel1" />
</Col>
<Col span="6">
<Input id="tel2" />
</Col>
<Col span="6">
<Input id="tel3" />
</Col>
</InputGroup>
</FormItem>
</Form>
, mountNode);
````

View File

@@ -1,5 +1,5 @@
---
order: 5
order: 6
title:
zh-CN: 表单组合
en-US: Mix

View File

@@ -0,0 +1,81 @@
---
order: 1
title:
zh-CN: 登陆框
en-US: Login Form
---
## zh-CN
普通的登陆框,可以容纳更多的元素。
## en-US
Normal login form which can contain more elements.
````jsx
import { Form, Icon, Input, Button, Checkbox } from 'antd';
const FormItem = Form.Item;
const NormalLoginForm = Form.create()(React.createClass({
handleSubmit(e) {
e.preventDefault();
this.props.form.validateFields((err, values) => {
if (err) {
return;
}
console.log('Received values of form: ', values);
});
},
render() {
const { getFieldDecorator } = this.props.form;
return (
<Form onSubmit={this.handleSubmit} className="login-form">
<FormItem>
{getFieldDecorator('userName', {
rules: [{ required: true, message: 'Please input your username!' }],
})(
<Input addonBefore={<Icon type="user" />} placeholder="Username" />
)}
</FormItem>
<FormItem>
{getFieldDecorator('password', {
rules: [{ required: true, message: 'Please input your Password!' }],
})(
<Input addonBefore={<Icon type="lock" />} type="password" placeholder="Password" />
)}
</FormItem>
<FormItem>
{getFieldDecorator('remember', {
valuePropName: 'checked',
initialValue: true,
})(
<Checkbox>Remember me</Checkbox>
)}
<a className="login-form-forgot">Forgot password</a>
<Button type="primary" htmlType="submit" className="login-form-button">
Log in
</Button>
Or <a>register now!</a>
</FormItem>
</Form>
);
},
}));
ReactDOM.render(<NormalLoginForm />, mountNode);
````
```css
#components-form-demo-normal-login .login-form {
max-width: 300px;
}
#components-form-demo-normal-login .login-form-forgot {
float: right;
}
#components-form-demo-normal-login .login-form-button {
width: 100%;
}
```

View File

@@ -0,0 +1,224 @@
---
order: 2
title:
zh-CN: 注册新用户
en-US: Registration
---
## zh-CN
用户填写必须的信息以注册新用户。
## en-US
Fill in this form to create a new account for you.
````jsx
import { Form, Input, Tooltip, Icon, Cascader, Select, Row, Col, Checkbox, Button } from 'antd';
const FormItem = Form.Item;
const Option = Select.Option;
const residences = [{
value: 'zhejiang',
label: 'Zhejiang',
children: [{
value: 'hangzhou',
label: 'Hangzhou',
children: [{
value: 'xihu',
label: 'West Lake',
}],
}],
}, {
value: 'jiangsu',
label: 'Jiangsu',
children: [{
value: 'nanjing',
label: 'Nanjing',
children: [{
value: 'zhonghuamen',
label: 'Zhong Hua Men',
}],
}],
}];
const RegistrationForm = Form.create()(React.createClass({
getInitialState() {
return {
passwordDirty: false,
};
},
handleSubmit(e) {
e.preventDefault();
this.props.form.validateFields((err, values) => {
if (err) {
return;
}
console.log('Received values of form: ', values);
});
},
handlePasswordBlur(e) {
const value = e.target.value;
this.setState({ passwordDirty: this.state.passwordDirty || !!value });
},
checkPassowrd(rule, value, callback) {
const form = this.props.form;
if (value && value !== form.getFieldValue('password')) {
callback('Two passwords that you enter is inconsistent!');
} else {
callback();
}
},
checkConfirm(rule, value, callback) {
const form = this.props.form;
if (value && this.state.passwordDirty) {
form.validateFields(['confirm'], { force: true });
}
callback();
},
render() {
const { getFieldDecorator } = this.props.form;
const formItemLayout = {
labelCol: { span: 6 },
wrapperCol: { span: 14 },
};
const prefixSelector = getFieldDecorator('prefix', {
initialValue: '86',
})(
<Select className="icp-selector">
<Option value="86">+86</Option>
</Select>
);
return (
<Form horizontal onSubmit={this.handleSubmit}>
<FormItem
{...formItemLayout}
label="E-mail"
hasFeedback
>
{getFieldDecorator('email', {
rules: [{
type: 'email', message: 'The input is not valid E-mail!',
}, {
required: true, message: 'Please input your E-mail!',
}],
})(
<Input />
)}
</FormItem>
<FormItem
{...formItemLayout}
label="Password"
hasFeedback
>
{getFieldDecorator('password', {
rules: [{
required: true, message: 'Please input your password!',
}, {
validator: this.checkConfirm,
}],
})(
<Input type="password" onBlur={this.handlePasswordBlur} />
)}
</FormItem>
<FormItem
{...formItemLayout}
label="Confirm Password"
hasFeedback
>
{getFieldDecorator('confirm', {
rules: [{
required: true, message: 'Please confirm your password!',
}, {
validator: this.checkPassowrd,
}],
})(
<Input type="password" />
)}
</FormItem>
<FormItem
{...formItemLayout}
label={(
<span>
Nickname&nbsp;
<Tooltip title="What do you want other to call you?">
<Icon type="question-circle-o" />
</Tooltip>
</span>
)}
hasFeedback
>
{getFieldDecorator('nickname', {
rules: [{ required: true, message: 'Please input your nickname!' }],
})(
<Input />
)}
</FormItem>
<FormItem
{...formItemLayout}
label="Habitual Residence"
>
{getFieldDecorator('residence', {
initialValue: ['zhejiang', 'hangzhou', 'xihu'],
rules: [{ type: 'array', required: true, message: 'Please select your habitual residence!' }],
})(
<Cascader options={residences} />
)}
</FormItem>
<FormItem
{...formItemLayout}
label="Phone Number"
>
{getFieldDecorator('phone', {
rules: [{ required: true, message: 'Please input your phone number!' }],
})(
<Input addonBefore={prefixSelector} />
)}
</FormItem>
<FormItem
{...formItemLayout}
label="Captcha"
>
<Row gutter={8}>
<Col span={12}>
{getFieldDecorator('captcha', {
rules: [{ required: true, message: 'Please input the captcha you got!' }],
})(
<Input size="large" />
)}
</Col>
<Col span={12}>
<Button size="large">Get captcha</Button>
</Col>
</Row>
</FormItem>
<FormItem>
<Row>
<Col span={14} offset={6}>
<p>
{getFieldDecorator('agreement', {
valuePropName: 'checked',
})(
<Checkbox>I had read the <a>agreement</a></Checkbox>
)}
</p>
<Button type="primary" htmlType="submit" size="large">Register</Button>
</Col>
</Row>
</FormItem>
</Form>
);
},
}));
ReactDOM.render(<RegistrationForm />, mountNode);
````
````css
#components-form-demo-register .icp-selector {
width: 60px;
}
````

View File

@@ -0,0 +1,92 @@
---
order: 5
title:
zh-CN: 时间类控件
en-US: Time-related Controls
---
## zh-CN
`antd@2.0` 之后,时间类组件的 `value` 改为 `moment` 类型,所以在提交前需要预处理。
## en-US
After `antd@2.0`, the `value` of time-related components had been changed to `moment`. So, we need to pre-process those values.
````jsx
import { Form, DatePicker, TimePicker, Row, Col, Button } from 'antd';
const FormItem = Form.Item;
const MonthPicker = DatePicker.MonthPicker;
const RangePicker = DatePicker.RangePicker;
const TimeRelatedForm = Form.create()(React.createClass({
handleSubmit(e) {
e.preventDefault();
const fieldsValue = this.props.form.getFieldsValue();
// Should format date value before submit.
const rangeValue = fieldsValue['range-picker'];
const values = {
...fieldsValue,
'date-picker': fieldsValue['date-picker'].format('YYYY-MM-DD'),
'month-picker': fieldsValue['month-picker'].format('YYYY-MM'),
'range-picker': [rangeValue[0].format('YYYY-MM-DD'), rangeValue[1].format('YYYY-MM-DD')],
'time-picker': fieldsValue['time-picker'].format('HH:mm:ss'),
};
console.log('Received values of form: ', values);
},
render() {
const { getFieldDecorator } = this.props.form;
const formItemLayout = {
labelCol: { span: 6 },
wrapperCol: { span: 14 },
};
return (
<Form horizontal onSubmit={this.handleSubmit}>
<FormItem
{...formItemLayout}
label="DatePicker"
>
{getFieldDecorator('date-picker')(
<DatePicker />
)}
</FormItem>
<FormItem
{...formItemLayout}
label="MonthPicker"
>
{getFieldDecorator('month-picker')(
<MonthPicker />
)}
</FormItem>
<FormItem
{...formItemLayout}
label="RangePicker"
>
{getFieldDecorator('range-picker')(
<RangePicker />
)}
</FormItem>
<FormItem
{...formItemLayout}
label="TimePicker"
>
{getFieldDecorator('time-picker')(
<TimePicker />
)}
</FormItem>
<FormItem>
<Row>
<Col span={14} offset={6}>
<Button type="primary" htmlType="submit" size="large">Submit</Button>
</Col>
</Row>
</FormItem>
</Form>
);
},
}));
ReactDOM.render(<TimeRelatedForm />, mountNode);
````

View File

@@ -1,183 +0,0 @@
---
order: 11
title:
zh-CN: 表单校验
en-US: Basic validate
---
## zh-CN
基本的表单校验例子。
## en-US
Basic validation for form.
````jsx
import { Button, Form, Input } from 'antd';
const createForm = Form.create;
const FormItem = Form.Item;
function noop() {
return false;
}
let BasicDemo = React.createClass({
handleReset(e) {
e.preventDefault();
this.props.form.resetFields();
},
handleSubmit(e) {
e.preventDefault();
this.props.form.validateFields((errors, values) => {
if (errors) {
console.log('Errors in form!!!');
return;
}
console.log('Submit!!!');
console.log(values);
});
},
userExists(rule, value, callback) {
if (!value) {
callback();
} else {
setTimeout(() => {
if (value === 'Jason Wood') {
callback([new Error('Sorry, the user name is already in use.')]);
} else {
callback();
}
}, 800);
}
},
checkPass(rule, value, callback) {
const { validateFields } = this.props.form;
if (value) {
validateFields(['rePasswd'], { force: true });
}
callback();
},
checkPass2(rule, value, callback) {
const { getFieldValue } = this.props.form;
if (value && value !== getFieldValue('passwd')) {
callback('The two passwords you enter are inconsistent!');
} else {
callback();
}
},
render() {
const { getFieldDecorator, getFieldError, isFieldValidating } = this.props.form;
const formItemLayout = {
labelCol: { span: 7 },
wrapperCol: { span: 12 },
};
return (
<Form horizontal>
<FormItem
{...formItemLayout}
label="User name"
hasFeedback
help={isFieldValidating('name') ? 'validating...' : (getFieldError('name') || []).join(', ')}
>
{getFieldDecorator('name', {
rules: [
{ required: true, min: 5, message: 'User name for at least 5 characters' },
{ validator: this.userExists },
],
})(
<Input placeholder="Realtime validation, try to input Jason Wood" />
)}
</FormItem>
<FormItem
{...formItemLayout}
label="Email"
hasFeedback
>
{getFieldDecorator('email', {
validate: [{
rules: [
{ required: true },
],
trigger: 'onBlur',
}, {
rules: [
{ type: 'email', message: 'Please input the correct email' },
],
trigger: ['onBlur', 'onChange'],
}],
})(
<Input type="email" placeholder="This control uses onBlur and onChange" />
)}
</FormItem>
<FormItem
{...formItemLayout}
label="Password"
hasFeedback
>
{getFieldDecorator('passwd', {
rules: [
{ required: true, whitespace: true, message: 'Please enter your password' },
{ validator: this.checkPass },
],
})(
<Input type="password" autoComplete="off"
onContextMenu={noop} onPaste={noop} onCopy={noop} onCut={noop}
/>
)}
</FormItem>
<FormItem
{...formItemLayout}
label="Confirm password"
hasFeedback
>
{getFieldDecorator('rePasswd', {
rules: [{
required: true,
whitespace: true,
message: 'Please confirm your password',
}, {
validator: this.checkPass2,
}],
})(
<Input type="password" autoComplete="off" placeholder="Both passwords that you enter must be consistent."
onContextMenu={noop} onPaste={noop} onCopy={noop} onCut={noop}
/>
)}
</FormItem>
<FormItem
{...formItemLayout}
label="remark"
>
{getFieldDecorator('textarea', {
rules: [
{ required: true, message: 'Really not supposed to write something?' },
],
})(
<Input type="textarea" placeholder="Please write something" id="textarea" name="textarea" />
)}
</FormItem>
<FormItem wrapperCol={{ span: 12, offset: 7 }}>
<Button type="primary" onClick={this.handleSubmit}>OK</Button>
&nbsp;&nbsp;&nbsp;
<Button type="ghost" onClick={this.handleReset}>Reset</Button>
</FormItem>
</Form>
);
},
});
BasicDemo = createForm()(BasicDemo);
ReactDOM.render(<BasicDemo />, mountNode);
````

View File

@@ -1,239 +0,0 @@
---
order: 13
title:
zh-CN: 自定义校验规则
en-US: Customized validation
---
## zh-CN
密码校验实例。
这里使用了 `this.props.form.validateFields` 方法,在对第一次输入的密码进行校验时会触发二次密码的校验。
## en-US
Customized validation for Password.
To use `this.props.form.validateFields` method, when validating first password you enter will trigger the second password validation.
````jsx
import { Button, Form, Input, Row, Col } from 'antd';
import classNames from 'classnames';
const createForm = Form.create;
const FormItem = Form.Item;
function noop() {
return false;
}
let Demo = React.createClass({
getInitialState() {
return {
dirty: false,
passBarShow: false, // Whether to display a tooltip of password strength
rePassBarShow: false,
passStrength: 'L', // Password strength
rePassStrength: 'L',
};
},
handleSubmit() {
this.props.form.validateFields((errors, values) => {
if (errors) {
console.log('Errors in form!!!');
return;
}
console.log('Submit!!!');
console.log(values);
});
},
getPassStrenth(value, type) {
if (value) {
let strength;
// Customized the password strength, here is just a simple example
if (value.length < 6) {
strength = 'L';
} else if (value.length <= 9) {
strength = 'M';
} else {
strength = 'H';
}
this.setState({
[`${type}BarShow`]: true,
[`${type}Strength`]: strength,
});
} else {
this.setState({
[`${type}BarShow`]: false,
});
}
},
checkPass(rule, value, callback) {
const form = this.props.form;
this.getPassStrenth(value, 'pass');
if (form.getFieldValue('pass') && this.state.dirty) {
form.validateFields(['rePass'], { force: true });
}
callback();
},
checkPass2(rule, value, callback) {
const form = this.props.form;
this.getPassStrenth(value, 'rePass');
if (value && value !== form.getFieldValue('pass')) {
callback('Two passwords you enter is inconsistent!');
} else {
callback();
}
},
renderPassStrengthBar(type) {
const strength = type === 'pass' ? this.state.passStrength : this.state.rePassStrength;
const classSet = classNames({
'ant-pwd-strength': true,
'ant-pwd-strength-low': strength === 'L',
'ant-pwd-strength-medium': strength === 'M',
'ant-pwd-strength-high': strength === 'H',
});
const level = {
L: 'Low',
M: 'Middle',
H: 'High',
};
return (
<div>
<ul className={classSet}>
<li className="ant-pwd-strength-item ant-pwd-strength-item-1" />
<li className="ant-pwd-strength-item ant-pwd-strength-item-2" />
<li className="ant-pwd-strength-item ant-pwd-strength-item-3" />
<span className="ant-form-text">
{level[strength]}
</span>
</ul>
</div>
);
},
render() {
const { getFieldDecorator } = this.props.form;
return (
<div>
<Form vertical style={{ maxWidth: 600 }}>
<Row type="flex" align="middle">
<Col span={12}>
<FormItem label="Password">
{getFieldDecorator('pass', {
rules: [
{ required: true, whitespace: true, message: 'Please enter your password' },
{ validator: this.checkPass },
],
})(
<Input type="password"
onContextMenu={noop} onPaste={noop} onCopy={noop} onCut={noop}
autoComplete="off" id="pass"
onChange={(e) => {
console.log('Your password is stolen in this way', e.target.value);
}}
onBlur={(e) => {
const value = e.target.value;
this.setState({ dirty: this.state.dirty || !!value });
}}
/>
)}
</FormItem>
</Col>
<Col span={12}>
{this.state.passBarShow ? this.renderPassStrengthBar('pass') : null}
</Col>
</Row>
<Row type="flex" align="middle">
<Col span={12}>
<FormItem label="Confirm">
{getFieldDecorator('rePass', {
rules: [{
required: true,
whitespace: true,
message: 'Please confirm your password',
}, {
validator: this.checkPass2,
}],
})(
<Input type="password"
onContextMenu={noop} onPaste={noop} onCopy={noop} onCut={noop}
autoComplete="off" id="rePass"
/>
)}
</FormItem>
</Col>
<Col span={12}>
{this.state.rePassBarShow ? this.renderPassStrengthBar('rePass') : null}
</Col>
</Row>
<FormItem><Button type="primary" onClick={this.handleSubmit}>Submit</Button></FormItem>
</Form>
</div>
);
},
});
Demo = createForm()(Demo);
ReactDOM.render(<Demo />, mountNode);
````
````css
.ant-pwd-strength {
display: inline-block;
margin-left: 8px;
line-height: 32px;
height: 32px;
vertical-align: middle;
}
.ant-pwd-strength-item {
float: left;
margin-right: 1px;
margin-top: 12px;
width: 19px;
height: 8px;
line-height: 8px;
list-style: none;
background-color: #f3f3f3;
transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
}
.ant-pwd-strength-item-1 {
border-top-left-radius: 6px;
border-bottom-left-radius: 6px;
}
.ant-pwd-strength-item-2 {
width: 20px;
}
.ant-pwd-strength-item-3 {
border-top-right-radius: 6px;
border-bottom-right-radius: 6px;
margin-right: 8px;
}
.ant-pwd-strength-low .ant-pwd-strength-item-1, .ant-pwd-strength-medium .ant-pwd-strength-item-1, .ant-pwd-strength-high .ant-pwd-strength-item-1 {
background-color: #FAC450;
}
.ant-pwd-strength-medium .ant-pwd-strength-item-2, .ant-pwd-strength-high .ant-pwd-strength-item-2 {
background-color: rgba(135, 208, 104, .6);
filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#9987D068,endColorstr=#9987D068);
}
.ant-pwd-strength-high .ant-pwd-strength-item-3 {
background-color: #87D068;
}
````

View File

@@ -137,20 +137,8 @@ let Demo = React.createClass({
{...formItemLayout}
label="Hobby"
>
{getFieldDecorator('eat', {
valuePropName: 'checked',
})(
<Checkbox>eat</Checkbox>
)}
{getFieldDecorator('sleep', {
valuePropName: 'checked',
})(
<Checkbox>sleeping</Checkbox>
)}
{getFieldDecorator('beat', {
valuePropName: 'checked',
})(
<Checkbox>dozen doug</Checkbox>
{getFieldDecorator('hobby')(
<Checkbox.Group options={['eat', 'sleeping', 'dozen doug']} />
)}
</FormItem>

View File

@@ -76,6 +76,13 @@ If the form has been decorated by `Form.create` then it has `this.props.form` pr
### this.props.form.getFieldDecorator(id, options)
After wrapped by `getFieldDecorator`, `value` `onChange` props will be added to form controlsthe flow of form data will be handled by Form which will cause:
1. You don't need to use `onChange` and should not add `value` `onChange` to controls. (There are warnings after `antd@2.0`)
2. You can not set default value via `defaultValue` prop, you should use `initialValue` in `getFieldDecorator` instead.
3. You don't need to call `setState` manully, please use `this.props.form.setFieldsValue` to change value programmatically.
#### Special attention
If you use `react@<15.3.0`, then, you can't use `getFieldDecorator` in stateless component: https://github.com/facebook/react/pull/6534

View File

@@ -78,6 +78,12 @@ CustomizedForm = Form.create({})(CustomizedForm);
### this.props.form.getFieldDecorator(id, options)
经过 `getFieldDecorator` 包装的控件,表单控件会自动添加 `value` `onChange` 等属性,数据同步将被 Form 接管,这会导致以下结果:
1. 你不再需要用 `onChange` 来做同步,也不应该给控件单独添加 `value` `onChange` 等属性。2.0 后会在控制台进行警告)
2. 你不能用控件的 `defaultValue` 属性来设置默认值,请用 `getFieldDecorator` 里的 `initialValue`
3. 你不需要用 `setState`,可以使用 `this.props.form.setFieldsValue` 来动态改变表单值。
#### 特别注意
如果使用的是 `react@<15.3.0`,则 `getFieldDecorator` 调用不能位于纯函数组件中: https://github.com/facebook/react/pull/6534

View File

@@ -62,6 +62,7 @@ input[type="checkbox"] {
font-size: @font-size-base;
margin-bottom: @form-item-margin-bottom;
color: #666;
vertical-align: top;
// nested FormItem
& > &,

3
components/icon/index.tsx Normal file → Executable file
View File

@@ -6,8 +6,9 @@ export interface IconProps {
type: string;
className?: string;
title?: string;
onClick?: (e) => void;
onClick?: React.MouseEventHandler<any>;
spin?: boolean;
style?: React.CSSProperties;
}
export default (props: IconProps) => {

View File

@@ -1,6 +0,0 @@
.anticon {
&-spin {
display: inline-block;
animation: loadingCircle 1.6s infinite linear;
}
}

View File

@@ -1,3 +1 @@
import '../../style/index.less';
import './index.less';

View File

@@ -10,14 +10,15 @@ export interface GroupProps {
}
const Group: React.StatelessComponent<GroupProps> = (props) => {
const className = classNames({
[props.prefixCls]: true,
[`${props.prefixCls}-lg`]: props.size === 'large',
[`${props.prefixCls}-sm`]: props.size === 'small',
[props.className]: !!props.className,
const { prefixCls = 'ant-input-group', className = '' } = props;
const cls = classNames({
[prefixCls]: true,
[`${prefixCls}-lg`]: props.size === 'large',
[`${prefixCls}-sm`]: props.size === 'small',
[className]: !!className,
});
return (
<span className={className} style={props.style}>
<span className={cls} style={props.style}>
{props.children}
</span>
);
@@ -27,8 +28,4 @@ Group.propTypes = {
children: React.PropTypes.any,
};
Group.defaultProps = {
prefixCls: 'ant-input-group',
};
export default Group;

View File

@@ -45,11 +45,11 @@ export interface InputProps {
readOnly?: boolean;
addonBefore?: React.ReactNode;
addonAfter?: React.ReactNode;
onPressEnter?: React.FormEventHandler;
onKeyDown?: React.FormEventHandler;
onChange?: React.FormEventHandler;
onClick?: React.FormEventHandler;
onBlur?: React.FormEventHandler;
onPressEnter?: React.FormEventHandler<any>;
onKeyDown?: React.FormEventHandler<any>;
onChange?: React.FormEventHandler<any>;
onClick?: React.FormEventHandler<any>;
onBlur?: React.FormEventHandler<any>;
autosize?: boolean | AutoSizeType;
autoComplete?: 'on' | 'off';
style?: React.CSSProperties;
@@ -61,9 +61,6 @@ export default class Input extends Component<InputProps, any> {
disabled: false,
prefixCls: 'ant-input',
type: 'text',
onPressEnter() {},
onKeyDown() {},
onChange() {},
autosize: false,
};
@@ -114,17 +111,23 @@ export default class Input extends Component<InputProps, any> {
}
handleKeyDown = (e) => {
if (e.keyCode === 13) {
this.props.onPressEnter(e);
const { onPressEnter, onKeyDown } = this.props;
if (e.keyCode === 13 && onPressEnter) {
onPressEnter(e);
}
if (onKeyDown) {
onKeyDown(e);
}
this.props.onKeyDown(e);
}
handleTextareaChange = (e) => {
if (!('value' in this.props)) {
this.resizeTextarea();
}
this.props.onChange(e);
const onChange = this.props.onChange;
if (onChange) {
onChange(e);
}
}
resizeTextarea = () => {

View File

@@ -87,8 +87,8 @@ function calculateNodeStyling(node, useCache = false) {
export default function calculateNodeHeight(
uiTextNode,
useCache = false,
minRows = null,
maxRows = null
minRows: number | null = null,
maxRows: number | null = null
) {
if (!hiddenTextarea) {
hiddenTextarea = document.createElement('textarea');

View File

@@ -130,7 +130,7 @@
&-addon,
&-wrap {
width: 1%;
width: 1px; // To make addon/wrap as small as possible
white-space: nowrap;
vertical-align: middle;
}

View File

@@ -33,10 +33,6 @@
&:hover {
border-color: @border-color-base;
}
form & {
padding-top: 6px;
padding-bottom: 6px;
}
}
&&-focus .@{ant-prefix}-search-btn-noempty,
&:hover .@{ant-prefix}-search-btn-noempty {

View File

@@ -30,52 +30,53 @@ export interface ColProps {
style?: React.CSSProperties;
}
const Col: React.StatelessComponent<ColProps> = (props) => {
const [{ span, order, offset, push, pull, className, children, prefixCls = 'ant-col' }, others] = splitObject(props,
['span', 'order', 'offset', 'push', 'pull', 'className', 'children', 'prefixCls']);
let sizeClassObj = {};
['xs', 'sm', 'md', 'lg'].forEach(size => {
let sizeProps: ColSize = {};
if (typeof props[size] === 'number') {
sizeProps.span = props[size];
} else if (typeof props[size] === 'object') {
sizeProps = props[size] || {};
}
export default class Col extends React.Component<ColProps, any> {
static propTypes = {
span: stringOrNumber,
order: stringOrNumber,
offset: stringOrNumber,
push: stringOrNumber,
pull: stringOrNumber,
className: PropTypes.string,
children: PropTypes.node,
xs: objectOrNumber,
sm: objectOrNumber,
md: objectOrNumber,
lg: objectOrNumber,
};
delete others[size];
render() {
const props = this.props;
const [{ span, order, offset, push, pull, className, children, prefixCls = 'ant-col' }, others] = splitObject(props,
['span', 'order', 'offset', 'push', 'pull', 'className', 'children', 'prefixCls']);
let sizeClassObj = {};
['xs', 'sm', 'md', 'lg'].forEach(size => {
let sizeProps: ColSize = {};
if (typeof props[size] === 'number') {
sizeProps.span = props[size];
} else if (typeof props[size] === 'object') {
sizeProps = props[size] || {};
}
sizeClassObj = assign({}, sizeClassObj, {
[`${prefixCls}-${size}-${sizeProps.span}`]: sizeProps.span !== undefined,
[`${prefixCls}-${size}-order-${sizeProps.order}`]: sizeProps.order,
[`${prefixCls}-${size}-offset-${sizeProps.offset}`]: sizeProps.offset,
[`${prefixCls}-${size}-push-${sizeProps.push}`]: sizeProps.push,
[`${prefixCls}-${size}-pull-${sizeProps.pull}`]: sizeProps.pull,
delete others[size];
sizeClassObj = assign({}, sizeClassObj, {
[`${prefixCls}-${size}-${sizeProps.span}`]: sizeProps.span !== undefined,
[`${prefixCls}-${size}-order-${sizeProps.order}`]: sizeProps.order,
[`${prefixCls}-${size}-offset-${sizeProps.offset}`]: sizeProps.offset,
[`${prefixCls}-${size}-push-${sizeProps.push}`]: sizeProps.push,
[`${prefixCls}-${size}-pull-${sizeProps.pull}`]: sizeProps.pull,
});
});
});
const classes = classNames(assign({}, {
[`${prefixCls}-${span}`]: span !== undefined,
[`${prefixCls}-order-${order}`]: order,
[`${prefixCls}-offset-${offset}`]: offset,
[`${prefixCls}-push-${push}`]: push,
[`${prefixCls}-pull-${pull}`]: pull,
[className]: !!className,
}, sizeClassObj));
const classes = classNames(assign({}, {
[`${prefixCls}-${span}`]: span !== undefined,
[`${prefixCls}-order-${order}`]: order,
[`${prefixCls}-offset-${offset}`]: offset,
[`${prefixCls}-push-${push}`]: push,
[`${prefixCls}-pull-${pull}`]: pull,
[className]: !!className,
}, sizeClassObj));
return <div {...others} className={classes}>{children}</div>;
};
Col.propTypes = {
span: stringOrNumber,
order: stringOrNumber,
offset: stringOrNumber,
push: stringOrNumber,
pull: stringOrNumber,
className: PropTypes.string,
children: PropTypes.node,
xs: objectOrNumber,
sm: objectOrNumber,
md: objectOrNumber,
lg: objectOrNumber,
};
export default Col;
return <div {...others} className={classes}>{children}</div>;
}
}

View File

@@ -13,6 +13,7 @@ export interface LocaleProviderProps {
Transfer?: Object,
Select?: Object,
};
children: any;
}
export default class LocaleProvider extends React.Component<LocaleProviderProps, any> {

View File

@@ -0,0 +1,41 @@
---
order: 3
title:
zh-CN: 受控模式
en-US: Controlled
---
## zh-CN
受控模式.
## en-US
Controlled mode.
````jsx
import { Mention } from 'antd';
const { toEditorState } = Mention;
const App = React.createClass({
getInitialState() {
return {
value: toEditorState('@afc163'),
};
},
handleChange(editorState) {
this.setState({
value: editorState,
});
},
render() {
return (<Mention
suggestions={['afc163', 'benjycui', 'yiminghe', 'RaoHai', '中文', 'にほんご']}
value={this.state.value}
onChange={this.handleChange}
/>);
},
});
ReactDOM.render(<App />, mountNode);
````

View File

@@ -1,8 +1,8 @@
---
order: 3
order: 4
title:
zh-CN: 受控模式
en-US: Controlled
zh-CN: 配合 Form 使用
en-US: With Form
---
## zh-CN

View File

@@ -1,5 +1,5 @@
---
order: 4
order: 5
title:
zh-CN: 多行
en-US: Multi-lines Mode

View File

@@ -31,7 +31,6 @@ export default class Mention extends React.Component<MentionProps, MentionState>
static getMentions = getMentions;
static defaultProps = {
prefixCls: 'ant-mention',
suggestions: [],
notFoundContent: '无匹配结果,轻敲空格完成输入',
loading: false,
multiLines: false,
@@ -65,7 +64,7 @@ export default class Mention extends React.Component<MentionProps, MentionState>
defaultSearchChange(value: String): void {
const searchValue = value.toLowerCase();
const filteredSuggestions = this.props.suggestions.filter(
const filteredSuggestions = (this.props.suggestions || []).filter(
suggestion => suggestion.toLowerCase().indexOf(searchValue) !== -1
);
this.setState({
@@ -74,7 +73,7 @@ export default class Mention extends React.Component<MentionProps, MentionState>
}
render() {
const { className, prefixCls, style, multiLines, defaultValue } = this.props;
const { className = '', prefixCls, style, multiLines, defaultValue } = this.props;
let { notFoundContent } = this.props;
const { suggestions, focus } = this.state;

View File

@@ -37,7 +37,7 @@ const Sider = React.createClass({
render() {
return (
<div>
<Switch onChange={this.changeTheme} checkedChildren={<Icon type="eye" />} unCheckedChildren={<Icon type="eye-o" />} />
<Switch onChange={this.changeTheme} checkedChildren="Dark" unCheckedChildren="Light" />
<br />
<br />
<Menu theme={this.state.theme}

View File

@@ -3,9 +3,6 @@ import RcMenu, { Item, Divider, SubMenu, ItemGroup } from 'rc-menu';
import animation from '../_util/openAnimation';
import warning from 'warning';
function noop() {
}
export interface SelectParam {
key: string;
keyPath: Array<string>;
@@ -61,8 +58,6 @@ export default class Menu extends React.Component<MenuProps, any> {
static ItemGroup = ItemGroup;
static defaultProps = {
prefixCls: 'ant-menu',
onClick: noop,
onOpenChange: noop,
className: '',
theme: 'light', // or dark
};
@@ -90,11 +85,19 @@ export default class Menu extends React.Component<MenuProps, any> {
}
handleClick = (e) => {
this.setOpenKeys([]);
this.props.onClick(e);
const onClick = this.props.onClick;
if (onClick) {
onClick(e);
}
}
handleOpenChange = (openKeys: string[]) => {
this.setOpenKeys(openKeys);
this.props.onOpenChange(openKeys);
const onOpenChange = this.props.onOpenChange;
if (onOpenChange) {
onOpenChange(openKeys);
}
}
setOpenKeys(openKeys) {
if (!('openKeys' in this.props)) {

View File

@@ -244,14 +244,12 @@
top: 1px;
float: left;
border-bottom: 2px solid transparent;
z-index: 2;
&:hover,
&-active,
&-selected {
border-bottom: 2px solid @primary-color;
color: @primary-color;
transform: translateZ(0);
}
> a {

10
components/message/index.tsx Normal file → Executable file
View File

@@ -23,7 +23,7 @@ function notice(
content: React.ReactNode,
duration: number = defaultDuration,
type: NoticeType,
onClose: () => void) {
onClose?: () => void) {
let iconType = ({
info: 'info-circle',
success: 'check-circle',
@@ -55,7 +55,7 @@ function notice(
type ConfigContent = React.ReactNode | string;
type ConfigDuration = number;
type ConfigOnClose = () => void;
export type ConfigOnClose = () => void;
export interface ConfigOptions {
top?: number;
@@ -85,13 +85,13 @@ export default {
},
config(options: ConfigOptions) {
if ('top' in options) {
if (options.top !== undefined) {
defaultTop = options.top;
}
if ('duration' in options) {
if (options.duration !== undefined) {
defaultDuration = options.duration;
}
if ('prefixCls' in options) {
if (options.prefixCls !== undefined) {
prefixCls = options.prefixCls;
}
},

View File

@@ -4,8 +4,6 @@ import Dialog from 'rc-dialog';
import addEventListener from 'rc-util/lib/Dom/addEventListener';
import Button from '../button';
function noop() {}
let mousePosition;
let mousePositionEventBinded;
@@ -21,7 +19,7 @@ export interface ModalProps {
/** 点击确定回调*/
onOk?: () => void;
/** 点击模态框右上角叉、取消按钮、Props.maskClosable 值为 true 时的遮罩层或键盘按下 Esc 时的回调*/
onCancel?: (e: React.MouseEvent) => void;
onCancel?: (e: React.MouseEvent<any>) => void;
/** 宽度*/
width?: string | number;
/** 底部内容*/
@@ -55,8 +53,6 @@ export default class Modal extends React.Component<ModalProps, any> {
static defaultProps = {
prefixCls: 'ant-modal',
onOk: noop,
onCancel: noop,
width: 520,
transitionName: 'zoom',
maskTransitionName: 'fade',
@@ -86,11 +82,17 @@ export default class Modal extends React.Component<ModalProps, any> {
context: ModalContext;
handleCancel = (e) => {
this.props.onCancel(e);
const onCancel = this.props.onCancel;
if (onCancel) {
onCancel(e);
}
}
handleOk = () => {
this.props.onOk();
const onOk = this.props.onOk;
if (onOk) {
onOk();
}
}
componentDidMount() {

View File

@@ -101,7 +101,7 @@ export default function confirm(config) {
</div>
);
let footer = null;
let footer: React.ReactElement<any> | null = null;
if (props.okCancel) {
footer = (
<div className={`${prefixCls}-btns`}>

19
components/notification/index.tsx Normal file → Executable file
View File

@@ -92,8 +92,19 @@ function notice(args) {
});
}
const api = {
open(args) {
const api: {
success?(args: ArgsProps): void;
error?(args: ArgsProps): void;
info?(args: ArgsProps): void;
warn?(args: ArgsProps): void;
warning?(args: ArgsProps): void;
open(args: ArgsProps): void;
close(key: string): void;
config(options: ConfigProps): void;
destroy(): void;
} = {
open(args: ArgsProps) {
notice(args);
},
close(key) {
@@ -102,10 +113,10 @@ const api = {
}
},
config(options: ConfigProps) {
if ('top' in options) {
if (options.top !== undefined) {
defaultTop = options.top;
}
if ('duration' in options) {
if (options.duration !== undefined) {
defaultDuration = options.duration;
}
},

View File

@@ -4,8 +4,6 @@ import Icon from '../icon';
import Button from '../button';
import splitObject from '../_util/splitObject';
const noop = () => {};
export interface PopconfirmProps {
/**
* Position of popup-container, options:`top`, `left`, `right`, `bottom`
@@ -46,9 +44,6 @@ export default class Popconfirm extends React.Component<PopconfirmProps, any> {
transitionName: 'zoom-big',
placement: 'top',
trigger: 'click',
onConfirm: noop,
onCancel: noop,
onVisibleChange: noop,
};
static contextTypes = {
@@ -72,12 +67,20 @@ export default class Popconfirm extends React.Component<PopconfirmProps, any> {
confirm = () => {
this.setVisible(false);
this.props.onConfirm.call(this);
const onConfirm = this.props.onConfirm;
if (onConfirm) {
onConfirm.call(this);
}
}
cancel = () => {
this.setVisible(false);
this.props.onCancel.call(this);
const onCancel = this.props.onCancel;
if (onCancel) {
onCancel.call(this);
}
}
onVisibleChange = (visible) => {
@@ -88,7 +91,11 @@ export default class Popconfirm extends React.Component<PopconfirmProps, any> {
if (!('visible' in this.props)) {
this.setState({ visible });
}
this.props.onVisibleChange(visible);
const onVisibleChange = this.props.onVisibleChange;
if (onVisibleChange) {
onVisibleChange(visible);
}
}
render() {

View File

@@ -1,4 +1,5 @@
import React from 'react';
import assign from 'object-assign';
import Tooltip from '../tooltip';
export interface PopoverProps {
@@ -11,7 +12,7 @@ export interface PopoverProps {
placement?: 'top' | 'left' | 'right' | 'bottom' | 'topLeft' | 'topRight' |
'bottomLeft' | 'bottomRight' | 'leftTop' | 'leftBottom' | 'rightTop' | 'rightBottom';
/** title of popup-container */
title?: React.ReactNode | string;
title?: React.ReactNode;
/** classname of popup-container */
overlayClassName?: string;
/** Style of overlay */
@@ -43,10 +44,12 @@ export default class Popover extends React.Component<PopoverProps, any> {
};
render() {
const props = assign({}, this.props);
delete props.title;
return (
<Tooltip
ref="tooltip"
{...this.props}
{...props}
overlay={this.getOverlay()}
/>
);

View File

@@ -52,7 +52,6 @@
}
&-inner {
min-width: @popover-min-width;
background-color: @popover-bg;
background-clip: padding-box;
border-radius: @border-radius-base;
@@ -60,6 +59,7 @@
}
&-title {
min-width: @popover-min-width;
margin: 0; // reset heading margin
padding: 0 16px;
line-height: 32px;

View File

@@ -2,7 +2,7 @@ import React from 'react';
import classNames from 'classnames';
import Radio from './radio';
import RadioButton from './radioButton';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import PureRenderMixin from 'rc-util/lib/PureRenderMixin';
import assign from 'object-assign';
function getCheckedValue(children) {
@@ -19,7 +19,7 @@ function getCheckedValue(children) {
export interface RadioGroupProps {
/** 选项变化时的回调函数*/
onChange?: React.FormEventHandler;
onChange?: React.FormEventHandler<any>;
/** 用于设置当前选中的值*/
value?: string | number;
/** 默认选中的值*/
@@ -33,10 +33,7 @@ export interface RadioGroupProps {
export default class RadioGroup extends React.Component<RadioGroupProps, any> {
static defaultProps = {
prefixCls: 'ant-radio-group',
disabled: false,
onChange() {
},
};
constructor(props) {
super(props);
@@ -76,11 +73,15 @@ export default class RadioGroup extends React.Component<RadioGroupProps, any> {
value: ev.target.value,
});
}
this.props.onChange(ev);
const onChange = this.props.onChange;
if (onChange) {
onChange(ev);
}
}
render() {
const props = this.props;
const children = React.Children.map(props.children, (radio: any) => {
const children = React.Children.map((props.children || {}), (radio: any) => {
if (radio && (radio.type === Radio || radio.type === RadioButton) && radio.props) {
const keyProps = {};
if (!('key' in radio) && typeof radio.props.value === 'string') {
@@ -94,9 +95,10 @@ export default class RadioGroup extends React.Component<RadioGroupProps, any> {
}
return radio;
});
const prefixCls = props.prefixCls || 'ant-radio-group';
const classString = classNames({
[props.prefixCls]: true,
[`${props.prefixCls}-${props.size}`]: props.size,
[prefixCls]: true,
[`${prefixCls}-${props.size}`]: props.size,
});
return <div className={classString} style={props.style}>{children}</div>;
}

View File

@@ -1,7 +1,7 @@
import RcRadio from 'rc-radio';
import React from 'react';
import classNames from 'classnames';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import PureRenderMixin from 'rc-util/lib/PureRenderMixin';
export interface RadioProps {
/** 指定当前是否选中*/
@@ -28,7 +28,7 @@ export default class Radio extends React.Component<RadioProps, any> {
return PureRenderMixin.shouldComponentUpdate.apply(this, args);
}
render() {
const { prefixCls, children, checked, disabled, className, style } = this.props;
const { prefixCls, children, checked, disabled, className = '', style } = this.props;
const wrapperClassString = classNames({
[`${prefixCls}-wrapper`]: true,
[`${prefixCls}-wrapper-checked`]: checked,

View File

@@ -181,7 +181,8 @@ span.@{radio-prefix-cls} + * {
}
.@{radio-prefix-cls}-inner,
input {
input[type="checkbox"],
input[type="radio"] {
.opacity(0);
width: 0;
height: 0;

View File

@@ -42,7 +42,10 @@ A Selector similar to Select2.
| size | Size of Select input. `large` `small` | String | default |
| showSearch | Whether show search input in single mode.| boolean | false |
| disabled | Whether disabled select | boolean | false |
| getPopupContainer | Parent Node which the selector should be rendered to. Default to `body`. When position issues happen, try to modify it into scrollable content and position it relative.[example](http://codepen.io/anon/pen/xVBOVQ?editors=001) | Function(triggerNode) | () => document.body |
| dropdownStyle | style of dropdown menu | object | - |
| dropdownClassName | className of dropdown menu | string | - |
| getPopupContainer | Parent Node which the selector should be rendered to. Default to `body`. When position issues happen, try to modify it into scrollable content and position it relative.[example](http://codepen.io/anon/pen/xVBOVQ?editors=001) | function(triggerNode) | () => document.body |
| labelInValue | whether to embed label in value | boolean | false |
### Option props

9
components/select/index.tsx Normal file → Executable file
View File

@@ -13,7 +13,7 @@ export interface SelectProps {
defaultValue?: SelectValue;
size?: 'default' | 'large' | 'small';
combobox?: boolean;
notFoundContent?: React.ReactNode | string;
notFoundContent?: React.ReactNode | null;
showSearch?: boolean;
transitionName?: string;
choiceTransitionName?: string;
@@ -35,7 +35,7 @@ export interface SelectProps {
style?: React.CSSProperties;
dropdownStyle?: React.CSSProperties;
dropdownMenuStyle?: React.CSSProperties;
onChange?: (value) => void;
onChange?: (value: SelectValue) => void;
}
export interface OptionProps {
@@ -53,7 +53,8 @@ export interface SelectContext {
};
}
export { Option, OptGroup };
// => It is needless to export the declaration of below two inner components.
// export { Option, OptGroup };
export default class Select extends React.Component<SelectProps, any> {
static Option = Option as React.ClassicComponentClass<OptionProps>;
@@ -83,7 +84,7 @@ export default class Select extends React.Component<SelectProps, any> {
render() {
const {
prefixCls,
className,
className = '',
size,
combobox,
showSearch,

View File

@@ -44,6 +44,8 @@ title: Select
| showSearch | 在选择框中显示搜索框 | boolean | false |
| disabled | 是否禁用 | boolean | false |
| defaultActiveFirstOption | 是否默认高亮第一个选项。 | boolean | true
| dropdownStyle | 下拉菜单的 style 属性 | object | - |
| dropdownClassName | 下拉菜单的 className 属性 | string | - |
| getPopupContainer | 菜单渲染父节点。默认渲染到 body 上,如果你遇到菜单滚动定位问题,试试修改为滚动的区域,并相对其定位。[示例](http://codepen.io/anon/pen/xVBOVQ?editors=001) | Function(triggerNode) | () => document.body |
| labelInValue | 是否把每个选项的 label 包装到 value 中,决定 Select 的 value 类型。 | boolean | false |

View File

@@ -38,7 +38,6 @@
box-sizing: border-box;
display: inline-block;
position: relative;
vertical-align: middle;
color: #666;
font-size: @font-size-base;
@@ -96,6 +95,15 @@
&:hover &__clear {
opacity: 1;
}
&-selected-value {
float: left;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 100%;
padding-right: 16px;
}
}
&-disabled {
@@ -132,33 +140,31 @@
height: 28px;
position: relative;
cursor: pointer;
.@{select-prefix-cls}-selection__rendered {
height: 26px;
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
padding-left: 8px;
padding-right: 24px;
line-height: 26px;
}
}
&-open&-show-search &-selection--single &-selection-selected-value {
position: absolute;
left: 8px;
top: 0;
&-selection__rendered {
display: block;
margin-left: 8px;
margin-right: 8px;
position: relative;
line-height: 26px;
// https://github.com/ant-design/ant-design/issues/3481#issuecomment-254721026
&:after {
content: '.';
visibility: hidden;
pointer-events: none;
display: inline-block;
width: 0;
}
}
&-lg {
.@{select-prefix-cls}-selection--single {
height: 32px;
.@{select-prefix-cls}-selection__rendered {
line-height: 30px;
}
}
.@{select-prefix-cls}-selection__rendered {
line-height: 30px;
}
.@{select-prefix-cls}-selection--multiple {
min-height: 32px;
.@{select-prefix-cls}-selection__rendered {
@@ -176,9 +182,9 @@
}
.@{select-prefix-cls}-selection--single {
height: 22px;
.@{select-prefix-cls}-selection__rendered {
line-height: 20px;
}
}
.@{select-prefix-cls}-selection__rendered {
line-height: 20px;
}
.@{select-prefix-cls}-selection--multiple {
min-height: 22px;
@@ -208,7 +214,7 @@
&-search__field__placeholder { // for TreeSelect compatibility
position: absolute;
top: 50%;
left: 9px;
left: 0;
right: 9px;
color: #ccc;
line-height: 20px;
@@ -222,7 +228,6 @@
&-search--inline {
position: absolute;
width: 100%;
height: 100%;
.@{select-prefix-cls}-selection--multiple & {
@@ -239,6 +244,7 @@
border: 0;
font-size: 100%;
height: 100%;
width: 100%;
background: transparent;
outline: 0;
border-radius: @border-radius-base;
@@ -247,7 +253,7 @@
.@{select-prefix-cls}-search__field__mirror {
position: absolute;
top: 0;
left: 9999px;
left: -9999px;
white-space: pre;
pointer-events: none;
}
@@ -260,24 +266,26 @@
&-selection--multiple {
min-height: 28px;
cursor: text;
padding-bottom: 3px;
.clearfix;
.@{select-prefix-cls}-search--inline {
width: auto;
padding: 0;
.@{select-prefix-cls}-search__field {
width: 0.75em;
}
}
.@{select-prefix-cls}-selection__rendered {
overflow: hidden;
text-overflow: ellipsis;
padding-left: 6px;
padding-bottom: 4px;
margin-left: 5px;
margin-bottom: -3px;
height: auto;
}
> ul > li,
.@{select-prefix-cls}-selection__rendered > ul > li { // for tree-select
margin-top: 4px;
margin-top: 3px;
height: 20px;
line-height: 20px;
}
@@ -348,6 +356,7 @@
}
.@{select-prefix-cls}-search--inline {
height: 100%;
width: 100%;
float: none;
}
.@{select-prefix-cls}-search__field__wrap {
@@ -355,7 +364,6 @@
height: 100%;
}
.@{select-prefix-cls}-search__field {
padding: 0 10px;
width: 100%;
height: 100%;
position: relative;
@@ -364,7 +372,7 @@
box-shadow: none;
}
.@{select-prefix-cls}-selection__rendered {
padding: 0 24px 0 0;
padding: 0;
height: 100%;
position: absolute;
left: 0;
@@ -489,6 +497,8 @@
.iconfont-size-under-12px(10px);
transition: all 0.2s ease;
position: absolute;
top: 50%;
transform: translateY(-50%);
right: 16px;
font-weight: bold;
text-shadow: 0 0.1px 0, 0.1px 0 0, 0 -0.1px 0, -0.1px 0;

View File

@@ -54,10 +54,12 @@
border: solid 2px tint(@primary-color, 50%);
background-color: #fff;
z-index: 2;
transition: border-color 0.3s ease;
transition: border-color 0.3s ease, transform .3s cubic-bezier(0.18, 0.89, 0.32, 1.28);
&:hover {
border-color: tint(@primary-color, 20%);
transform: scale(1.2);
transform-origin: center center;
}
&:active {

View File

@@ -182,8 +182,10 @@
.@{iconfont-css-prefix}-hdd:before { content: "\e69a"; }
.@{iconfont-css-prefix}-ie:before { content: "\e69b"; }
.@{iconfont-css-prefix}-file-jpg:before { content: "\e69c"; }
.@{iconfont-css-prefix}-like:before { content: "\e69d"; }
.@{iconfont-css-prefix}-dislike:before { content: "\e69e"; }
.@{iconfont-css-prefix}-like:before { content: "\e64c"; }
.@{iconfont-css-prefix}-like-o:before { content: "\e69d"; }
.@{iconfont-css-prefix}-dislike:before { content: "\e64b"; }
.@{iconfont-css-prefix}-dislike-o:before { content: "\e69e"; }
.@{iconfont-css-prefix}-delete:before { content: "\e69f"; }
.@{iconfont-css-prefix}-enter:before { content: "\e6a0"; }
.@{iconfont-css-prefix}-pushpin-o:before { content: "\e6a1"; }
@@ -232,3 +234,10 @@
.@{iconfont-css-prefix}-down-square-o:before { content: "\e6ce"; }
.@{iconfont-css-prefix}-up-square-o:before { content: "\e6cf"; }
.@{iconfont-css-prefix}-loading:before { content: "\e6ae"; }
.@{iconfont-css-prefix}-bulb:before { content: "\e649"; }
.@{iconfont-css-prefix}-select:before { content: "\e64a"; }
.@{iconfont-css-prefix}-spin {
display: inline-block;
animation: loadingCircle 1.6s infinite linear;
}

View File

@@ -23,7 +23,7 @@
// ICONFONT
@iconfont-css-prefix : anticon;
@icon-url : "https://at.alicdn.com/t/font_1473840929_824008";
@icon-url : "https://at.alicdn.com/t/font_pldm8phsjkathuxr";
// LINK
@link-color : #2db7f5;

View File

@@ -29,6 +29,5 @@ ReactDOM.render(
<style>
.ant-switch {
margin-bottom: 8px;
display: block;
}
<style>

View File

@@ -31,6 +31,7 @@ const Test = React.createClass({
return (
<div>
<Switch disabled={this.state.disabled} />
<br />
<Button type="primary" onClick={this.toggle}>Toggle disabled</Button>
</div>
);

View File

@@ -19,6 +19,7 @@ import { Switch } from 'antd';
ReactDOM.render(
<div>
<Switch />
<br />
<Switch size="small" />
</div>
, mountNode);

View File

@@ -18,7 +18,9 @@ import { Switch, Icon } from 'antd';
ReactDOM.render(<div>
<Switch checkedChildren={'开'} unCheckedChildren={'关'} />
<br />
<Switch checkedChildren="1" unCheckedChildren="0" />
<br />
<Switch checkedChildren={<Icon type="check" />} unCheckedChildren={<Icon type="cross" />} />
</div>, mountNode);
````

3
components/switch/index.tsx Normal file → Executable file
View File

@@ -12,6 +12,7 @@ export interface SwitchProps {
onChange?: (checked: boolean) => any;
checkedChildren?: React.ReactNode;
unCheckedChildren?: React.ReactNode;
disabled?: boolean;
}
export default class Switch extends React.Component<SwitchProps, any> {
@@ -27,7 +28,7 @@ export default class Switch extends React.Component<SwitchProps, any> {
};
render() {
const { prefixCls, size, className } = this.props;
const { prefixCls, size, className = '' } = this.props;
const classes = classNames({
[className]: !!className,
[`${prefixCls}-small`]: size === 'small',

View File

@@ -8,22 +8,23 @@
position: relative;
display: inline-block;
box-sizing: border-box;
width: 44px;
height: 22px;
min-width: 44px;
line-height: 20px;
vertical-align: middle;
border-radius: 20px;
border: 1px solid #ccc;
background-color: #ccc;
cursor: pointer;
transition: all @switch-duration @ease-in-out-circ;
transition: all @switch-duration;
user-select: none;
&-inner {
color: #fff;
font-size: 12px;
position: absolute;
left: 24px;
margin-left: 24px;
margin-right: 6px;
display: block;
}
&:after {
@@ -32,11 +33,12 @@
height: 18px;
left: 2px;
top: 1px;
border-radius: 18px;
background-color: #fff;
content: " ";
cursor: pointer;
transition: left @switch-duration @ease-in-out-circ, width @switch-duration @ease-in-out-circ;
transition: all @switch-duration, width @switch-duration;
}
&:active:after {
@@ -54,23 +56,40 @@
&-small {
height: 14px;
min-width: 28px;
line-height: 12px;
width: 28px;
.@{switch-prefix-cls}-inner {
margin-left: 18px;
margin-right: 3px;
}
&:after {
width: 12px;
height: 12px;
top: 0;
left: 0;
}
&:active:after {
width: 16px;
}
}
&-small&-checked:after {
left: 14px;
&-small&-checked {
&:after {
left: 100%;
margin-left: -12px;
}
.@{switch-prefix-cls}-inner {
margin-left: 3px;
margin-right: 18px;
}
}
&-small:active&-checked:after {
left: 10px;
}
@@ -80,11 +99,13 @@
background-color: @primary-color;
.@{switch-prefix-cls}-inner {
left: 6px;
margin-left: 6px;
margin-right: 24px;
}
&:after {
left: 22px;
left: 100%;
margin-left: -20px;
}
&:active:after {

View File

@@ -0,0 +1,13 @@
import React from 'react';
export interface FilterDropdownMenuWrapperProps {
onClick?: React.MouseEventHandler<any>;
children?: any;
className?: string;
}
export default class FilterDropdownMenuWrapper extends React.Component<FilterDropdownMenuWrapperProps, any> {
render() {
const { onClick, children, className } = this.props;
return <div className={className} onClick={onClick}>{children}</div>;
}
}

101
components/table/Table.tsx Normal file → Executable file
View File

@@ -34,22 +34,22 @@ const defaultPagination = {
onShowSizeChange: noop,
};
export interface TableRowSelection {
export interface TableRowSelection<T> {
type?: 'checkbox' | 'radio';
selectedRowKeys?: string[];
onChange?: (selectedRowKeys: string[], selectedRows: Object[]) => any;
getCheckboxProps?: (record: Object) => Object;
onSelect?: (record: Object, selected: boolean, selectedRows: Object[]) => any;
getCheckboxProps?: (record: T) => Object;
onSelect?: (record: T, selected: boolean, selectedRows: Object[]) => any;
onSelectAll?: (selected: boolean, selectedRows: Object[], changeRows: Object[]) => any;
}
export interface TableColumnConfig {
export interface TableColumnConfig<T> {
title?: React.ReactNode;
key?: string;
dataIndex?: string;
render?: (text: any, record: Object, index: number) => React.ReactNode;
render?: (text: any, record: T, index: number) => React.ReactNode;
filters?: { text: string; value: string }[];
onFilter?: (value: any, record: Object) => boolean;
onFilter?: (value: any, record: T) => boolean;
filterMultiple?: boolean;
filterDropdown?: React.ReactNode;
sorter?: boolean | ((a: any, b: any) => number);
@@ -61,16 +61,16 @@ export interface TableColumnConfig {
sortOrder?: boolean | ('ascend' | 'descend');
}
export interface TableProps {
export interface TableProps<T> {
prefixCls?: string;
dropdownPrefixCls?: string;
rowSelection?: TableRowSelection;
rowSelection?: TableRowSelection<T>;
pagination?: PaginationProps | boolean;
size?: 'default' | 'small';
dataSource?: Object[];
columns?: TableColumnConfig[];
rowKey?: string | ((record: Object, index: number) => string);
rowClassName?: (record: Object, index: number) => string;
dataSource?: T[];
columns: TableColumnConfig<T>[];
rowKey?: string | ((record: T, index: number) => string);
rowClassName?: (record: T, index: number) => string;
expandedRowRender?: any;
defaultExpandedRowKeys?: string[];
expandedRowKeys?: string[];
@@ -80,14 +80,14 @@ export interface TableProps {
loading?: boolean;
locale?: Object;
indentSize?: number;
onRowClick?: (record: Object, index: number) => any;
onRowClick?: (record: T, index: number) => any;
useFixedHeader?: boolean;
bordered?: boolean;
showHeader?: boolean;
footer?: (currentPageData: Object[]) => React.ReactNode;
title?: (currentPageData: Object[]) => React.ReactNode;
scroll?: { x?: boolean | number, y?: boolean | number};
childrenColumnName?: 'string';
childrenColumnName?: string;
bodyStyle?: React.CSSProperties;
className?: string;
}
@@ -98,7 +98,7 @@ export interface TableContext {
};
}
export default class Table extends React.Component<TableProps, any> {
export default class Table<T> extends React.Component<TableProps<T>, any> {
static propTypes = {
dataSource: React.PropTypes.array,
columns: React.PropTypes.array.isRequired,
@@ -117,7 +117,6 @@ export default class Table extends React.Component<TableProps, any> {
static defaultProps = {
dataSource: [],
prefixCls: 'ant-table',
dropdownPrefixCls: 'ant-dropdown',
useFixedHeader: false,
rowSelection: null,
className: '',
@@ -125,10 +124,8 @@ export default class Table extends React.Component<TableProps, any> {
loading: false,
bordered: false,
indentSize: 20,
onChange: noop,
locale: {},
rowKey: 'key',
childrenColumnName: 'children',
};
static contextTypes = {
@@ -361,7 +358,10 @@ export default class Table extends React.Component<TableProps, any> {
this.setState(newState);
}
this.props.onChange.apply(null, this.prepareParamsArguments(assign({}, this.state, newState)));
const onChange = this.props.onChange;
if (onChange) {
onChange.apply(null, this.prepareParamsArguments(assign({}, this.state, newState)));
}
}
handleFilter = (column, nextFilters) => {
@@ -409,11 +409,14 @@ export default class Table extends React.Component<TableProps, any> {
}
this.setState(newState, () => {
props.onChange.apply(null, this.prepareParamsArguments(assign({}, this.state, {
selectionDirty: false,
filters,
pagination,
})));
const onChange = this.props.onChange;
if (onChange) {
onChange.apply(null, this.prepareParamsArguments(assign({}, this.state, {
selectionDirty: false,
filters,
pagination,
})));
}
});
}
@@ -463,7 +466,7 @@ export default class Table extends React.Component<TableProps, any> {
.map((item, i) => this.getRecordKey(item, i));
// 记录变化的列
const changeRowKeys = [];
const changeRowKeys: string[] = [];
if (checked) {
changableRowKeys.forEach(key => {
if (selectedRowKeys.indexOf(key) < 0) {
@@ -511,13 +514,16 @@ export default class Table extends React.Component<TableProps, any> {
}
this.setState(newState);
this.props.onChange.apply(null, this.prepareParamsArguments(assign({}, this.state, {
selectionDirty: false,
pagination,
})));
const onChange = this.props.onChange;
if (onChange) {
onChange.apply(null, this.prepareParamsArguments(assign({}, this.state, {
selectionDirty: false,
pagination,
})));
}
}
renderSelectionRadio = (value, record, index) => {
renderSelectionRadio = (_, record, index) => {
let rowIndex = this.getRecordKey(record, index); // 从 1 开始
const props = this.getCheckboxPropsByItem(record);
let checked;
@@ -537,7 +543,7 @@ export default class Table extends React.Component<TableProps, any> {
);
}
renderSelectionCheckBox = (value, record, index) => {
renderSelectionCheckBox = (_, record, index) => {
let rowIndex = this.getRecordKey(record, index); // 从 1 开始
let checked;
if (this.state.selectionDirty) {
@@ -558,7 +564,7 @@ export default class Table extends React.Component<TableProps, any> {
);
}
getRecordKey(record, index?) {
getRecordKey(record, index?): string {
const rowKey = this.props.rowKey;
if (typeof rowKey === 'function') {
return rowKey(record, index);
@@ -584,11 +590,11 @@ export default class Table extends React.Component<TableProps, any> {
}
renderRowSelection() {
const prefixCls = this.props.prefixCls;
const { prefixCls, rowSelection } = this.props;
const columns = this.props.columns.concat();
if (this.props.rowSelection) {
if (rowSelection) {
const data = this.getFlatCurrentPageData().filter((item) => {
if (this.props.rowSelection.getCheckboxProps) {
if (rowSelection.getCheckboxProps) {
return !this.getCheckboxPropsByItem(item).disabled;
}
return true;
@@ -617,7 +623,7 @@ export default class Table extends React.Component<TableProps, any> {
);
}
let selectionColumn;
if (this.props.rowSelection.type === 'radio') {
if (rowSelection.type === 'radio') {
selectionColumn = {
key: 'selection-column',
render: this.renderSelectionRadio,
@@ -689,7 +695,7 @@ export default class Table extends React.Component<TableProps, any> {
selectedKeys={colFilters}
confirmFilter={this.handleFilter}
prefixCls={`${prefixCls}-filter`}
dropdownPrefixCls={dropdownPrefixCls}
dropdownPrefixCls={dropdownPrefixCls || 'ant-dropdown'}
/>
);
}
@@ -736,9 +742,13 @@ export default class Table extends React.Component<TableProps, any> {
pagination.onShowSizeChange(current, pageSize);
const nextPagination = assign({}, pagination, { pageSize, current });
this.setState({ pagination: nextPagination });
this.props.onChange.apply(null, this.prepareParamsArguments(assign({}, this.state, {
pagination: nextPagination,
})));
const onChange = this.props.onChange;
if (onChange) {
onChange.apply(null, this.prepareParamsArguments(assign({}, this.state, {
pagination: nextPagination,
})));
}
}
renderPagination() {
@@ -750,7 +760,7 @@ export default class Table extends React.Component<TableProps, any> {
const { pagination } = this.state;
if (pagination.size) {
size = pagination.size;
} else if (this.props.size === 'middle' || this.props.size === 'small') {
} else if (this.props.size as string === 'middle' || this.props.size === 'small') {
size = 'small';
}
let total = pagination.total || this.getLocalData().length;
@@ -803,7 +813,7 @@ export default class Table extends React.Component<TableProps, any> {
// 当数据量少于等于每页数量时,直接设置数据
// 否则进行读取分页数据
if (data.length > pageSize || pageSize === Number.MAX_VALUE) {
data = data.filter((item, i) => {
data = data.filter((_, i) => {
return i >= (current - 1) * pageSize && i < current * pageSize;
});
}
@@ -819,7 +829,7 @@ export default class Table extends React.Component<TableProps, any> {
}
recursiveSort(data, sorterFn) {
const { childrenColumnName } = this.props;
const { childrenColumnName = 'children' } = this.props;
return data.sort(sorterFn).map(item => (item[childrenColumnName] ? assign(
{},
item, {
@@ -849,8 +859,9 @@ export default class Table extends React.Component<TableProps, any> {
if (values.length === 0) {
return;
}
data = col.onFilter ? data.filter(record => {
return values.some(v => col.onFilter(v, record));
const onFilter = col.onFilter;
data = onFilter ? data.filter(record => {
return values.some(v => onFilter(v, record));
}) : data;
});
}

View File

@@ -11,7 +11,7 @@ title:
> 若列头与内容不对齐,请指定每列宽度 `width`。
> 建议指定 scroll.x 为固定宽度。
> 建议指定 `scroll.x` 为固定宽度。注意,非固定列宽度之和不要超过 `scroll.x`。
## en-US
@@ -19,7 +19,7 @@ Suitable for large amounts of data with long columns.
> Specify the width of each column if header and cell do not align properly.
> A fixed width for `scroll.x` is recommended.
> A fixed width for `scroll.x` is recommended. The sum of unfixed columns should not greater than `scroll.x`.
````jsx
import { Table } from 'antd';
@@ -34,7 +34,7 @@ const columns = [
{ title: 'Column 5', dataIndex: 'address', key: '5', width: 150 },
{ title: 'Column 6', dataIndex: 'address', key: '6', width: 150 },
{ title: 'Column 7', dataIndex: 'address', key: '7', width: 150 },
{ title: 'Column 8', dataIndex: 'address', key: '8', width: 150 },
{ title: 'Column 8', dataIndex: 'address', key: '8' },
{
title: 'Action',
key: 'operation',

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