mirror of
https://github.com/ant-design/ant-design.git
synced 2026-02-17 06:42:28 +08:00
Compare commits
154 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e6fd745c26 | ||
|
|
e047bb166f | ||
|
|
4bd107f9d7 | ||
|
|
9eaac3f568 | ||
|
|
0218bee810 | ||
|
|
ee27e87cf0 | ||
|
|
b3b39fcfd5 | ||
|
|
03c10c9a05 | ||
|
|
89574017be | ||
|
|
95cf9f3e48 | ||
|
|
a318c2ed77 | ||
|
|
8fe3c113b6 | ||
|
|
bce044bac2 | ||
|
|
cdfdae51ed | ||
|
|
88615024b1 | ||
|
|
b828741dc0 | ||
|
|
fe47f01796 | ||
|
|
4e68a53d27 | ||
|
|
a383df8870 | ||
|
|
7d3d271aea | ||
|
|
5977d31590 | ||
|
|
3a25ef8d14 | ||
|
|
4378454495 | ||
|
|
1350c87ab1 | ||
|
|
d78d0de36c | ||
|
|
a7597819a2 | ||
|
|
cb0a92e13b | ||
|
|
8c95732bfb | ||
|
|
476ace8aae | ||
|
|
42cd542677 | ||
|
|
96766d4018 | ||
|
|
f99b8a1792 | ||
|
|
b24d5a65a5 | ||
|
|
1817052194 | ||
|
|
7473f9b871 | ||
|
|
0d438610ff | ||
|
|
69d2656ab2 | ||
|
|
97ee28ee7a | ||
|
|
0f547e31d5 | ||
|
|
ecf83c0438 | ||
|
|
0929a8b2c5 | ||
|
|
8f830ec366 | ||
|
|
e0c74501f4 | ||
|
|
1ac6b5782d | ||
|
|
1c02a65593 | ||
|
|
a127ba6789 | ||
|
|
b71301b65f | ||
|
|
839d0dcb09 | ||
|
|
f8fbb33c73 | ||
|
|
1f730faf2d | ||
|
|
f5bf79d2d8 | ||
|
|
af8a025aeb | ||
|
|
e56e1a71c3 | ||
|
|
bfc75f5872 | ||
|
|
2f0580d08b | ||
|
|
843056e58e | ||
|
|
69f0601d13 | ||
|
|
f7bf62de65 | ||
|
|
2bfc23b6f1 | ||
|
|
6106e459a3 | ||
|
|
422b20993b | ||
|
|
f04e6886b6 | ||
|
|
1272ec0e04 | ||
|
|
57a3d96c3b | ||
|
|
51e3012dc6 | ||
|
|
3aeca7c10e | ||
|
|
f706e2554f | ||
|
|
28f6c4891a | ||
|
|
2ac67ddc25 | ||
|
|
dd30678033 | ||
|
|
d23a996b35 | ||
|
|
1fb7bac8ca | ||
|
|
e1d68061d1 | ||
|
|
7abf528b96 | ||
|
|
c2d1d72675 | ||
|
|
7b643d2aaa | ||
|
|
4b0bcee220 | ||
|
|
79f25d1107 | ||
|
|
9a386e7336 | ||
|
|
2e4d2b497a | ||
|
|
c9aeb29b43 | ||
|
|
14fff83a4a | ||
|
|
92e10eb015 | ||
|
|
d0d5481c17 | ||
|
|
30a6d38898 | ||
|
|
21b0f329b9 | ||
|
|
a98e42784e | ||
|
|
2c7112be7b | ||
|
|
68ad468938 | ||
|
|
26936de2e8 | ||
|
|
1b0d37d1f3 | ||
|
|
d4715e1783 | ||
|
|
8b8c133984 | ||
|
|
a140533a26 | ||
|
|
5681d6381a | ||
|
|
219500ee7a | ||
|
|
243a5b6097 | ||
|
|
cf43c19a80 | ||
|
|
933d175f5b | ||
|
|
43f47e0f4a | ||
|
|
3b8dd8152d | ||
|
|
8280c6da80 | ||
|
|
d1650e31e9 | ||
|
|
860809f173 | ||
|
|
9c777231e3 | ||
|
|
2c79d2a7c1 | ||
|
|
377062bc9b | ||
|
|
2d5d71bf85 | ||
|
|
06403f92f3 | ||
|
|
c5462e4d45 | ||
|
|
0574c759cf | ||
|
|
2546a30485 | ||
|
|
05cf557ee1 | ||
|
|
fa007942b2 | ||
|
|
a5df939c2c | ||
|
|
2a66546433 | ||
|
|
a7c1aca7f9 | ||
|
|
75df1e762e | ||
|
|
154e6781ec | ||
|
|
1c9ed454b1 | ||
|
|
d644da4a5d | ||
|
|
fc8a21d03c | ||
|
|
aba8f7e585 | ||
|
|
67ad6262e5 | ||
|
|
1f2945e88e | ||
|
|
87efad2da7 | ||
|
|
62fe5dda35 | ||
|
|
41df6cead4 | ||
|
|
2029762297 | ||
|
|
ee128020e7 | ||
|
|
d554fa82a4 | ||
|
|
cc9b09df13 | ||
|
|
0d246d38bc | ||
|
|
e2ec0c2b48 | ||
|
|
6b6f4625ab | ||
|
|
e7b48e92eb | ||
|
|
4f5355675b | ||
|
|
988a84ab15 | ||
|
|
7e911637e2 | ||
|
|
6ee4c1a290 | ||
|
|
ce2469667d | ||
|
|
4e4c737e9b | ||
|
|
cde6dbe7c3 | ||
|
|
327f78adbb | ||
|
|
c7452f3a9d | ||
|
|
ca56828df7 | ||
|
|
1e0400704b | ||
|
|
13593a9629 | ||
|
|
77cd0c1849 | ||
|
|
5a1c9066f9 | ||
|
|
6b94bd0bb4 | ||
|
|
8d2a42fa91 | ||
|
|
4c6244bd0c | ||
|
|
814980d9c6 |
29
.jest.js
29
.jest.js
@@ -7,25 +7,10 @@ const transformIgnorePatterns = [
|
||||
|
||||
module.exports = {
|
||||
verbose: true,
|
||||
setupFiles: [
|
||||
'./tests/setup.js',
|
||||
],
|
||||
moduleFileExtensions: [
|
||||
'ts',
|
||||
'tsx',
|
||||
'js',
|
||||
'jsx',
|
||||
'json',
|
||||
'md',
|
||||
],
|
||||
modulePathIgnorePatterns: [
|
||||
'/_site/',
|
||||
],
|
||||
testPathIgnorePatterns: [
|
||||
'/node_modules/',
|
||||
'dekko',
|
||||
'node',
|
||||
],
|
||||
setupFiles: ['./tests/setup.js'],
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'md'],
|
||||
modulePathIgnorePatterns: ['/_site/'],
|
||||
testPathIgnorePatterns: ['/node_modules/', 'dekko', 'node'],
|
||||
transform: {
|
||||
'\\.tsx?$': './node_modules/antd-tools/lib/jest/codePreprocessor',
|
||||
'\\.js$': './node_modules/antd-tools/lib/jest/codePreprocessor',
|
||||
@@ -41,12 +26,10 @@ module.exports = {
|
||||
'!components/**/*/interface.{ts,tsx}',
|
||||
],
|
||||
transformIgnorePatterns,
|
||||
snapshotSerializers: [
|
||||
'enzyme-to-json/serializer',
|
||||
],
|
||||
snapshotSerializers: ['enzyme-to-json/serializer'],
|
||||
globals: {
|
||||
'ts-jest': {
|
||||
tsConfigFile: './tsconfig.test.json',
|
||||
tsConfig: './tsconfig.test.json',
|
||||
},
|
||||
},
|
||||
testURL: 'http://localhost',
|
||||
|
||||
@@ -1,14 +1,7 @@
|
||||
// jest config for server render environment
|
||||
module.exports = {
|
||||
setupFiles: [
|
||||
'./tests/setup.js',
|
||||
],
|
||||
moduleFileExtensions: [
|
||||
'ts',
|
||||
'tsx',
|
||||
'js',
|
||||
'md',
|
||||
],
|
||||
setupFiles: ['./tests/setup.js'],
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'md'],
|
||||
transform: {
|
||||
'\\.tsx?$': './node_modules/antd-tools/lib/jest/codePreprocessor',
|
||||
'\\.js$': './node_modules/antd-tools/lib/jest/codePreprocessor',
|
||||
@@ -16,9 +9,7 @@ module.exports = {
|
||||
},
|
||||
testRegex: 'demo\\.test\\.js$',
|
||||
testEnvironment: 'node',
|
||||
snapshotSerializers: [
|
||||
'enzyme-to-json/serializer',
|
||||
],
|
||||
snapshotSerializers: ['enzyme-to-json/serializer'],
|
||||
globals: {
|
||||
'ts-jest': {
|
||||
tsConfigFile: './tsconfig.test.json',
|
||||
|
||||
@@ -15,13 +15,75 @@ timeline: true
|
||||
|
||||
---
|
||||
|
||||
## 3.11.5
|
||||
|
||||
`2018-12-24`
|
||||
|
||||
- 🐞 Fixed `lib` missing css file match. [#13791](https://github.com/ant-design/ant-design/issues/13803)
|
||||
|
||||
## 3.11.4
|
||||
|
||||
`2018-12-23`
|
||||
|
||||
- 🐞 Fixed DependencyNotFoundError `Could not find dependency: '@babel/runtime'`. [#13791](https://github.com/ant-design/ant-design/issues/13791)
|
||||
- ⚡️ Refactor Tag component with less code and better performance. [b828741](https://github.com/ant-design/ant-design/commit/b828741dc06eaa69ff3f8c76024fd5527ed6d74f)
|
||||
|
||||
## 3.11.3 🎅🏻
|
||||
|
||||
`2018-12-22`
|
||||
|
||||
- ⚡️ Upgrade our toolchains (babel and webpack) to latest version and prettier all codes!
|
||||
- Table
|
||||
- 🐞 **Fixed that dropdown menu action not clickable**. [#13563](https://github.com/ant-design/ant-design/issues/13563)
|
||||
- 🐞 Fixed hovering components on Table sortable column. [#13467](https://github.com/ant-design/ant-design/issues/13467)
|
||||
- 🐞 Fixed crash issue of selection Table under IE9/10. [#13540](https://github.com/ant-design/ant-design/issues/13540)
|
||||
- 🐞 Fixed check-all checkbox state when Table `childrenColumnName` is specified. [#13710](https://github.com/ant-design/ant-design/issues/13710)
|
||||
- 💄 Remove work break styles in table cell for consistent behavior. [#13624](https://github.com/ant-design/ant-design/issues/13624)
|
||||
- 💄 Rewrote the custom filter demo of Table. [Link](https://ant.design/components/table-cn/#components-table-demo-custom-filter-panel)
|
||||
- 🐞 Fixed padding of Button which children is `0`. [#13596](https://github.com/ant-design/ant-design/pull/13596) [@951565664](https://github.com/951565664)
|
||||
- 💄 Chore Card header and loading UI.
|
||||
- 💄 Optimized Spin wrapper styles and improve performance slightly. [2c7112b](https://github.com/ant-design/ant-design/commit/2c7112be7bf32c6e8362334b86b0799cc3a4a6c4)
|
||||
- 🐞 Fixed border color of validated Input.Group. [#13529](https://github.com/ant-design/ant-design/issues/13529) [@morenyang](https://github.com/morenyang)
|
||||
- 🐞 Fixed submenu animation of vertical-type Menu. [#13597](https://github.com/ant-design/ant-design/issues/13597)
|
||||
- 🐞 Fixed width of WeekPicker. [#13629](https://github.com/ant-design/ant-design/issues/13629)
|
||||
- 🐞 Fixed cursor style of disabled Radio.Button. [#13642](https://github.com/ant-design/ant-design/pull/13642) [@gianpaj](https://github.com/gianpaj)
|
||||
- Dropdown
|
||||
- 🐞 Fixed slight shift when menu is popped in Chrome. [#12115](https://github.com/ant-design/ant-design/issues/12115) [@gurungrahul2](https://github.com/gurungrahul2)
|
||||
- 🐞 Fixed unexpected scrollbar caused by dropdown placed at screen edge. [00564dd](https://github.com/ant-design/ant-design/commit/3aeca7c10ec6ee3441f024fe7fdb5ae9e00564dd)
|
||||
- 🐞 Fixed `offset` props when Badge `count` is specified as a ReactNode. [#13694](https://github.com/ant-design/ant-design/issues/13694)
|
||||
- 🐞 Remove nested Form.Item negative margin. [#13748](https://github.com/ant-design/ant-design/issues/13748)
|
||||
- 📝 Added a Select demo of [Hide Already Selected](https://ant.design/components/select/#components-select-demo-hide-selected). [#13552](https://github.com/ant-design/ant-design/pull/13552) [@SergeyVolynkin](https://github.com/SergeyVolynkin)
|
||||
- 🐞 Fixed padding of Comment actions. [#13713](https://github.com/ant-design/ant-design/issues/13713)
|
||||
- 🐞 Fixed broken arrow style when customize Popover's background color. [#13533](https://github.com/ant-design/ant-design/issues/13533) [@gurungrahul2](https://github.com/gurungrahul2)
|
||||
- 🐞 Corrected Drawer `style` prop to outside wrapper. [#11504](https://github.com/ant-design/ant-design/issues/11504)
|
||||
- 🐞 Fixed one problem of incorrect state when Affix first mounted. [#13737](https://github.com/ant-design/ant-design/pull/13737) [@xuxinhang](https://github.com/xuxinhang)
|
||||
- 🐞 Fixed Tabs cursor style of disabled tab. [#13709](https://github.com/ant-design/ant-design/issues/13709)
|
||||
- 🌟 Added some less variables of [Tabs](https://github.com/ant-design/ant-design/pull/13727), [Table](https://github.com/ant-design/ant-design/pull/13754), [Alert](https://github.com/ant-design/ant-design/pull/13768).
|
||||
- TypeScript
|
||||
- ⚡️ Enhanced Table `ColumnProps` types about `dataIndex`. [#13605](https://github.com/ant-design/ant-design/pull/13605) [@bondBo](https://github.com/bondBo)
|
||||
- ⚡️ Enhanced Table `TableRowSelection.onChange` arguments with generic types.[#13761](https://github.com/ant-design/ant-design/issues/13761) [@hahabazinga](https://github.com/hahabazinga)
|
||||
- 🐞 Fixed type of LocaleProvider's `children`. [#12974](https://github.com/ant-design/ant-design/issues/12974)
|
||||
- 🐞 Fixed type of RangePicker `onOk`'s arguments. [#13650](https://github.com/ant-design/ant-design/pull/13650) [@iugo](https://github.com/iugo)
|
||||
- 🐞 Fixed Comment `author` type from string to ReactNode。[#13670](https://github.com/ant-design/ant-design/pull/13670) [@reichjustin](https://github.com/reichjustin)
|
||||
- 🐞 Fixed type of Select `dropdownProps`'s arguments. [#13617](https://github.com/ant-design/ant-design/pull/13617) [@SylvanasGone](https://github.com/SylvanasGone)
|
||||
|
||||
## 3.11.2
|
||||
|
||||
`2018-12-10`
|
||||
|
||||
- 🐞 Fixed Table `Cannot read property 'children' of undefined` error when customize `column.title` as ReactNode. [#13542](https://github.com/ant-design/ant-design/issues/13542) [@geraldchen890806](https://github.com/geraldchen890806)
|
||||
- 🐞 Fixed another border problem of Button when customized less variable `@border-width-base`. [#13534](https://github.com/ant-design/ant-design/issues/13534) [@morenyang](https://github.com/morenyang)
|
||||
- 🐞 Fixed Upload don't support resolve `Blob` object when `beforeUpload` returns a Promise. [#13528](https://github.com/ant-design/ant-design/pull/13528/) [@huanz](https://github.com/huanz)
|
||||
- https://github.com/ant-design/ant-design/pull/13536
|
||||
- 🐞 Fixed two props of Dropdown TypeScript definitions. [#13536](https://github.com/ant-design/ant-design/pull/13536) [@wangxingkang](https://github.com/wangxingkang)
|
||||
|
||||
## 3.11.1
|
||||
|
||||
`2018-12-08`
|
||||
|
||||
- 🐞 Fixed the issue where the Avatar icon could not be centered vertically. [#13408](https://github.com/ant-design/ant-design/issues/13408)
|
||||
- 🐞 Fixed the border problem of Button when setting the less variable `@border-width-base` to `1`. [#13413](https://github.com/ant-design/ant-design/issues/13413) [@morenyang](https://github.com/morenyang)
|
||||
- 🐞 Fixed Commnet does not correctly display line breaks. [#13429](https://github.com/ant-design/ant-design/issues/13429)
|
||||
- 🐞 Fixed the border problem of Button when customized less variable `@border-width-base`. [#13413](https://github.com/ant-design/ant-design/issues/13413) [@morenyang](https://github.com/morenyang)
|
||||
- 🐞 Fixed Comment does not correctly display line breaks. [#13429](https://github.com/ant-design/ant-design/issues/13429)
|
||||
- 🐞 Fixed the issue that when the Alert is in `closable`, the icon will be covered by the text. [#13440](https://github.com/ant-design/ant-design/issues/13440)
|
||||
- Button
|
||||
- 🐞 Fixed the issue that when the `href` property is `undefined`, the Button will also be rendered as a anchor. [#13337](https://github.com/ant-design/ant-design/issues/13337)
|
||||
@@ -1101,12 +1163,15 @@ Learn more in the [Ant Design 3.0 announcement post](https://medium.com/ant-desi
|
||||
- New [Divider](https://ant.design/components/divider/) component.
|
||||
- 30 New [icons](https://ant.design/components/icon/).
|
||||
|
||||
### ⚠️ Read it before migration
|
||||
|
||||
- We suggest you upgrade to latest 3.x version directly.
|
||||
- Some APIs may be deprecated in other 3.x versions which don't described below, please pay attention to warning in browser console and upgrade them.
|
||||
- We strongly suggest upgrade react to 16 or newest for better support and performance, which could be conduct via [React 16 upgrading](https://reactjs.org/blog/2017/09/26/react-v16.0.html#upgrading).
|
||||
- Then you can migrate to antd@3 by following `Breaking Changes` section.
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
> We suggest you upgrade to latest 3.x version directly.
|
||||
|
||||
> Some APIs may be deprecated in other 3.x versions which don't described below, please pay attention to warning in browser console and upgrade them.
|
||||
|
||||
We provide a [migration tool](https://github.com/ant-design/antd-migration-helper) to help you find deprecated usages in your codebase.
|
||||
|
||||
- Card's `noHovering` has been renamed to `hoverable`, and its default value now is `true`.
|
||||
|
||||
@@ -15,12 +15,74 @@ timeline: true
|
||||
|
||||
---
|
||||
|
||||
## 3.11.5
|
||||
|
||||
`2018-12-24`
|
||||
|
||||
- 🐞 修复 `lib` 下样式文件路径问题。[#13791](https://github.com/ant-design/ant-design/issues/13803)
|
||||
|
||||
## 3.11.4
|
||||
|
||||
`2018-12-23`
|
||||
|
||||
- 🐞 修复 `Could not find dependency: '@babel/runtime'` 的问题。[#13791](https://github.com/ant-design/ant-design/issues/13791)
|
||||
- ⚡️ 重构 Tag 组件,简化代码并提升性能。[b828741](https://github.com/ant-design/ant-design/commit/b828741dc06eaa69ff3f8c76024fd5527ed6d74f)
|
||||
|
||||
## 3.11.3 🎅🏻
|
||||
|
||||
`2018-12-22`
|
||||
|
||||
- ⚡️ 升级内部依赖到 babel@7 和 webpack@4,并使用 prettier 格式化了所有代码。
|
||||
- Table
|
||||
- 🐞 **修复 Table 列筛选菜单按钮不可点击的问题**。[#13563](https://github.com/ant-design/ant-design/issues/13563)
|
||||
- 🐞 修复 Table 列设置排序后影响列头自定义浮出组件的展现问题。[#13467](https://github.com/ant-design/ant-design/issues/13467)
|
||||
- 🐞 修复 Table 选择时在 IE9/10 下崩溃的问题。[#13540](https://github.com/ant-design/ant-design/issues/13540)
|
||||
- 🐞 修复 Table 指定 `childrenColumnName` 时,全选框无法自动勾选的问题。[#13710](https://github.com/ant-design/ant-design/issues/13710)
|
||||
- 💄 移除 Table 下英文单词断行的样式。[#13624](https://github.com/ant-design/ant-design/issues/13624)
|
||||
- 💄 优化了 Table 自定义列搜索例子的实现和 UI。[演示](https://ant.design/components/table-cn/#components-table-demo-custom-filter-panel)
|
||||
- 🐞 修复 Button 内容为 `0` 时的样式。[#13596](https://github.com/ant-design/ant-design/pull/13596) [@951565664](https://github.com/951565664)
|
||||
- 💄 微调 Card 头部和加载中的样式细节。
|
||||
- 💄 优化 Spin 样式并略微提升了切换状态的性能。[2c7112b](https://github.com/ant-design/ant-design/commit/2c7112be7bf32c6e8362334b86b0799cc3a4a6c4)
|
||||
- 🐞 修复一个 Input.Group 使用 compact 时校验状态边框样式的问题。[#13529](https://github.com/ant-design/ant-design/issues/13529) [@morenyang](https://github.com/morenyang)
|
||||
- 🐞 修复 Menu 在 vertical 模式下的展开收起动画。[#13597](https://github.com/ant-design/ant-design/issues/13597)
|
||||
- 🐞 修复 WeekPicker 的宽度样式异常。[#13629](https://github.com/ant-design/ant-design/issues/13629)
|
||||
- 🐞 修复 Radio.Button 失效状态下的鼠标手势。[#13642](https://github.com/ant-design/ant-design/pull/13642) [@gianpaj](https://github.com/gianpaj)
|
||||
- Dropdown
|
||||
- 🐞 修复 Chrome 下菜单弹出时有轻微移动的问题。[#12115](https://github.com/ant-design/ant-design/issues/12115) [@gurungrahul2](https://github.com/gurungrahul2)
|
||||
- 🐞 修复一个屏幕边缘的 Dropdown 菜单引起的浏览器滚动条异常出现的问题。[00564dd](https://github.com/ant-design/ant-design/commit/3aeca7c10ec6ee3441f024fe7fdb5ae9e00564dd)
|
||||
- 🐞 修复 Badge 的 `count` 是自定义 ReactNode 时 `offset` 属性失效的问题。[#13694](https://github.com/ant-design/ant-design/issues/13694)
|
||||
- 🐞 去掉 Form.Item 内嵌负边距,改用其他的方式实现单行多个表单项。[#13748](https://github.com/ant-design/ant-design/issues/13748)
|
||||
- 📝 补充了一个 Select 选择后隐藏选项的[例子](https://ant.design/components/select-cn/#components-select-demo-hide-selected)。[#13552](https://github.com/ant-design/ant-design/pull/13552) [@SergeyVolynkin](https://github.com/SergeyVolynkin)
|
||||
- 🐞 修复 Comment 的操作链接边距样式。[#13713](https://github.com/ant-design/ant-design/issues/13713)
|
||||
- 🐞 修复自定义 Popover 背景色时箭头样式突兀的问题。[#13533](https://github.com/ant-design/ant-design/issues/13533) [@gurungrahul2](https://github.com/gurungrahul2)
|
||||
- 🐞 修正 Drawer 的 `style` 属性到最外层容器上。[#11504](https://github.com/ant-design/ant-design/issues/11504)
|
||||
- 🐞 修复一个 Affix 初始化时固定状态不正确的问题。[#13737](https://github.com/ant-design/ant-design/pull/13737) [@xuxinhang](https://github.com/xuxinhang)
|
||||
- 🐞 修复 Tabs 失效页签的鼠标手型。[#13709](https://github.com/ant-design/ant-design/issues/13709)
|
||||
- 🌟 补充 [Tabs](https://github.com/ant-design/ant-design/pull/13727)、[Table](https://github.com/ant-design/ant-design/pull/13754)、[Alert](https://github.com/ant-design/ant-design/pull/13768) 组件的一些样式变量。
|
||||
- TypeScript
|
||||
- ⚡️ 完善 Table 的 `ColumnProps` 定义,增强对 `dataIndex` 的校验。[#13605](https://github.com/ant-design/ant-design/pull/13605) [@bondBo](https://github.com/bondBo)
|
||||
- ⚡️ 完善 Table 的 `TableRowSelection.onChange` 参数泛型定义。[#13761](https://github.com/ant-design/ant-design/issues/13761) [@hahabazinga](https://github.com/hahabazinga)
|
||||
- 🐞 修复 LocaleProvider 的 `children` 类型。 [#12974](https://github.com/ant-design/ant-design/issues/12974)
|
||||
- 🐞 修复 RangePicker 的 `onOk` 的参数类型。[#13650](https://github.com/ant-design/ant-design/pull/13650) [@iugo](https://github.com/iugo)
|
||||
- 🐞 修正 Comment `author` 属性的类型为 ReactNode。[#13670](https://github.com/ant-design/ant-design/pull/13670) [@reichjustin](https://github.com/reichjustin)
|
||||
- 🐞 修复 Select `dropdownProps` 的参数定义。[#13617](https://github.com/ant-design/ant-design/pull/13617) [@SylvanasGone](https://github.com/SylvanasGone)
|
||||
|
||||
## 3.11.2
|
||||
|
||||
`2018-12-10`
|
||||
|
||||
- 🐞 修复 Table 使用自定义列头时报 `Cannot read property 'children' of undefined` 的问题。[#13542](https://github.com/ant-design/ant-design/issues/13542) [@geraldchen890806](https://github.com/geraldchen890806)
|
||||
- 🐞 修复另一个 Input 在自定义了 less 变量 `@border-width-base` 时的边框问题。[#13534](https://github.com/ant-design/ant-design/pull/13534) [@morenyang](https://github.com/morenyang)
|
||||
- 🐞 修复 Upload 的 `beforeUpload` 方法返回 Promise 时不支持 resolve `Blob` 对象的问题。[#13528](https://github.com/ant-design/ant-design/pull/13528/) [@huanz](https://github.com/huanz)
|
||||
- https://github.com/ant-design/ant-design/pull/13536
|
||||
- 🐞 修复 Dropdown 两个属性的 TypeScript 定义。[#13536](https://github.com/ant-design/ant-design/pull/13536) [@wangxingkang](https://github.com/wangxingkang)
|
||||
|
||||
## 3.11.1
|
||||
|
||||
`2018-12-08`
|
||||
|
||||
- 🐞 修复 Avatar 图标不能垂直居中的问题。[#13408](https://github.com/ant-design/ant-design/issues/13408)
|
||||
- 🐞 修复 Input 在设置 less 变量 `@border-width-base` 为 `1` 时的边框问题。[#13413](https://github.com/ant-design/ant-design/issues/13413) [@morenyang](https://github.com/morenyang)
|
||||
- 🐞 修复 Input 在自定义了 less 变量 `@border-width-base` 时的边框问题。[#13413](https://github.com/ant-design/ant-design/issues/13413) [@morenyang](https://github.com/morenyang)
|
||||
- 🐞 修复 Commnet 组件不能正确显示换行的问题。[#13429](https://github.com/ant-design/ant-design/issues/13429)
|
||||
- 🐞 修复 Alert 在 `closable` 时,关闭图标会被文字遮挡的问题。[#13440](https://github.com/ant-design/ant-design/issues/13440)
|
||||
- Button
|
||||
@@ -1104,12 +1166,15 @@ timeline: true
|
||||
- 新的 [Divider](https://ant.design/components/divider-cn/) 组件。
|
||||
- 新增 30 个[图标](https://ant.design/components/icon-cn/)。
|
||||
|
||||
### ⚠️ 升级必读
|
||||
|
||||
- 如果你从 2.x 升级到 3.x,建议直接升级到 3.x 的最新版本。
|
||||
- 3.x 后续的版本可能已经废弃了一些下面没有提到的改动,请参考控制台的警告提示相应升级。
|
||||
- 建议同时升级 React 到 16 或更新版本,以获得更好的性能和更完善的支持,升级方式见 [官方发布文档](https://reactjs.org/blog/2017/09/26/react-v16.0.html#upgrading)。
|
||||
- 最后请参照下面的不兼容改动进行升级。
|
||||
|
||||
### 不兼容改动
|
||||
|
||||
> 如果你从 2.x 升级到 3.x,建议直接升级到 3.x 的最新版本。
|
||||
|
||||
> 3.x 后续的版本可能已经废弃了一些下面没有提到的改动,请参考控制台的警告提示相应升级。
|
||||
|
||||
此版本有部分不兼容的改动,升级时确保修改相应的使用代码。另外由于人肉查找代码中的废弃用法过于低效,所以我们提供了 [antd-migration-helper](https://github.com/ant-design/antd-migration-helper) 用于扫描代码中的废弃用法。
|
||||
|
||||
- Card 的 `noHovering` 属性重命名为 `hoverable`,且默认值改为 `true`。
|
||||
|
||||
@@ -12,14 +12,16 @@
|
||||
|
||||
[](https://circleci.com/gh/ant-design/ant-design)
|
||||
[](https://codecov.io/gh/ant-design/ant-design/branch/master)
|
||||
[](https://david-dm.org/ant-design/ant-design)
|
||||
[](https://david-dm.org/ant-design/ant-design?type=dev)
|
||||
|
||||
[](https://www.npmjs.org/package/antd)
|
||||
[](http://npmjs.com/antd)
|
||||
[](http://isitmaintained.com/project/ant-design/ant-design "Percentage of issues still open")
|
||||
[](https://gitter.im/ant-design/ant-design-english?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)(🇺🇸)
|
||||
[](https://gitter.im/ant-design/ant-design?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)(🇨🇳)
|
||||
[](https://github.com/ant-design/ant-design/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22)
|
||||
|
||||
[](https://david-dm.org/ant-design/ant-design)
|
||||
[](https://david-dm.org/ant-design/ant-design?type=dev)
|
||||
[](https://lgtm.com/projects/g/ant-design/ant-design/alerts/)
|
||||
[](https://lgtm.com/projects/g/ant-design/ant-design/context:javascript)
|
||||
[](https://gitter.im/ant-design/ant-design-english?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||
[](https://gitter.im/ant-design/ant-design?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
</div>
|
||||
|
||||
@@ -109,6 +111,8 @@ $ npm start
|
||||
|
||||
> 强烈推荐阅读 [《提问的智慧》](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way)、[《如何向开源社区提问题》](https://github.com/seajs/seajs/issues/545) 和 [《如何有效地报告 Bug》](http://www.chiark.greenend.org.uk/%7Esgtatham/bugs-cn.html)、[《如何向开源项目提交无法解答的问题》](https://zhuanlan.zhihu.com/p/25795393),更好的问题更容易获得帮助。
|
||||
|
||||
[](https://issuehunt.io/repos/34526884)
|
||||
|
||||
## 社区互助
|
||||
|
||||
如果您在使用的过程中碰到问题,可以通过下面几个途径寻求帮助,同时我们也鼓励资深用户通过下面的途径给新人提供帮助。
|
||||
|
||||
18
README.md
18
README.md
@@ -8,18 +8,20 @@
|
||||
|
||||
<div align="center">
|
||||
|
||||
An enterprise-class UI design language and React-based implementation.
|
||||
An enterprise-class UI design language and React implementation.
|
||||
|
||||
[](https://circleci.com/gh/ant-design/ant-design)
|
||||
[](https://codecov.io/gh/ant-design/ant-design/branch/master)
|
||||
[](https://david-dm.org/ant-design/ant-design)
|
||||
[](https://david-dm.org/ant-design/ant-design?type=dev)
|
||||
|
||||
[](https://www.npmjs.org/package/antd)
|
||||
[](http://npmjs.com/antd)
|
||||
[](http://isitmaintained.com/project/ant-design/ant-design "Percentage of issues still open")
|
||||
[](https://gitter.im/ant-design/ant-design-english?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)(🇺🇸)
|
||||
[](https://gitter.im/ant-design/ant-design?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)(🇨🇳)
|
||||
[](https://github.com/ant-design/ant-design/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22)
|
||||
|
||||
[](https://david-dm.org/ant-design/ant-design)
|
||||
[](https://david-dm.org/ant-design/ant-design?type=dev)
|
||||
[](https://lgtm.com/projects/g/ant-design/ant-design/alerts/)
|
||||
[](https://lgtm.com/projects/g/ant-design/ant-design/context:javascript)
|
||||
[](https://gitter.im/ant-design/ant-design-english?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||
[](https://gitter.im/ant-design/ant-design?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
</div>
|
||||
|
||||
@@ -107,3 +109,5 @@ Open your browser and visit http://127.0.0.1:8001 , see more at [Development](ht
|
||||
Read our [contributing guide](https://ant.design/docs/react/contributing) and let's build a better antd together.
|
||||
|
||||
We welcome all contributions. Please read our [CONTRIBUTING.md](https://github.com/ant-design/ant-design/blob/master/.github/CONTRIBUTING.md) first. You can submit any ideas as [pull requests](https://github.com/ant-design/ant-design/pulls) or as [GitHub issues](https://github.com/ant-design/ant-design/issues). If you'd like to improve code, check out the [Development Instructions](https://github.com/ant-design/ant-design/wiki/Development) and have a good time! :)
|
||||
|
||||
[](https://issuehunt.io/repos/34526884)
|
||||
|
||||
@@ -218,6 +218,8 @@ export default class Affix extends React.Component<AffixProps, AffixState> {
|
||||
// Wait for parent component ref has its value
|
||||
this.timeout = setTimeout(() => {
|
||||
this.setTargetEventListeners(target);
|
||||
// Mock Event object.
|
||||
this.updatePosition({} as Event);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
@alert-message-color: @heading-color;
|
||||
@alert-text-color: @text-color;
|
||||
@alert-close-color: @text-color-secondary;
|
||||
@alert-close-hover-color: #404040;
|
||||
|
||||
.@{alert-prefix-cls} {
|
||||
.reset-component;
|
||||
@@ -78,7 +79,7 @@
|
||||
color: @alert-close-color;
|
||||
transition: color 0.3s;
|
||||
&:hover {
|
||||
color: #404040;
|
||||
color: @alert-close-hover-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,22 +3,14 @@ import { mount } from 'enzyme';
|
||||
import BackTop from '..';
|
||||
|
||||
describe('BackTop', () => {
|
||||
beforeAll(() => {
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('should scroll to top after click it', () => {
|
||||
it('should scroll to top after click it', async () => {
|
||||
const wrapper = mount(<BackTop visibilityHeight={-1} />);
|
||||
document.documentElement.scrollTop = 400;
|
||||
// trigger scroll manually
|
||||
wrapper.instance().handleScroll();
|
||||
jest.runAllTimers();
|
||||
await new Promise(resolve => setTimeout(resolve, 0));
|
||||
wrapper.find('.ant-back-top').simulate('click');
|
||||
jest.runAllTimers();
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
expect(Math.abs(Math.round(document.documentElement.scrollTop))).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -164,7 +164,10 @@ export default class ScrollNumber extends Component<ScrollNumberProps, ScrollNum
|
||||
}
|
||||
if (displayComponent) {
|
||||
return React.cloneElement(displayComponent, {
|
||||
className: `${prefixCls}-custom-component`,
|
||||
className: classNames(
|
||||
`${prefixCls}-custom-component`,
|
||||
displayComponent.props && displayComponent.props.className,
|
||||
),
|
||||
});
|
||||
}
|
||||
return createElement(component as any, newProps, this.renderNumberElement());
|
||||
|
||||
@@ -2185,3 +2185,18 @@ exports[`Badge should render when count is changed 5`] = `
|
||||
</span>
|
||||
</Badge>
|
||||
`;
|
||||
|
||||
exports[`Badge should support offset when count is a ReactNode 1`] = `
|
||||
<span
|
||||
class="ant-badge"
|
||||
>
|
||||
<a
|
||||
class="head-example"
|
||||
href="#"
|
||||
/>
|
||||
<span
|
||||
class="ant-scroll-number-custom-component custom"
|
||||
style="right:-10px;margin-top:20px;color:#f5222d"
|
||||
/>
|
||||
</span>
|
||||
`;
|
||||
|
||||
@@ -72,4 +72,14 @@ describe('Badge', () => {
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/13694
|
||||
it('should support offset when count is a ReactNode', () => {
|
||||
const wrapper = render(
|
||||
<Badge count={<span className="custom" style={{ color: '#f5222d' }} />} offset={[10, 20]}>
|
||||
<a href="#" className="head-example" />
|
||||
</Badge>,
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -112,7 +112,16 @@ export default class Badge extends React.Component<BadgeProps, any> {
|
||||
|
||||
renderDispayComponent() {
|
||||
const { count } = this.props;
|
||||
return count && typeof count === 'object' ? (count as React.ReactElement<any>) : undefined;
|
||||
const customNode = count as React.ReactElement<any>;
|
||||
if (!customNode || typeof customNode !== 'object') {
|
||||
return undefined;
|
||||
}
|
||||
return React.cloneElement(customNode, {
|
||||
style: {
|
||||
...this.getStyleWithOffset(),
|
||||
...(customNode.props && customNode.props.style),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
renderBadgeNumber() {
|
||||
@@ -130,8 +139,6 @@ export default class Badge extends React.Component<BadgeProps, any> {
|
||||
[`${prefixCls}-status-${status}`]: !!status,
|
||||
});
|
||||
|
||||
const styleWithOffset = this.getStyleWithOffset();
|
||||
|
||||
return hidden ? null : (
|
||||
<ScrollNumber
|
||||
prefixCls={scrollNumberPrefixCls}
|
||||
@@ -140,7 +147,7 @@ export default class Badge extends React.Component<BadgeProps, any> {
|
||||
count={displayCount}
|
||||
displayComponent={this.renderDispayComponent()} // <Badge status="success" count={<Icon type="xxx" />}></Badge>
|
||||
title={this.getScollNumberTitle()}
|
||||
style={styleWithOffset}
|
||||
style={this.getStyleWithOffset()}
|
||||
key="scrollNumber"
|
||||
/>
|
||||
);
|
||||
@@ -172,12 +179,10 @@ export default class Badge extends React.Component<BadgeProps, any> {
|
||||
[`${prefixCls}-status-${status}`]: !!status,
|
||||
});
|
||||
|
||||
const styleWithOffset = this.getStyleWithOffset();
|
||||
|
||||
// <Badge status="success" />
|
||||
if (!children && status) {
|
||||
return (
|
||||
<span {...restProps} className={this.getBadgeClassName()} style={styleWithOffset}>
|
||||
<span {...restProps} className={this.getBadgeClassName()} style={this.getStyleWithOffset()}>
|
||||
<span className={statusCls} />
|
||||
<span className={`${prefixCls}-status-text`}>{text}</span>
|
||||
</span>
|
||||
|
||||
@@ -207,7 +207,7 @@ export default class Button extends React.Component<ButtonProps, any> {
|
||||
[`${prefixCls}-${type}`]: type,
|
||||
[`${prefixCls}-${shape}`]: shape,
|
||||
[`${prefixCls}-${sizeCls}`]: sizeCls,
|
||||
[`${prefixCls}-icon-only`]: !children && icon,
|
||||
[`${prefixCls}-icon-only`]: !children && children !== 0 && icon,
|
||||
[`${prefixCls}-loading`]: loading,
|
||||
[`${prefixCls}-background-ghost`]: ghost,
|
||||
[`${prefixCls}-two-chinese-chars`]: hasTwoCNChar,
|
||||
|
||||
@@ -66,11 +66,10 @@
|
||||
|
||||
&-extra {
|
||||
float: right;
|
||||
padding: @card-head-padding + 1.5px 0;
|
||||
padding: @card-head-padding 0;
|
||||
font-size: @font-size-base;
|
||||
color: @text-color;
|
||||
font-weight: normal;
|
||||
text-align: right;
|
||||
// https://stackoverflow.com/a/22429853/3040605
|
||||
margin-left: auto;
|
||||
}
|
||||
@@ -232,6 +231,21 @@
|
||||
}
|
||||
}
|
||||
|
||||
&-loading {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
|
||||
&:after {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: @card-padding-base;
|
||||
background: @component-background;
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
|
||||
&-loading &-body {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import arrayTreeFilter from 'array-tree-filter';
|
||||
import classNames from 'classnames';
|
||||
import omit from 'omit.js';
|
||||
import KeyCode from 'rc-util/lib/KeyCode';
|
||||
import { polyfill } from 'react-lifecycles-compat';
|
||||
import Input from '../input';
|
||||
import Icon from '../icon';
|
||||
import { ConfigConsumer, ConfigProviderProps } from '../config-provider';
|
||||
@@ -103,6 +104,7 @@ export interface CascaderState {
|
||||
value: string[];
|
||||
popupVisible: boolean | undefined;
|
||||
flattenOptions: CascaderOptionType[][] | undefined;
|
||||
prevProps: CascaderProps;
|
||||
}
|
||||
|
||||
interface CascaderLocale {
|
||||
@@ -180,9 +182,29 @@ function getFilledFieldNames(props: CascaderProps) {
|
||||
return names;
|
||||
}
|
||||
|
||||
function flattenTree(
|
||||
options: CascaderOptionType[],
|
||||
props: CascaderProps,
|
||||
ancestor: CascaderOptionType[] = [],
|
||||
) {
|
||||
const names: FilledFieldNamesType = getFilledFieldNames(props);
|
||||
let flattenOptions = [] as CascaderOptionType[][];
|
||||
const childrenName = names.children;
|
||||
options.forEach(option => {
|
||||
const path = ancestor.concat(option);
|
||||
if (props.changeOnSelect || !option[childrenName] || !option[childrenName].length) {
|
||||
flattenOptions.push(path);
|
||||
}
|
||||
if (option[childrenName]) {
|
||||
flattenOptions = flattenOptions.concat(flattenTree(option[childrenName], props, path));
|
||||
}
|
||||
});
|
||||
return flattenOptions;
|
||||
}
|
||||
|
||||
const defaultDisplayRender = (label: string[]) => label.join(' / ');
|
||||
|
||||
export default class Cascader extends React.Component<CascaderProps, CascaderState> {
|
||||
class Cascader extends React.Component<CascaderProps, CascaderState> {
|
||||
static defaultProps = {
|
||||
prefixCls: 'ant-cascader',
|
||||
inputPrefixCls: 'ant-input',
|
||||
@@ -194,6 +216,24 @@ export default class Cascader extends React.Component<CascaderProps, CascaderSta
|
||||
notFoundContent: 'Not Found',
|
||||
};
|
||||
|
||||
static getDerivedStateFromProps(nextProps: CascaderProps, { prevProps }: CascaderState) {
|
||||
const newState: Partial<CascaderState> = {
|
||||
prevProps: nextProps,
|
||||
};
|
||||
|
||||
if ('value' in nextProps) {
|
||||
newState.value = nextProps.value || [];
|
||||
}
|
||||
if ('popupVisible' in nextProps) {
|
||||
newState.popupVisible = nextProps.popupVisible;
|
||||
}
|
||||
if (nextProps.showSearch && prevProps.options !== nextProps.options) {
|
||||
newState.flattenOptions = flattenTree(nextProps.options, nextProps);
|
||||
}
|
||||
|
||||
return newState;
|
||||
}
|
||||
|
||||
cachedOptions: CascaderOptionType[];
|
||||
|
||||
private input: Input;
|
||||
@@ -205,24 +245,11 @@ export default class Cascader extends React.Component<CascaderProps, CascaderSta
|
||||
inputValue: '',
|
||||
inputFocused: false,
|
||||
popupVisible: props.popupVisible,
|
||||
flattenOptions: props.showSearch ? this.flattenTree(props.options, props) : undefined,
|
||||
flattenOptions: props.showSearch ? flattenTree(props.options, props) : undefined,
|
||||
prevProps: props,
|
||||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps: CascaderProps) {
|
||||
if ('value' in nextProps) {
|
||||
this.setState({ value: nextProps.value || [] });
|
||||
}
|
||||
if ('popupVisible' in nextProps) {
|
||||
this.setState({ popupVisible: nextProps.popupVisible });
|
||||
}
|
||||
if (nextProps.showSearch && this.props.options !== nextProps.options) {
|
||||
this.setState({
|
||||
flattenOptions: this.flattenTree(nextProps.options, nextProps),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleChange = (value: any, selectedOptions: CascaderOptionType[]) => {
|
||||
this.setState({ inputValue: '' });
|
||||
if (selectedOptions[0].__IS_FILTERED_OPTION) {
|
||||
@@ -236,11 +263,11 @@ export default class Cascader extends React.Component<CascaderProps, CascaderSta
|
||||
|
||||
handlePopupVisibleChange = (popupVisible: boolean) => {
|
||||
if (!('popupVisible' in this.props)) {
|
||||
this.setState({
|
||||
this.setState(state => ({
|
||||
popupVisible,
|
||||
inputFocused: popupVisible,
|
||||
inputValue: popupVisible ? this.state.inputValue : '',
|
||||
});
|
||||
inputValue: popupVisible ? state.inputValue : '',
|
||||
}));
|
||||
}
|
||||
|
||||
const onPopupVisibleChange = this.props.onPopupVisibleChange;
|
||||
@@ -312,26 +339,6 @@ export default class Cascader extends React.Component<CascaderProps, CascaderSta
|
||||
}
|
||||
};
|
||||
|
||||
flattenTree(
|
||||
options: CascaderOptionType[],
|
||||
props: CascaderProps,
|
||||
ancestor: CascaderOptionType[] = [],
|
||||
) {
|
||||
const names: FilledFieldNamesType = getFilledFieldNames(props);
|
||||
let flattenOptions = [] as CascaderOptionType[][];
|
||||
const childrenName = names.children;
|
||||
options.forEach(option => {
|
||||
const path = ancestor.concat(option);
|
||||
if (props.changeOnSelect || !option[childrenName] || !option[childrenName].length) {
|
||||
flattenOptions.push(path);
|
||||
}
|
||||
if (option[childrenName]) {
|
||||
flattenOptions = flattenOptions.concat(this.flattenTree(option[childrenName], props, path));
|
||||
}
|
||||
});
|
||||
return flattenOptions;
|
||||
}
|
||||
|
||||
generateFilteredOptions(prefixCls: string | undefined) {
|
||||
const { showSearch, notFoundContent } = this.props;
|
||||
const names: FilledFieldNamesType = getFilledFieldNames(this.props);
|
||||
@@ -564,3 +571,7 @@ export default class Cascader extends React.Component<CascaderProps, CascaderSta
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
polyfill(Cascader);
|
||||
|
||||
export default Cascader;
|
||||
|
||||
@@ -5,7 +5,7 @@ export interface CommentProps {
|
||||
/** List of action items rendered below the comment content */
|
||||
actions?: Array<React.ReactNode>;
|
||||
/** The element to display as the comment author. */
|
||||
author?: string;
|
||||
author?: React.ReactNode;
|
||||
/** The element to display as the comment avatar - generally an antd Avatar */
|
||||
avatar?: React.ReactNode;
|
||||
/** className of comment */
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
|
||||
&-actions {
|
||||
margin-top: 12px;
|
||||
|
||||
padding-left: 0;
|
||||
> li {
|
||||
display: inline-block;
|
||||
color: @comment-action-color;
|
||||
|
||||
@@ -173,24 +173,22 @@ class WeekPicker extends React.Component<any, WeekPickerState> {
|
||||
<span className={`${prefixCls}-picker-icon`}>{suffixIcon}</span>
|
||||
))) || <Icon type="calendar" className={`${prefixCls}-picker-icon`} />;
|
||||
|
||||
const input = ({ value }: { value: moment.Moment | undefined }) => {
|
||||
return (
|
||||
<span style={{ display: 'inline-block' }}>
|
||||
<input
|
||||
ref={this.saveInput}
|
||||
disabled={disabled}
|
||||
readOnly
|
||||
value={(value && value.format(format)) || ''}
|
||||
placeholder={placeholder}
|
||||
className={pickerInputClass}
|
||||
onFocus={onFocus}
|
||||
onBlur={onBlur}
|
||||
/>
|
||||
{clearIcon}
|
||||
{inputIcon}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
const input = ({ value }: { value: moment.Moment | undefined }) => (
|
||||
<span style={{ display: 'inline-block', width: '100%' }}>
|
||||
<input
|
||||
ref={this.saveInput}
|
||||
disabled={disabled}
|
||||
readOnly
|
||||
value={(value && value.format(format)) || ''}
|
||||
placeholder={placeholder}
|
||||
className={pickerInputClass}
|
||||
onFocus={onFocus}
|
||||
onBlur={onBlur}
|
||||
/>
|
||||
{clearIcon}
|
||||
{inputIcon}
|
||||
</span>
|
||||
);
|
||||
return (
|
||||
<span className={classNames(className, pickerClass)} style={style} id={id}>
|
||||
<RcDatePicker
|
||||
|
||||
@@ -2995,7 +2995,6 @@ exports[`RangePicker switch to corresponding month panel when click presetted ra
|
||||
>
|
||||
<div
|
||||
class="ant-tag ant-tag-blue"
|
||||
data-show="true"
|
||||
>
|
||||
My Birthday
|
||||
</div>
|
||||
|
||||
@@ -6,7 +6,7 @@ exports[`WeekPicker should support style prop 1`] = `
|
||||
style="width: 400px;"
|
||||
>
|
||||
<span
|
||||
style="display: inline-block;"
|
||||
style="display: inline-block; width: 100%;"
|
||||
>
|
||||
<input
|
||||
class="ant-calendar-picker-input ant-input"
|
||||
|
||||
@@ -112,7 +112,7 @@ exports[`renders ./components/date-picker/demo/basic.md correctly 1`] = `
|
||||
class="ant-calendar-picker"
|
||||
>
|
||||
<span
|
||||
style="display:inline-block"
|
||||
style="display:inline-block;width:100%"
|
||||
>
|
||||
<input
|
||||
class="ant-calendar-picker-input ant-input"
|
||||
@@ -1146,7 +1146,7 @@ exports[`renders ./components/date-picker/demo/size.md correctly 1`] = `
|
||||
class="ant-calendar-picker ant-calendar-picker-default"
|
||||
>
|
||||
<span
|
||||
style="display:inline-block"
|
||||
style="display:inline-block;width:100%"
|
||||
>
|
||||
<input
|
||||
class="ant-calendar-picker-input ant-input"
|
||||
@@ -1353,7 +1353,7 @@ exports[`renders ./components/date-picker/demo/suffix.md correctly 1`] = `
|
||||
class="ant-calendar-picker"
|
||||
>
|
||||
<span
|
||||
style="display:inline-block"
|
||||
style="display:inline-block;width:100%"
|
||||
>
|
||||
<input
|
||||
class="ant-calendar-picker-input ant-input"
|
||||
@@ -1455,7 +1455,7 @@ exports[`renders ./components/date-picker/demo/suffix.md correctly 1`] = `
|
||||
class="ant-calendar-picker"
|
||||
>
|
||||
<span
|
||||
style="display:inline-block"
|
||||
style="display:inline-block;width:100%"
|
||||
>
|
||||
<input
|
||||
class="ant-calendar-picker-input ant-input"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import moment from 'moment';
|
||||
import DatePicker from '..';
|
||||
|
||||
const { RangePicker } = DatePicker;
|
||||
@@ -38,6 +39,7 @@ describe('DatePicker with showTime', () => {
|
||||
onChange={onChangeFn}
|
||||
onOk={onOkFn}
|
||||
onOpenChange={onOpenChangeFn}
|
||||
defaultValue={moment()}
|
||||
/>,
|
||||
);
|
||||
|
||||
|
||||
@@ -117,16 +117,16 @@ The following APIs are shared by DatePicker, MonthPicker, RangePicker, WeekPicke
|
||||
| -------- | ----------- | ---- | ------- |
|
||||
| defaultValue | to set default date | \[[moment](http://momentjs.com/), [moment](http://momentjs.com/)] | - |
|
||||
| defaultPickerValue | to set default picker date | \[[moment](http://momentjs.com/), [moment](http://momentjs.com/)\] | - |
|
||||
| disabledTime | to specify the time that cannot be selected | function(dates: [moment, moment], partial: `'start'|'end'`) | - |
|
||||
| disabledTime | to specify the time that cannot be selected | function(dates: \[moment, moment], partial: `'start'|'end'`) | - |
|
||||
| format | to set the date format | string | "YYYY-MM-DD HH:mm:ss" |
|
||||
| ranges | preseted ranges for quick selection | { \[range: string]: [moment](http://momentjs.com/)\[] } \| { \[range: string]: () => [moment](http://momentjs.com/)\[] } | - |
|
||||
| renderExtraFooter | render extra footer in panel | () => React.ReactNode | - |
|
||||
| showTime | to provide an additional time selection | object\|boolean | [TimePicker Options](/components/time-picker/#API) |
|
||||
| showTime.defaultValue | to set default time of selected date, [demo](#components-date-picker-demo-disabled-date) | [moment](http://momentjs.com/)\[] | [moment(), moment()] |
|
||||
| showTime.defaultValue | to set default time of selected date, [demo](#components-date-picker-demo-disabled-date) | [moment](http://momentjs.com/)\[] | \[moment(), moment()] |
|
||||
| value | to set date | \[[moment](http://momentjs.com/), [moment](http://momentjs.com/)] | - |
|
||||
| onCalendarChange | a callback function, can be executed when the start time or the end time of the range is changing | function(dates: [moment, moment], dateStrings: [string, string]) | - |
|
||||
| onChange | a callback function, can be executed when the selected time is changing | function(dates: [moment, moment], dateStrings: [string, string]) | - |
|
||||
| onOk | callback when click ok button | function() | - |
|
||||
| onCalendarChange | a callback function, can be executed when the start time or the end time of the range is changing | function(dates: \[moment, moment], dateStrings: \[string, string]) | - |
|
||||
| onChange | a callback function, can be executed when the selected time is changing | function(dates: \[moment, moment], dateStrings: \[string, string]) | - |
|
||||
| onOk | callback when click ok button | function(dates: [moment](http://momentjs.com/)\[]) | - |
|
||||
|
||||
<style>
|
||||
.code-box-demo .ant-calendar-picker {
|
||||
|
||||
@@ -119,16 +119,16 @@ moment.locale('zh-cn');
|
||||
| --- | --- | --- | --- |
|
||||
| defaultValue | 默认日期 | [moment](http://momentjs.com/)\[] | 无 |
|
||||
| defaultPickerValue | 默认面板日期 | [moment](http://momentjs.com/)\[] | 无 |
|
||||
| disabledTime | 不可选择的时间 | function(dates: [moment, moment], partial: `'start'|'end'`) | 无 |
|
||||
| disabledTime | 不可选择的时间 | function(dates: \[moment, moment\], partial: `'start'|'end'`) | 无 |
|
||||
| format | 展示的日期格式 | string | "YYYY-MM-DD HH:mm:ss" |
|
||||
| ranges | 预设时间范围快捷选择 | { \[range: string]: [moment](http://momentjs.com/)\[] } \| { \[range: string]: () => [moment](http://momentjs.com/)\[] } | 无 |
|
||||
| renderExtraFooter | 在面板中添加额外的页脚 | () => React.ReactNode | - |
|
||||
| showTime | 增加时间选择功能 | Object\|boolean | [TimePicker Options](/components/time-picker/#API) |
|
||||
| showTime.defaultValue | 设置用户选择日期时默认的时分秒,[例子](#components-date-picker-demo-disabled-date) | [moment](http://momentjs.com/)\[] | [moment(), moment()] |
|
||||
| showTime.defaultValue | 设置用户选择日期时默认的时分秒,[例子](#components-date-picker-demo-disabled-date) | [moment](http://momentjs.com/)\[] | \[moment(), moment()] |
|
||||
| value | 日期 | [moment](http://momentjs.com/)\[] | 无 |
|
||||
| onCalendarChange | 待选日期发生变化的回调 | function(dates: [moment, moment], dateStrings: [string, string]) | 无 |
|
||||
| onChange | 日期范围发生变化的回调 | function(dates: [moment, moment], dateStrings: [string, string]) | 无 |
|
||||
| onOk | 点击确定按钮的回调 | function() | - |
|
||||
| onCalendarChange | 待选日期发生变化的回调 | function(dates: \[moment, moment\], dateStrings: \[string, string\]) | 无 |
|
||||
| onChange | 日期范围发生变化的回调 | function(dates: \[moment, moment\], dateStrings: \[string, string\]) | 无 |
|
||||
| onOk | 点击确定按钮的回调 | function(dates: [moment](http://momentjs.com/)\[]) | - |
|
||||
|
||||
<style>
|
||||
.code-box-demo .ant-calendar-picker {
|
||||
|
||||
@@ -67,7 +67,7 @@ export interface RangePickerProps extends PickerProps {
|
||||
defaultPickerValue?: RangePickerValue;
|
||||
onChange?: (dates: RangePickerValue, dateStrings: [string, string]) => void;
|
||||
onCalendarChange?: (dates: RangePickerValue, dateStrings: [string, string]) => void;
|
||||
onOk?: (selectedTime: moment.Moment) => void;
|
||||
onOk?: (selectedTime: moment.Moment[]) => void;
|
||||
showTime?: TimePickerProps | boolean;
|
||||
ranges?: {
|
||||
[range: string]: RangePickerPresetRange;
|
||||
|
||||
261
components/drawer/__tests__/__snapshots__/demo.test.js.snap
Normal file
261
components/drawer/__tests__/__snapshots__/demo.test.js.snap
Normal file
@@ -0,0 +1,261 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders ./components/drawer/demo/basic-right.md correctly 1`] = `
|
||||
<div>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Open
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/drawer/demo/form-in-drawer.md correctly 1`] = `
|
||||
<div>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary"
|
||||
type="button"
|
||||
>
|
||||
<i
|
||||
class="anticon anticon-plus"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="plus"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M848 474H550V152h-76v322H176c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h298v322h76V550h298c4.4 0 8-3.6 8-8v-60c0-4.4-3.6-8-8-8z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
<span>
|
||||
New account
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/drawer/demo/multi-level-drawer.md correctly 1`] = `
|
||||
<div>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Open drawer
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/drawer/demo/placement.md correctly 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-radio-group ant-radio-group-outline"
|
||||
style="margin-right:8px"
|
||||
>
|
||||
<label
|
||||
class="ant-radio-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-radio"
|
||||
>
|
||||
<input
|
||||
class="ant-radio-input"
|
||||
type="radio"
|
||||
value="top"
|
||||
/>
|
||||
<span
|
||||
class="ant-radio-inner"
|
||||
/>
|
||||
</span>
|
||||
<span>
|
||||
top
|
||||
</span>
|
||||
</label>
|
||||
<label
|
||||
class="ant-radio-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-radio"
|
||||
>
|
||||
<input
|
||||
class="ant-radio-input"
|
||||
type="radio"
|
||||
value="right"
|
||||
/>
|
||||
<span
|
||||
class="ant-radio-inner"
|
||||
/>
|
||||
</span>
|
||||
<span>
|
||||
right
|
||||
</span>
|
||||
</label>
|
||||
<label
|
||||
class="ant-radio-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-radio"
|
||||
>
|
||||
<input
|
||||
class="ant-radio-input"
|
||||
type="radio"
|
||||
value="bottom"
|
||||
/>
|
||||
<span
|
||||
class="ant-radio-inner"
|
||||
/>
|
||||
</span>
|
||||
<span>
|
||||
bottom
|
||||
</span>
|
||||
</label>
|
||||
<label
|
||||
class="ant-radio-wrapper ant-radio-wrapper-checked"
|
||||
>
|
||||
<span
|
||||
class="ant-radio ant-radio-checked"
|
||||
>
|
||||
<input
|
||||
checked=""
|
||||
class="ant-radio-input"
|
||||
type="radio"
|
||||
value="left"
|
||||
/>
|
||||
<span
|
||||
class="ant-radio-inner"
|
||||
/>
|
||||
</span>
|
||||
<span>
|
||||
left
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Open
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/drawer/demo/user-profile.md correctly 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-list ant-list-split ant-list-bordered"
|
||||
>
|
||||
<div
|
||||
class="ant-spin-nested-loading"
|
||||
>
|
||||
<div
|
||||
class="ant-spin-container"
|
||||
>
|
||||
<div
|
||||
class="ant-list-item"
|
||||
>
|
||||
<div
|
||||
class="ant-list-item-meta"
|
||||
>
|
||||
<div
|
||||
class="ant-list-item-meta-avatar"
|
||||
>
|
||||
<span
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-list-item-meta-content"
|
||||
>
|
||||
<h4
|
||||
class="ant-list-item-meta-title"
|
||||
>
|
||||
<a
|
||||
href="https://ant.design/index-cn"
|
||||
>
|
||||
Lily
|
||||
</a>
|
||||
</h4>
|
||||
<div
|
||||
class="ant-list-item-meta-description"
|
||||
>
|
||||
Progresser AFX
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ul
|
||||
class="ant-list-item-action"
|
||||
>
|
||||
<li>
|
||||
<a>
|
||||
View Profile
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div
|
||||
class="ant-list-item"
|
||||
>
|
||||
<div
|
||||
class="ant-list-item-meta"
|
||||
>
|
||||
<div
|
||||
class="ant-list-item-meta-avatar"
|
||||
>
|
||||
<span
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-list-item-meta-content"
|
||||
>
|
||||
<h4
|
||||
class="ant-list-item-meta-title"
|
||||
>
|
||||
<a
|
||||
href="https://ant.design/index-cn"
|
||||
>
|
||||
Lily
|
||||
</a>
|
||||
</h4>
|
||||
<div
|
||||
class="ant-list-item-meta-description"
|
||||
>
|
||||
Progresser AFX
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ul
|
||||
class="ant-list-item-action"
|
||||
>
|
||||
<li>
|
||||
<a>
|
||||
View Profile
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
3
components/drawer/__tests__/demo.test.js
Normal file
3
components/drawer/__tests__/demo.test.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import demoTest from '../../../tests/shared/demoTest';
|
||||
|
||||
demoTest('drawer');
|
||||
@@ -1,21 +1,21 @@
|
||||
---
|
||||
order: 3
|
||||
title:
|
||||
zh-CN: 对象编辑
|
||||
en-US: Edit item in drawer
|
||||
zh-CN: 抽屉表单
|
||||
en-US: Submit form in drawer
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
用于承载编辑相关操作,需要点击关闭按钮关闭。
|
||||
在抽屉中使用表单。
|
||||
|
||||
## en-US
|
||||
|
||||
A drawer containing an editable form which needs to be collapsed by clicking the close button.
|
||||
Use form in drawer with submit button.
|
||||
|
||||
```jsx
|
||||
import {
|
||||
Drawer, Form, Button, Col, Row, Input, Select, DatePicker,
|
||||
Drawer, Form, Button, Col, Row, Input, Select, DatePicker, Icon,
|
||||
} from 'antd';
|
||||
|
||||
const { Option } = Select;
|
||||
@@ -40,19 +40,17 @@ class DrawerForm extends React.Component {
|
||||
return (
|
||||
<div>
|
||||
<Button type="primary" onClick={this.showDrawer}>
|
||||
Create
|
||||
<Icon type="plus" /> New account
|
||||
</Button>
|
||||
<Drawer
|
||||
title="Create"
|
||||
title="Create a new account"
|
||||
width={720}
|
||||
placement="right"
|
||||
onClose={this.onClose}
|
||||
maskClosable={false}
|
||||
visible={this.state.visible}
|
||||
style={{
|
||||
height: 'calc(100% - 55px)',
|
||||
overflow: 'auto',
|
||||
paddingBottom: 53,
|
||||
height: 'calc(100% - 108px)',
|
||||
paddingBottom: '108px',
|
||||
}}
|
||||
>
|
||||
<Form layout="vertical" hideRequiredMark>
|
||||
@@ -60,20 +58,20 @@ class DrawerForm extends React.Component {
|
||||
<Col span={12}>
|
||||
<Form.Item label="Name">
|
||||
{getFieldDecorator('name', {
|
||||
rules: [{ required: true, message: 'please enter user name' }],
|
||||
})(<Input placeholder="please enter user name" />)}
|
||||
rules: [{ required: true, message: 'Please enter user name' }],
|
||||
})(<Input placeholder="Please enter user name" />)}
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Form.Item label="Url">
|
||||
{getFieldDecorator('url', {
|
||||
rules: [{ required: true, message: 'please enter url' }],
|
||||
rules: [{ required: true, message: 'Please enter url' }],
|
||||
})(
|
||||
<Input
|
||||
style={{ width: '100%' }}
|
||||
addonBefore="http://"
|
||||
addonAfter=".com"
|
||||
placeholder="please enter url"
|
||||
placeholder="Please enter url"
|
||||
/>
|
||||
)}
|
||||
</Form.Item>
|
||||
@@ -149,25 +147,21 @@ class DrawerForm extends React.Component {
|
||||
<div
|
||||
style={{
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
bottom: 0,
|
||||
width: '100%',
|
||||
borderTop: '1px solid #e8e8e8',
|
||||
borderTop: '1px solid #e9e9e9',
|
||||
padding: '10px 16px',
|
||||
textAlign: 'right',
|
||||
left: 0,
|
||||
background: '#fff',
|
||||
borderRadius: '0 0 4px 4px',
|
||||
textAlign: 'right',
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
style={{
|
||||
marginRight: 8,
|
||||
}}
|
||||
onClick={this.onClose}
|
||||
>
|
||||
<Button onClick={this.onClose} style={{ marginRight: 8 }}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button onClick={this.onClose} type="primary">Submit</Button>
|
||||
<Button onClick={this.onClose} type="primary">
|
||||
Submit
|
||||
</Button>
|
||||
</div>
|
||||
</Drawer>
|
||||
</div>
|
||||
@@ -21,7 +21,7 @@ A Drawer is a panel that is typically overlaid on top of a page and slides in fr
|
||||
| --- | --- | --- | --- |
|
||||
| closable | Whether a close (x) button is visible on top right of the Drawer dialog or not. | boolean | true |
|
||||
| destroyOnClose | Whether to unmount child components on closing drawer or not. | boolean | false |
|
||||
| getContainer | Return the mounted node for Drawer. | HTMLElement \| `() => HTMLElement` \| selectors | 'body' |
|
||||
| getContainer | Return the mounted node for Drawer. | HTMLElement \| `() => HTMLElement` \| Selectors | 'body' |
|
||||
| mask | Whether to show mask or not. | Boolean | true |
|
||||
| maskClosable | Clicking on the mask (area outside the Drawer) to close the Drawer or not. | boolean | true |
|
||||
| maskStyle | Style for Drawer's mask element. | object | {} |
|
||||
|
||||
@@ -196,25 +196,20 @@ export default class Drawer extends React.Component<DrawerProps, IDrawerState> {
|
||||
>
|
||||
{header}
|
||||
{closer}
|
||||
<div className={`${prefixCls}-body`} style={this.props.style}>
|
||||
{this.props.children}
|
||||
</div>
|
||||
<div className={`${prefixCls}-body`}>{this.props.children}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
getRcDrawerStyle = () => {
|
||||
const { zIndex, placement, maskStyle } = this.props;
|
||||
return this.state.push
|
||||
? {
|
||||
...maskStyle,
|
||||
zIndex,
|
||||
transform: this.getPushTransform(placement),
|
||||
}
|
||||
: {
|
||||
...maskStyle,
|
||||
zIndex,
|
||||
};
|
||||
const { zIndex, placement, maskStyle, style } = this.props;
|
||||
const { push } = this.state;
|
||||
return {
|
||||
...maskStyle,
|
||||
zIndex,
|
||||
transform: push ? this.getPushTransform(placement) : undefined,
|
||||
style,
|
||||
};
|
||||
};
|
||||
|
||||
// render Provider for Multi-level drawe
|
||||
|
||||
@@ -20,7 +20,7 @@ title: Drawer
|
||||
| --- | --- | --- | --- |
|
||||
| closable | 是否显示右上角的关闭按钮 | boolean | true |
|
||||
| destroyOnClose | 关闭时销毁 Drawer 里的子元素 | boolean | false |
|
||||
| getContainer | 指定 Drawer 挂载的 HTML 节点 | HTMLElement \| `() => HTMLElement` \| selectors | 'body' |
|
||||
| getContainer | 指定 Drawer 挂载的 HTML 节点 | HTMLElement \| `() => HTMLElement` \| Selectors | 'body' |
|
||||
| maskClosable | 点击蒙层是否允许关闭 | boolean | true |
|
||||
| mask | 是否展示遮罩 | Boolean | true |
|
||||
| maskStyle | 遮罩样式 | object | {} |
|
||||
|
||||
@@ -18,6 +18,8 @@ export interface DropDownProps {
|
||||
className?: string;
|
||||
transitionName?: string;
|
||||
placement?: 'topLeft' | 'topCenter' | 'topRight' | 'bottomLeft' | 'bottomCenter' | 'bottomRight';
|
||||
overlayClassName?: string;
|
||||
overlayStyle?: React.CSSProperties;
|
||||
forceRender?: boolean;
|
||||
mouseEnterDelay?: number;
|
||||
mouseLeaveDelay?: number;
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
position: absolute;
|
||||
top: -7px;
|
||||
left: -7px;
|
||||
right: -7px;
|
||||
right: 0;
|
||||
bottom: -7px;
|
||||
content: ' ';
|
||||
opacity: 0.0001;
|
||||
@@ -55,6 +55,7 @@
|
||||
border-radius: @border-radius-base;
|
||||
box-shadow: @box-shadow-base;
|
||||
background-clip: padding-box;
|
||||
-webkit-transform: translate3d(0, 0, 0);
|
||||
|
||||
&-item-group-title {
|
||||
color: @text-color-secondary;
|
||||
|
||||
@@ -83,6 +83,8 @@ export type GetFieldDecoratorOptions = {
|
||||
normalize?: (value: any, prevValue: any, allValues: any) => any;
|
||||
/** Whether stop validate on first rule of error for this field. */
|
||||
validateFirst?: boolean;
|
||||
/** 是否一直保留子节点的信息 */
|
||||
preserve?: boolean;
|
||||
};
|
||||
|
||||
// function create
|
||||
|
||||
@@ -3118,6 +3118,163 @@ exports[`renders ./components/form/demo/validate-other.md correctly 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-row ant-form-item"
|
||||
>
|
||||
<div
|
||||
class="ant-col-6 ant-form-item-label"
|
||||
>
|
||||
<label
|
||||
class=""
|
||||
for="checkbox-group"
|
||||
title="Checkbox.Group"
|
||||
>
|
||||
Checkbox.Group
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="ant-col-14 ant-form-item-control-wrapper"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-control has-success"
|
||||
>
|
||||
<span
|
||||
class="ant-form-item-children"
|
||||
>
|
||||
<div
|
||||
class="ant-checkbox-group"
|
||||
data-__field="[object Object]"
|
||||
data-__meta="[object Object]"
|
||||
id="checkbox-group"
|
||||
style="width:100%"
|
||||
>
|
||||
<div
|
||||
class="ant-row"
|
||||
>
|
||||
<div
|
||||
class="ant-col-8"
|
||||
>
|
||||
<label
|
||||
class="ant-checkbox-wrapper ant-checkbox-wrapper-checked"
|
||||
>
|
||||
<span
|
||||
class="ant-checkbox ant-checkbox-checked"
|
||||
>
|
||||
<input
|
||||
checked=""
|
||||
class="ant-checkbox-input"
|
||||
type="checkbox"
|
||||
value="A"
|
||||
/>
|
||||
<span
|
||||
class="ant-checkbox-inner"
|
||||
/>
|
||||
</span>
|
||||
<span>
|
||||
A
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="ant-col-8"
|
||||
>
|
||||
<label
|
||||
class="ant-checkbox-wrapper ant-checkbox-wrapper-checked ant-checkbox-wrapper-disabled"
|
||||
>
|
||||
<span
|
||||
class="ant-checkbox ant-checkbox-checked ant-checkbox-disabled"
|
||||
>
|
||||
<input
|
||||
checked=""
|
||||
class="ant-checkbox-input"
|
||||
disabled=""
|
||||
type="checkbox"
|
||||
value="B"
|
||||
/>
|
||||
<span
|
||||
class="ant-checkbox-inner"
|
||||
/>
|
||||
</span>
|
||||
<span>
|
||||
B
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="ant-col-8"
|
||||
>
|
||||
<label
|
||||
class="ant-checkbox-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-checkbox"
|
||||
>
|
||||
<input
|
||||
class="ant-checkbox-input"
|
||||
type="checkbox"
|
||||
value="C"
|
||||
/>
|
||||
<span
|
||||
class="ant-checkbox-inner"
|
||||
/>
|
||||
</span>
|
||||
<span>
|
||||
C
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="ant-col-8"
|
||||
>
|
||||
<label
|
||||
class="ant-checkbox-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-checkbox"
|
||||
>
|
||||
<input
|
||||
class="ant-checkbox-input"
|
||||
type="checkbox"
|
||||
value="D"
|
||||
/>
|
||||
<span
|
||||
class="ant-checkbox-inner"
|
||||
/>
|
||||
</span>
|
||||
<span>
|
||||
D
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="ant-col-8"
|
||||
>
|
||||
<label
|
||||
class="ant-checkbox-wrapper"
|
||||
>
|
||||
<span
|
||||
class="ant-checkbox"
|
||||
>
|
||||
<input
|
||||
class="ant-checkbox-input"
|
||||
type="checkbox"
|
||||
value="E"
|
||||
/>
|
||||
<span
|
||||
class="ant-checkbox-inner"
|
||||
/>
|
||||
</span>
|
||||
<span>
|
||||
E
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-row ant-form-item"
|
||||
>
|
||||
@@ -4171,6 +4328,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
|
||||
</div>
|
||||
<div
|
||||
class="ant-row ant-form-item"
|
||||
style="margin-bottom:0"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-label ant-col-xs-24 ant-col-sm-5"
|
||||
@@ -4192,114 +4350,104 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
|
||||
class="ant-form-item-children"
|
||||
>
|
||||
<div
|
||||
class="ant-col-11"
|
||||
class="ant-row ant-form-item ant-form-item-with-help"
|
||||
style="display:inline-block;width:calc(50% - 12px)"
|
||||
>
|
||||
<div
|
||||
class="ant-row ant-form-item ant-form-item-with-help"
|
||||
class="ant-form-item-control-wrapper"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-control-wrapper"
|
||||
class="ant-form-item-control has-error"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-control has-error"
|
||||
<span
|
||||
class="ant-form-item-children"
|
||||
>
|
||||
<span
|
||||
class="ant-form-item-children"
|
||||
class="ant-calendar-picker"
|
||||
>
|
||||
<span
|
||||
class="ant-calendar-picker"
|
||||
>
|
||||
<div>
|
||||
<input
|
||||
class="ant-calendar-picker-input ant-input"
|
||||
placeholder="Select date"
|
||||
readonly=""
|
||||
value=""
|
||||
/>
|
||||
<i
|
||||
class="anticon anticon-calendar ant-calendar-picker-icon"
|
||||
<div>
|
||||
<input
|
||||
class="ant-calendar-picker-input ant-input"
|
||||
placeholder="Select date"
|
||||
readonly=""
|
||||
value=""
|
||||
/>
|
||||
<i
|
||||
class="anticon anticon-calendar ant-calendar-picker-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="calendar"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="calendar"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M880 184H712v-64c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v64H384v-64c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v64H144c-17.7 0-32 14.3-32 32v664c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V216c0-17.7-14.3-32-32-32zm-40 656H184V460h656v380zM184 392V256h128v48c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-48h256v48c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-48h128v136H184z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
</div>
|
||||
</span>
|
||||
<path
|
||||
d="M880 184H712v-64c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v64H384v-64c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v64H144c-17.7 0-32 14.3-32 32v664c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V216c0-17.7-14.3-32-32-32zm-40 656H184V460h656v380zM184 392V256h128v48c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-48h256v48c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-48h128v136H184z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
</div>
|
||||
</span>
|
||||
<div
|
||||
class="ant-form-explain"
|
||||
>
|
||||
Please select the correct date
|
||||
</div>
|
||||
</span>
|
||||
<div
|
||||
class="ant-form-explain"
|
||||
>
|
||||
Please select the correct date
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-col-2"
|
||||
<span
|
||||
style="display:inline-block;width:24px;text-align:center"
|
||||
>
|
||||
<span
|
||||
style="display:inline-block;width:100%;text-align:center"
|
||||
>
|
||||
-
|
||||
</span>
|
||||
</div>
|
||||
-
|
||||
</span>
|
||||
<div
|
||||
class="ant-col-11"
|
||||
class="ant-row ant-form-item"
|
||||
style="display:inline-block;width:calc(50% - 12px)"
|
||||
>
|
||||
<div
|
||||
class="ant-row ant-form-item"
|
||||
class="ant-form-item-control-wrapper"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-control-wrapper"
|
||||
class="ant-form-item-control"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-control"
|
||||
<span
|
||||
class="ant-form-item-children"
|
||||
>
|
||||
<span
|
||||
class="ant-form-item-children"
|
||||
class="ant-calendar-picker"
|
||||
>
|
||||
<span
|
||||
class="ant-calendar-picker"
|
||||
>
|
||||
<div>
|
||||
<input
|
||||
class="ant-calendar-picker-input ant-input"
|
||||
placeholder="Select date"
|
||||
readonly=""
|
||||
value=""
|
||||
/>
|
||||
<i
|
||||
class="anticon anticon-calendar ant-calendar-picker-icon"
|
||||
<div>
|
||||
<input
|
||||
class="ant-calendar-picker-input ant-input"
|
||||
placeholder="Select date"
|
||||
readonly=""
|
||||
value=""
|
||||
/>
|
||||
<i
|
||||
class="anticon anticon-calendar ant-calendar-picker-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="calendar"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="calendar"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M880 184H712v-64c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v64H384v-64c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v64H144c-17.7 0-32 14.3-32 32v664c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V216c0-17.7-14.3-32-32-32zm-40 656H184V460h656v380zM184 392V256h128v48c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-48h256v48c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-48h128v136H184z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
</div>
|
||||
</span>
|
||||
<path
|
||||
d="M880 184H712v-64c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v64H384v-64c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v64H144c-17.7 0-32 14.3-32 32v664c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V216c0-17.7-14.3-32-32-32zm-40 656H184V460h656v380zM184 392V256h128v48c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-48h256v48c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-48h128v136H184z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -23,8 +23,6 @@ import {
|
||||
Form, Row, Col, Input, Button, Icon,
|
||||
} from 'antd';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
class AdvancedSearchForm extends React.Component {
|
||||
state = {
|
||||
expand: false,
|
||||
@@ -38,7 +36,7 @@ class AdvancedSearchForm extends React.Component {
|
||||
for (let i = 0; i < 10; i++) {
|
||||
children.push(
|
||||
<Col span={8} key={i} style={{ display: i < count ? 'block' : 'none' }}>
|
||||
<FormItem label={`Field ${i}`}>
|
||||
<Form.Item label={`Field ${i}`}>
|
||||
{getFieldDecorator(`field-${i}`, {
|
||||
rules: [{
|
||||
required: true,
|
||||
@@ -47,7 +45,7 @@ class AdvancedSearchForm extends React.Component {
|
||||
})(
|
||||
<Input placeholder="placeholder" />
|
||||
)}
|
||||
</FormItem>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -18,8 +18,7 @@ import {
|
||||
Form, Select, Input, Button,
|
||||
} from 'antd';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const Option = Select.Option;
|
||||
const { Option } = Select;
|
||||
|
||||
class App extends React.Component {
|
||||
handleSubmit = (e) => {
|
||||
@@ -42,7 +41,7 @@ class App extends React.Component {
|
||||
const { getFieldDecorator } = this.props.form;
|
||||
return (
|
||||
<Form onSubmit={this.handleSubmit}>
|
||||
<FormItem
|
||||
<Form.Item
|
||||
label="Note"
|
||||
labelCol={{ span: 5 }}
|
||||
wrapperCol={{ span: 12 }}
|
||||
@@ -52,8 +51,8 @@ class App extends React.Component {
|
||||
})(
|
||||
<Input />
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="Gender"
|
||||
labelCol={{ span: 5 }}
|
||||
wrapperCol={{ span: 12 }}
|
||||
@@ -69,14 +68,14 @@ class App extends React.Component {
|
||||
<Option value="female">female</Option>
|
||||
</Select>
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
wrapperCol={{ span: 12, offset: 5 }}
|
||||
>
|
||||
<Button type="primary" htmlType="submit">
|
||||
Submit
|
||||
</Button>
|
||||
</FormItem>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -24,8 +24,7 @@ import {
|
||||
Form, Input, Select, Button,
|
||||
} from 'antd';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const Option = Select.Option;
|
||||
const { Option } = Select;
|
||||
|
||||
class PriceInput extends React.Component {
|
||||
static getDerivedStateFromProps(nextProps) {
|
||||
@@ -122,15 +121,15 @@ class Demo extends React.Component {
|
||||
const { getFieldDecorator } = this.props.form;
|
||||
return (
|
||||
<Form layout="inline" onSubmit={this.handleSubmit}>
|
||||
<FormItem label="Price">
|
||||
<Form.Item label="Price">
|
||||
{getFieldDecorator('price', {
|
||||
initialValue: { number: 0, currency: 'rmb' },
|
||||
rules: [{ validator: this.checkPrice }],
|
||||
})(<PriceInput />)}
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
<Button type="primary" htmlType="submit">Submit</Button>
|
||||
</FormItem>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -18,8 +18,6 @@ import {
|
||||
Form, Input, Icon, Button,
|
||||
} from 'antd';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
let id = 0;
|
||||
|
||||
class DynamicFieldSet extends React.Component {
|
||||
@@ -80,7 +78,7 @@ class DynamicFieldSet extends React.Component {
|
||||
getFieldDecorator('keys', { initialValue: [] });
|
||||
const keys = getFieldValue('keys');
|
||||
const formItems = keys.map((k, index) => (
|
||||
<FormItem
|
||||
<Form.Item
|
||||
{...(index === 0 ? formItemLayout : formItemLayoutWithOutLabel)}
|
||||
label={index === 0 ? 'Passengers' : ''}
|
||||
required={false}
|
||||
@@ -104,19 +102,19 @@ class DynamicFieldSet extends React.Component {
|
||||
onClick={() => this.remove(k)}
|
||||
/>
|
||||
) : null}
|
||||
</FormItem>
|
||||
</Form.Item>
|
||||
));
|
||||
return (
|
||||
<Form onSubmit={this.handleSubmit}>
|
||||
{formItems}
|
||||
<FormItem {...formItemLayoutWithOutLabel}>
|
||||
<Form.Item {...formItemLayoutWithOutLabel}>
|
||||
<Button type="dashed" onClick={this.add} style={{ width: '60%' }}>
|
||||
<Icon type="plus" /> Add field
|
||||
</Button>
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayoutWithOutLabel}>
|
||||
</Form.Item>
|
||||
<Form.Item {...formItemLayoutWithOutLabel}>
|
||||
<Button type="primary" htmlType="submit">Submit</Button>
|
||||
</FormItem>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -18,8 +18,6 @@ import {
|
||||
Form, Input, Button, Checkbox,
|
||||
} from 'antd';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
const formItemLayout = {
|
||||
labelCol: { span: 4 },
|
||||
wrapperCol: { span: 8 },
|
||||
@@ -55,7 +53,7 @@ class DynamicRule extends React.Component {
|
||||
const { getFieldDecorator } = this.props.form;
|
||||
return (
|
||||
<div>
|
||||
<FormItem {...formItemLayout} label="Name">
|
||||
<Form.Item {...formItemLayout} label="Name">
|
||||
{getFieldDecorator('username', {
|
||||
rules: [{
|
||||
required: true,
|
||||
@@ -64,8 +62,8 @@ class DynamicRule extends React.Component {
|
||||
})(
|
||||
<Input placeholder="Please input your name" />
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="Nickname">
|
||||
</Form.Item>
|
||||
<Form.Item {...formItemLayout} label="Nickname">
|
||||
{getFieldDecorator('nickname', {
|
||||
rules: [{
|
||||
required: this.state.checkNick,
|
||||
@@ -74,20 +72,20 @@ class DynamicRule extends React.Component {
|
||||
})(
|
||||
<Input placeholder="Please input your nickname" />
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem {...formTailLayout}>
|
||||
</Form.Item>
|
||||
<Form.Item {...formTailLayout}>
|
||||
<Checkbox
|
||||
checked={this.state.checkNick}
|
||||
onChange={this.handleChange}
|
||||
>
|
||||
Nickname is required
|
||||
</Checkbox>
|
||||
</FormItem>
|
||||
<FormItem {...formTailLayout}>
|
||||
</Form.Item>
|
||||
<Form.Item {...formTailLayout}>
|
||||
<Button type="primary" onClick={this.check}>
|
||||
Check
|
||||
</Button>
|
||||
</FormItem>
|
||||
</Form.Item>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -18,8 +18,6 @@ import {
|
||||
Button, Modal, Form, Input, Radio,
|
||||
} from 'antd';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
const CollectionCreateForm = Form.create()(
|
||||
// eslint-disable-next-line
|
||||
class extends React.Component {
|
||||
@@ -37,17 +35,17 @@ const CollectionCreateForm = Form.create()(
|
||||
onOk={onCreate}
|
||||
>
|
||||
<Form layout="vertical">
|
||||
<FormItem label="Title">
|
||||
<Form.Item label="Title">
|
||||
{getFieldDecorator('title', {
|
||||
rules: [{ required: true, message: 'Please input the title of collection!' }],
|
||||
})(
|
||||
<Input />
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem label="Description">
|
||||
</Form.Item>
|
||||
<Form.Item label="Description">
|
||||
{getFieldDecorator('description')(<Input type="textarea" />)}
|
||||
</FormItem>
|
||||
<FormItem className="collection-create-form_last-form-item">
|
||||
</Form.Item>
|
||||
<Form.Item className="collection-create-form_last-form-item">
|
||||
{getFieldDecorator('modifier', {
|
||||
initialValue: 'public',
|
||||
})(
|
||||
@@ -56,7 +54,7 @@ const CollectionCreateForm = Form.create()(
|
||||
<Radio value="private">Private</Radio>
|
||||
</Radio.Group>
|
||||
)}
|
||||
</FormItem>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
);
|
||||
|
||||
@@ -20,8 +20,6 @@ We can store form data into upper component or [Redux](https://github.com/reactj
|
||||
````jsx
|
||||
import { Form, Input } from 'antd';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
const CustomizedForm = Form.create({
|
||||
onFieldsChange(props, changedFields) {
|
||||
props.onChange(changedFields);
|
||||
@@ -41,11 +39,11 @@ const CustomizedForm = Form.create({
|
||||
const { getFieldDecorator } = props.form;
|
||||
return (
|
||||
<Form layout="inline">
|
||||
<FormItem label="Username">
|
||||
<Form.Item label="Username">
|
||||
{getFieldDecorator('username', {
|
||||
rules: [{ required: true, message: 'Username is required!' }],
|
||||
})(<Input />)}
|
||||
</FormItem>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -18,8 +18,6 @@ import {
|
||||
Form, Icon, Input, Button,
|
||||
} from 'antd';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
function hasErrors(fieldsError) {
|
||||
return Object.keys(fieldsError).some(field => fieldsError[field]);
|
||||
}
|
||||
@@ -49,7 +47,7 @@ class HorizontalLoginForm extends React.Component {
|
||||
const passwordError = isFieldTouched('password') && getFieldError('password');
|
||||
return (
|
||||
<Form layout="inline" onSubmit={this.handleSubmit}>
|
||||
<FormItem
|
||||
<Form.Item
|
||||
validateStatus={userNameError ? 'error' : ''}
|
||||
help={userNameError || ''}
|
||||
>
|
||||
@@ -58,8 +56,8 @@ class HorizontalLoginForm extends React.Component {
|
||||
})(
|
||||
<Input prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />} placeholder="Username" />
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
validateStatus={passwordError ? 'error' : ''}
|
||||
help={passwordError || ''}
|
||||
>
|
||||
@@ -68,8 +66,8 @@ class HorizontalLoginForm extends React.Component {
|
||||
})(
|
||||
<Input prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />} type="password" placeholder="Password" />
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
<Button
|
||||
type="primary"
|
||||
htmlType="submit"
|
||||
@@ -77,7 +75,7 @@ class HorizontalLoginForm extends React.Component {
|
||||
>
|
||||
Log in
|
||||
</Button>
|
||||
</FormItem>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -18,8 +18,6 @@ import {
|
||||
Form, Input, Button, Radio,
|
||||
} from 'antd';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
class FormLayoutDemo extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
@@ -44,7 +42,7 @@ class FormLayoutDemo extends React.Component {
|
||||
return (
|
||||
<div>
|
||||
<Form layout={formLayout}>
|
||||
<FormItem
|
||||
<Form.Item
|
||||
label="Form Layout"
|
||||
{...formItemLayout}
|
||||
>
|
||||
@@ -53,22 +51,22 @@ class FormLayoutDemo extends React.Component {
|
||||
<Radio.Button value="vertical">Vertical</Radio.Button>
|
||||
<Radio.Button value="inline">Inline</Radio.Button>
|
||||
</Radio.Group>
|
||||
</FormItem>
|
||||
<FormItem
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="Field A"
|
||||
{...formItemLayout}
|
||||
>
|
||||
<Input placeholder="input placeholder" />
|
||||
</FormItem>
|
||||
<FormItem
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="Field B"
|
||||
{...formItemLayout}
|
||||
>
|
||||
<Input placeholder="input placeholder" />
|
||||
</FormItem>
|
||||
<FormItem {...buttonItemLayout}>
|
||||
</Form.Item>
|
||||
<Form.Item {...buttonItemLayout}>
|
||||
<Button type="primary">Submit</Button>
|
||||
</FormItem>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -18,8 +18,6 @@ import {
|
||||
Form, Icon, Input, Button, Checkbox,
|
||||
} from 'antd';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
class NormalLoginForm extends React.Component {
|
||||
handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
@@ -34,21 +32,21 @@ class NormalLoginForm extends React.Component {
|
||||
const { getFieldDecorator } = this.props.form;
|
||||
return (
|
||||
<Form onSubmit={this.handleSubmit} className="login-form">
|
||||
<FormItem>
|
||||
<Form.Item>
|
||||
{getFieldDecorator('userName', {
|
||||
rules: [{ required: true, message: 'Please input your username!' }],
|
||||
})(
|
||||
<Input prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />} placeholder="Username" />
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
{getFieldDecorator('password', {
|
||||
rules: [{ required: true, message: 'Please input your Password!' }],
|
||||
})(
|
||||
<Input prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />} type="password" placeholder="Password" />
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
{getFieldDecorator('remember', {
|
||||
valuePropName: 'checked',
|
||||
initialValue: true,
|
||||
@@ -60,7 +58,7 @@ class NormalLoginForm extends React.Component {
|
||||
Log in
|
||||
</Button>
|
||||
Or <a href="">register now!</a>
|
||||
</FormItem>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -18,8 +18,7 @@ import {
|
||||
Form, Input, Tooltip, Icon, Cascader, Select, Row, Col, Checkbox, Button, AutoComplete,
|
||||
} from 'antd';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const Option = Select.Option;
|
||||
const { Option } = Select;
|
||||
const AutoCompleteOption = AutoComplete.Option;
|
||||
|
||||
const residences = [{
|
||||
@@ -134,7 +133,7 @@ class RegistrationForm extends React.Component {
|
||||
|
||||
return (
|
||||
<Form onSubmit={this.handleSubmit}>
|
||||
<FormItem
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label="E-mail"
|
||||
>
|
||||
@@ -147,8 +146,8 @@ class RegistrationForm extends React.Component {
|
||||
})(
|
||||
<Input />
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label="Password"
|
||||
>
|
||||
@@ -161,8 +160,8 @@ class RegistrationForm extends React.Component {
|
||||
})(
|
||||
<Input type="password" />
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label="Confirm Password"
|
||||
>
|
||||
@@ -175,8 +174,8 @@ class RegistrationForm extends React.Component {
|
||||
})(
|
||||
<Input type="password" onBlur={this.handleConfirmBlur} />
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label={(
|
||||
<span>
|
||||
@@ -192,8 +191,8 @@ class RegistrationForm extends React.Component {
|
||||
})(
|
||||
<Input />
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label="Habitual Residence"
|
||||
>
|
||||
@@ -203,8 +202,8 @@ class RegistrationForm extends React.Component {
|
||||
})(
|
||||
<Cascader options={residences} />
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label="Phone Number"
|
||||
>
|
||||
@@ -213,8 +212,8 @@ class RegistrationForm extends React.Component {
|
||||
})(
|
||||
<Input addonBefore={prefixSelector} style={{ width: '100%' }} />
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label="Website"
|
||||
>
|
||||
@@ -229,8 +228,8 @@ class RegistrationForm extends React.Component {
|
||||
<Input />
|
||||
</AutoComplete>
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label="Captcha"
|
||||
extra="We must make sure that your are a human."
|
||||
@@ -247,17 +246,17 @@ class RegistrationForm extends React.Component {
|
||||
<Button>Get captcha</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
<FormItem {...tailFormItemLayout}>
|
||||
</Form.Item>
|
||||
<Form.Item {...tailFormItemLayout}>
|
||||
{getFieldDecorator('agreement', {
|
||||
valuePropName: 'checked',
|
||||
})(
|
||||
<Checkbox>I have read the <a href="">agreement</a></Checkbox>
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem {...tailFormItemLayout}>
|
||||
</Form.Item>
|
||||
<Form.Item {...tailFormItemLayout}>
|
||||
<Button type="primary" htmlType="submit">Register</Button>
|
||||
</FormItem>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ import {
|
||||
Form, DatePicker, TimePicker, Button,
|
||||
} from 'antd';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const { MonthPicker, RangePicker } = DatePicker;
|
||||
|
||||
class TimeRelatedForm extends React.Component {
|
||||
@@ -69,62 +68,62 @@ class TimeRelatedForm extends React.Component {
|
||||
};
|
||||
return (
|
||||
<Form onSubmit={this.handleSubmit}>
|
||||
<FormItem
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label="DatePicker"
|
||||
>
|
||||
{getFieldDecorator('date-picker', config)(
|
||||
<DatePicker />
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label="DatePicker[showTime]"
|
||||
>
|
||||
{getFieldDecorator('date-time-picker', config)(
|
||||
<DatePicker showTime format="YYYY-MM-DD HH:mm:ss" />
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label="MonthPicker"
|
||||
>
|
||||
{getFieldDecorator('month-picker', config)(
|
||||
<MonthPicker />
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label="RangePicker"
|
||||
>
|
||||
{getFieldDecorator('range-picker', rangeConfig)(
|
||||
<RangePicker />
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label="RangePicker[showTime]"
|
||||
>
|
||||
{getFieldDecorator('range-time-picker', rangeConfig)(
|
||||
<RangePicker showTime format="YYYY-MM-DD HH:mm:ss" />
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label="TimePicker"
|
||||
>
|
||||
{getFieldDecorator('time-picker', config)(
|
||||
<TimePicker />
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
wrapperCol={{
|
||||
xs: { span: 24, offset: 0 },
|
||||
sm: { span: 16, offset: 8 },
|
||||
}}
|
||||
>
|
||||
<Button type="primary" htmlType="submit">Submit</Button>
|
||||
</FormItem>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -16,13 +16,11 @@ Demostration for validataion configuration for form controls which are not show
|
||||
````jsx
|
||||
import {
|
||||
Form, Select, InputNumber, Switch, Radio,
|
||||
Slider, Button, Upload, Icon, Rate,
|
||||
Slider, Button, Upload, Icon, Rate, Checkbox,
|
||||
Row, Col,
|
||||
} from 'antd';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const Option = Select.Option;
|
||||
const RadioButton = Radio.Button;
|
||||
const RadioGroup = Radio.Group;
|
||||
const { Option } = Select;
|
||||
|
||||
class Demo extends React.Component {
|
||||
handleSubmit = (e) => {
|
||||
@@ -50,13 +48,13 @@ class Demo extends React.Component {
|
||||
};
|
||||
return (
|
||||
<Form onSubmit={this.handleSubmit}>
|
||||
<FormItem
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label="Plain Text"
|
||||
>
|
||||
<span className="ant-form-text">China</span>
|
||||
</FormItem>
|
||||
<FormItem
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label="Select"
|
||||
hasFeedback
|
||||
@@ -71,9 +69,9 @@ class Demo extends React.Component {
|
||||
<Option value="usa">U.S.A</Option>
|
||||
</Select>
|
||||
)}
|
||||
</FormItem>
|
||||
</Form.Item>
|
||||
|
||||
<FormItem
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label="Select[multiple]"
|
||||
>
|
||||
@@ -88,9 +86,9 @@ class Demo extends React.Component {
|
||||
<Option value="blue">Blue</Option>
|
||||
</Select>
|
||||
)}
|
||||
</FormItem>
|
||||
</Form.Item>
|
||||
|
||||
<FormItem
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label="InputNumber"
|
||||
>
|
||||
@@ -98,18 +96,18 @@ class Demo extends React.Component {
|
||||
<InputNumber min={1} max={10} />
|
||||
)}
|
||||
<span className="ant-form-text"> machines</span>
|
||||
</FormItem>
|
||||
</Form.Item>
|
||||
|
||||
<FormItem
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label="Switch"
|
||||
>
|
||||
{getFieldDecorator('switch', { valuePropName: 'checked' })(
|
||||
<Switch />
|
||||
)}
|
||||
</FormItem>
|
||||
</Form.Item>
|
||||
|
||||
<FormItem
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label="Slider"
|
||||
>
|
||||
@@ -119,35 +117,54 @@ class Demo extends React.Component {
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</FormItem>
|
||||
</Form.Item>
|
||||
|
||||
<FormItem
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label="Radio.Group"
|
||||
>
|
||||
{getFieldDecorator('radio-group')(
|
||||
<RadioGroup>
|
||||
<Radio.Group>
|
||||
<Radio value="a">item 1</Radio>
|
||||
<Radio value="b">item 2</Radio>
|
||||
<Radio value="c">item 3</Radio>
|
||||
</RadioGroup>
|
||||
</Radio.Group>
|
||||
)}
|
||||
</FormItem>
|
||||
</Form.Item>
|
||||
|
||||
<FormItem
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label="Radio.Button"
|
||||
>
|
||||
{getFieldDecorator('radio-button')(
|
||||
<RadioGroup>
|
||||
<RadioButton value="a">item 1</RadioButton>
|
||||
<RadioButton value="b">item 2</RadioButton>
|
||||
<RadioButton value="c">item 3</RadioButton>
|
||||
</RadioGroup>
|
||||
<Radio.Group>
|
||||
<Radio.Button value="a">item 1</Radio.Button>
|
||||
<Radio.Button value="b">item 2</Radio.Button>
|
||||
<Radio.Button value="c">item 3</Radio.Button>
|
||||
</Radio.Group>
|
||||
)}
|
||||
</FormItem>
|
||||
</Form.Item>
|
||||
|
||||
<FormItem
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label="Checkbox.Group"
|
||||
>
|
||||
{getFieldDecorator("checkbox-group", {
|
||||
initialValue: ["A", "B"],
|
||||
})(
|
||||
<Checkbox.Group style={{ width: "100%" }}>
|
||||
<Row>
|
||||
<Col span={8}><Checkbox value="A">A</Checkbox></Col>
|
||||
<Col span={8}><Checkbox disabled value="B">B</Checkbox></Col>
|
||||
<Col span={8}><Checkbox value="C">C</Checkbox></Col>
|
||||
<Col span={8}><Checkbox value="D">D</Checkbox></Col>
|
||||
<Col span={8}><Checkbox value="E">E</Checkbox></Col>
|
||||
</Row>
|
||||
</Checkbox.Group>
|
||||
)}
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label="Rate"
|
||||
>
|
||||
@@ -156,9 +173,9 @@ class Demo extends React.Component {
|
||||
})(
|
||||
<Rate />
|
||||
)}
|
||||
</FormItem>
|
||||
</Form.Item>
|
||||
|
||||
<FormItem
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label="Upload"
|
||||
extra="longgggggggggggggggggggggggggggggggggg"
|
||||
@@ -173,9 +190,9 @@ class Demo extends React.Component {
|
||||
</Button>
|
||||
</Upload>
|
||||
)}
|
||||
</FormItem>
|
||||
</Form.Item>
|
||||
|
||||
<FormItem
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label="Dragger"
|
||||
>
|
||||
@@ -193,13 +210,13 @@ class Demo extends React.Component {
|
||||
</Upload.Dragger>
|
||||
)}
|
||||
</div>
|
||||
</FormItem>
|
||||
</Form.Item>
|
||||
|
||||
<FormItem
|
||||
<Form.Item
|
||||
wrapperCol={{ span: 12, offset: 6 }}
|
||||
>
|
||||
<Button type="primary" htmlType="submit">Submit</Button>
|
||||
</FormItem>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -23,11 +23,10 @@ We provide properties like `validateStatus` `help` `hasFeedback` to customize yo
|
||||
|
||||
````jsx
|
||||
import {
|
||||
Form, Input, DatePicker, Col, TimePicker, Select, Cascader, InputNumber,
|
||||
Form, Input, DatePicker, TimePicker, Select, Cascader, InputNumber,
|
||||
} from 'antd';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const Option = Select.Option;
|
||||
const { Option } = Select;
|
||||
|
||||
const formItemLayout = {
|
||||
labelCol: {
|
||||
@@ -42,24 +41,24 @@ const formItemLayout = {
|
||||
|
||||
ReactDOM.render(
|
||||
<Form>
|
||||
<FormItem
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label="Fail"
|
||||
validateStatus="error"
|
||||
help="Should be combination of numbers & alphabets"
|
||||
>
|
||||
<Input placeholder="unavailable choice" id="error" />
|
||||
</FormItem>
|
||||
</Form.Item>
|
||||
|
||||
<FormItem
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label="Warning"
|
||||
validateStatus="warning"
|
||||
>
|
||||
<Input placeholder="Warning" id="warning" />
|
||||
</FormItem>
|
||||
</Form.Item>
|
||||
|
||||
<FormItem
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label="Validating"
|
||||
hasFeedback
|
||||
@@ -67,27 +66,27 @@ ReactDOM.render(
|
||||
help="The information is being validated..."
|
||||
>
|
||||
<Input placeholder="I'm the content is being validated" id="validating" />
|
||||
</FormItem>
|
||||
</Form.Item>
|
||||
|
||||
<FormItem
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label="Success"
|
||||
hasFeedback
|
||||
validateStatus="success"
|
||||
>
|
||||
<Input placeholder="I'm the content" id="success" />
|
||||
</FormItem>
|
||||
</Form.Item>
|
||||
|
||||
<FormItem
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label="Warning"
|
||||
hasFeedback
|
||||
validateStatus="warning"
|
||||
>
|
||||
<Input placeholder="Warning" id="warning" />
|
||||
</FormItem>
|
||||
</Form.Item>
|
||||
|
||||
<FormItem
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label="Fail"
|
||||
hasFeedback
|
||||
@@ -95,27 +94,27 @@ ReactDOM.render(
|
||||
help="Should be combination of numbers & alphabets"
|
||||
>
|
||||
<Input placeholder="unavailable choice" id="error" />
|
||||
</FormItem>
|
||||
</Form.Item>
|
||||
|
||||
<FormItem
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label="Success"
|
||||
hasFeedback
|
||||
validateStatus="success"
|
||||
>
|
||||
<DatePicker style={{ width: '100%' }} />
|
||||
</FormItem>
|
||||
</Form.Item>
|
||||
|
||||
<FormItem
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label="Warning"
|
||||
hasFeedback
|
||||
validateStatus="warning"
|
||||
>
|
||||
<TimePicker style={{ width: '100%' }} />
|
||||
</FormItem>
|
||||
</Form.Item>
|
||||
|
||||
<FormItem
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label="Error"
|
||||
hasFeedback
|
||||
@@ -126,9 +125,9 @@ ReactDOM.render(
|
||||
<Option value="2">Option 2</Option>
|
||||
<Option value="3">Option 3</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
</Form.Item>
|
||||
|
||||
<FormItem
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label="Validating"
|
||||
hasFeedback
|
||||
@@ -136,37 +135,36 @@ ReactDOM.render(
|
||||
help="The information is being validated..."
|
||||
>
|
||||
<Cascader defaultValue={['1']} options={[]} />
|
||||
</FormItem>
|
||||
</Form.Item>
|
||||
|
||||
<FormItem
|
||||
<Form.Item
|
||||
label="inline"
|
||||
{...formItemLayout}
|
||||
style={{ marginBottom: 0 }}
|
||||
>
|
||||
<Col span={11}>
|
||||
<FormItem validateStatus="error" help="Please select the correct date">
|
||||
<DatePicker />
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col span={2}>
|
||||
<span style={{ display: 'inline-block', width: '100%', textAlign: 'center' }}>
|
||||
-
|
||||
</span>
|
||||
</Col>
|
||||
<Col span={11}>
|
||||
<FormItem>
|
||||
<DatePicker />
|
||||
</FormItem>
|
||||
</Col>
|
||||
</FormItem>
|
||||
<Form.Item
|
||||
validateStatus="error"
|
||||
help="Please select the correct date"
|
||||
style={{ display: 'inline-block', width: 'calc(50% - 12px)' }}
|
||||
>
|
||||
<DatePicker />
|
||||
</Form.Item>
|
||||
<span style={{ display: 'inline-block', width: '24px', textAlign: 'center' }}>
|
||||
-
|
||||
</span>
|
||||
<Form.Item style={{ display: 'inline-block', width: 'calc(50% - 12px)' }}>
|
||||
<DatePicker />
|
||||
</Form.Item>
|
||||
</Form.Item>
|
||||
|
||||
<FormItem
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label="Success"
|
||||
hasFeedback
|
||||
validateStatus="success"
|
||||
>
|
||||
<InputNumber style={{ width: '100%' }} />
|
||||
</FormItem>
|
||||
</Form.Item>
|
||||
</Form>,
|
||||
mountNode
|
||||
);
|
||||
|
||||
@@ -16,8 +16,6 @@ title:
|
||||
````jsx
|
||||
import { Form, InputNumber } from 'antd';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
function validatePrimeNumber(number) {
|
||||
if (number === 11) {
|
||||
return {
|
||||
@@ -56,7 +54,7 @@ class RawForm extends React.Component {
|
||||
const tips = 'A prime is a natural number greater than 1 that has no positive divisors other than 1 and itself.';
|
||||
return (
|
||||
<Form>
|
||||
<FormItem
|
||||
<Form.Item
|
||||
{...formItemLayout}
|
||||
label="Prime between 8 & 12"
|
||||
validateStatus={number.validateStatus}
|
||||
@@ -68,7 +66,7 @@ class RawForm extends React.Component {
|
||||
value={number.value}
|
||||
onChange={this.handleNumberChange}
|
||||
/>
|
||||
</FormItem>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
|
||||
99
components/form/docs/tutorial.md
Normal file
99
components/form/docs/tutorial.md
Normal file
@@ -0,0 +1,99 @@
|
||||
# 表单实现原理
|
||||
|
||||
---
|
||||
|
||||
antd 中的 [Form](https://github.com/ant-design/ant-design/blob/master/components/form/index.zh-CN.md) 组件基于 [rc-form](https://github.com/react-component/form) 实现。本文第一部分将介绍 rc-form 库;第二部分再介绍 antd 中的 Form 组件;第三部分将结合表单组件的使用,回顾前两部分的内容。
|
||||
|
||||
---
|
||||
|
||||
### rc-form
|
||||
|
||||
常规收集表单数据并作校验,只需以 store 实时记录表单数据,校验后重绘表单。这样的思路以业务代码为例,就是,以数据模型 model 集成数据处理操作,再通过 setState 将 model 中的实时数据注入组件中,并驱动组件重绘(除了 setState 方法以外,也可以使用 forceUpdate 方法重绘组件,并在 render 阶段重新访问 model 中的实时数据)。
|
||||
|
||||
#### FieldsStore
|
||||
|
||||
在 rc-form 中,上述数据模型的具体实现为 FieldsStore 类。如前所述,FieldsStore 实例与视图层的交互逻辑为,在用户行为驱动字段变更时,即时存储字段的值及校验信息(本文以校验信息代指校验文案和校验状态),继而调用表单组件实例的 forceUpdate 方法强制重绘;在绘制过程中,再从 FieldsStore 实例读取实时数据和校验信息。
|
||||
|
||||
建模方面,FieldsStore 实例以 fields 属性存储表单的实时数据,即由用户行为或开发者显式更新的数据。本文把实时数据已存入 fields 中的字段称为已收集字段;反之,称为未收集字段。以下是 fields\[name\] 中成员属性的意义(name 为字段名,下同)。
|
||||
|
||||
- value 字段的值。
|
||||
- errors 校验文案,数组形式。
|
||||
- validating 校验状态。
|
||||
- dirty 脏值标识。真值时意味着字段的值已作变更,但未作校验。
|
||||
- touched 用户行为标识。通常情况下,真值时意味着用户行为已促使字段的值发生了变更。
|
||||
|
||||
FieldsStore 实例又以 fieldsMeta 属性存储字段的元数据。元数据作为配置项,通常是指定后不再变更的数据,用于操控表单数据转换等行为。元数据通过下文中 getFieldProps, getFieldDecorator 方法的次参 fieldOption 配置。以下是 fieldsMeta\[name\] 中部分成员属性的意义(如不作特殊说明,该成员属性即 fieldOption 中的同名属性)。
|
||||
|
||||
- validate 校验规则和触发事件,用于约定在何种事件下以何种方式校验字段的值,\[{ rules, trigger }\] 形式。通过fieldOption.validate, fieldOption.rules, fieldOption.validateTrigger 配置。
|
||||
- hidden 设置为 true 时,validateFields 将不会校验该字段,需要开发者手动校验,并且,getFieldsValue, getFieldsError 等方法也将无法获取该字段的数据及校验信息等实时数据。适用场景如勾选协议复选框,当其已勾选时,提交按钮才可点击,该复选框的值不会出现在全量表单数据中。本文假定配置了 hidden 为 true 的字段为虚拟隐藏项。
|
||||
- getValueFromEvent(event) 用于从 event 对象中获取字段的值,适用场景如处理 input, radio 等原生组件。特别的,当字段组件输出的首参不是 event 对象时,getValueFromEvent 将对首参进行数据转化,以满足特定的场景,比如由开发者指定具体首参内容的自定义字段组件。
|
||||
- initialValue 字段的初始值。当字段的值未作收集时,初始值用于作为字段的值。
|
||||
- valuePropName 约定字段的值以何种 props 属性注入字段组件中,适用场景如将字段的值以 props.checked 属性注入 radio 组件中。注入字段组件的值数据 props 由 getFieldValuePropValue 方法生成,下同。
|
||||
- getValueProps(value) 用于转化字段的值,输出 props 以注入字段组件中。适用场景如当 get, post 请求的数据结构不同时,且字段组件以 post 请求的数据结构输出字段的值、以 get 请求的数据结构接受字段的值,那就可以使用 getValueProps 将 post 请求的数据结构转换为 get 请求的数据结构。
|
||||
- normalize(newValue, oldValue, values) 用于转化存入 FieldsStore 实例的字段的值。使用案例如[全选按钮](https://codepen.io/afc163/pen/JJVXzG?editors=001)。
|
||||
|
||||
在此基础上,FieldsStore 提供了一些便捷的访问器操作。需要说明的是,rc-form 借助 [lodash](https://github.com/lodash/lodash),支持以嵌套结构定义字段名,即使用 '.', '\[|\]' 作为分割符,如 'a.b' 意味着 a 对象下的 b 属性;'c\[0\]' 意味着 c 数组的首项。本文约定匹配字段指,所有以指定字符串起始或等值的字段列表。为此,FieldsStore 提供 isValidNestedFieldName 用于校验字段名不能作为表单中另一个字段名的成员;flattenRegisteredFields 用于传参数据作扁平化处理;getValidFieldsFullName 用于获取匹配字段列表,但不包含虚拟隐藏项。除此以外,FieldsStore 提供了对实时数据和元数据的读取操作,特别的,部分 api 可用于获取匹配字段的实时数据,参见[文档](https://ant.design/components/form-cn/)。
|
||||
|
||||
#### BaseForm
|
||||
|
||||
与业务 model 不同的是,FieldsStore 仅作为表单实时数据和元数据的存储器,校验数据等方法由 BaseForm 提供。BaseForm既作为 HOC 容器,能为开发者自定义表单组件(下文用自定义表单替代)注入表单操作函数集,通常是 props.form;又用于装饰字段组件或其 props,以收集字段的元数据、通过绑定函数收集或校验字段的实时数据。因此,可以部分认为,BaseForm 即 FieldsStore 和视图层桥接的控制器。其机制为:
|
||||
|
||||
首先,通过 createBaseForm(option, mixins) 创建装饰函数。装饰函数可以为自定义表单包裹上 BaseForm 容器。参数 option 用于配置表单层面的绑定函数、校验文案以及部分字段组件的 props 属性名;mixins 将作为实例方法混入 BaseForm,特别的,createDOMForm 函数即通过这一机制混入了 validateFieldsAndScroll 方法。
|
||||
|
||||
其次,在 BaseForm 的 getInitialState 阶段,将创建 FieldsStore 实例,并初始化 clearedFieldMetaCache 等缓存。这些缓存的意义包含缓存字段组件实例,缓存内置的 ref 引用及绑定函数,缓存渲染状态等。特别的,clearedFieldMetaCache 用于在 ref 引用函数执行时缓存字段的实时数据和元数据,以便于在字段重绘过程中的第两次执行 ref 引用时,恢复 FieldsStore 存储的实时数据和元数据(参见[源码](https://github.com/react-component/form/blob/master/src/createBaseForm.js)中的 saveRef 方法)。不然,元数据的丢失将导致数据校验无法正常工作。
|
||||
|
||||
其次,执行 render 方法,将表单操作函数集通过 props 注入自定义表单。介于此,在自定义表单中,开发者可以获取到表单的实时数据,或者更新表单数据,或者校验表单,以完成特定的处理逻辑。
|
||||
|
||||
其次,由 BaseForm 提供的 getFieldProps 或 getFieldDecorator 实例方法完成字段组件的渲染。以下是 getFieldProps, getFieldDecorator 的意义。
|
||||
|
||||
- getFieldProps(name, fieldOption) 用于为 FieldsStore 实例收集字段的元数据,如经转化后的校验规则等;指定字段组件的 ref 引用函数;为字段组件绑定 onCollect, onCollectValidate 实例方法,以在指定事件触发时收集或校验字段的值;最终将输出注入字段组件的 props,包含全量的元数据和实时数据、以及字段的值。
|
||||
- getFieldDecorator(name, fieldOption) 基于 getFieldProps 方法,直接装饰字段组件,这样就可以操控添加在字段组件上的 ref 引用函数及 props.onChange 等绑定函数。
|
||||
|
||||
其次,当用户行为促使字段的值发生变更时,将执行 BaseForm 实例的 onCollect, onCollectValidate 方法,以收集或校验该字段的实时数据,并重绘表单。其中,rc-form 中的数据校验通过 [async-validate](https://github.com/yiminghe/async-validator) 库实现,具体实现为 BaseForm 实例的 validateFieldsInternal 方法。校验字段时,默认将沿用上一次的校验信息;当设置 force 为 true 时,将强制重新校验。
|
||||
|
||||
详细的工作流程参见下方的时序图:
|
||||
<img class="preview-img no-padding" src="http://xzfyu.com/2018/11/04/ant%20design/antd-Form%20%E7%BB%84%E4%BB%B6/rc-form%E6%97%B6%E5%BA%8F%E5%9B%BE.png">
|
||||
|
||||
### Form 表单
|
||||
|
||||
#### 表单
|
||||
|
||||
Form 组件本身并不承载逻辑,而是通过 props.className, props.prefixCls, props.layout, props.hideRequiredMark, props.onSubmit 设定注入 form 原生节点的样式类及绑定函数,以影响表单内部节点渲染时的样式。同时,Form 组件将为子组件传入 context.vertical 以区分是水平布局,还是垂直布局。
|
||||
|
||||
#### 表单域
|
||||
|
||||
FormItem 组件用于设定表单项的布局。如同受控组件和非受控组件,FormItem 组件提供两种使用方式:其一,当未设定校验信息相关的 props 属性时,FormItem 组件将自动根据内部字段组件实例的状况渲染校验文案及校验状态;其二,当设定校验信息相关的 props 属性时,FormItem 组件将根据开发者传入的 props 渲染校验文案及校验状态。在第一种使用方式下,FormItem 组件只可以包含一个字段组件;在第二种使用方式下,FormItem 组件中可以包含多个字段组件,布局也更为灵活。这里说的相关 props 属性包含:校验文案 help, 校验状态 validateStatus(用于绘制反馈图标), 必填标识 required, 字段名 id(影响点击 label 时聚焦哪个字段元素)。
|
||||
|
||||
那么,FormItem 又是怎样自动收集字段组件的校验数据呢?因为在 BaseForm 组件提供的 getFieldProp 方法,字段名、元数据和实时数据都将作为特殊的 props 属性传入到字段组件中,所以作为字段组件容器的 FormItem,就可以通过这些特殊的 props 属性判断子组件实例是不是一个字段组件实例。当其为字段组件实例时,进一步收集实时的校验信息,从校验规则中获取是否必填标识,以完成表单域的渲染。
|
||||
|
||||
此外,FormItem 可以使用 props.labelCol, props.wrapperCol 属性栅格化布局标签组件和字段组件,其实现借助于 antd 提供的 [Row, Col 组件](https://ant.design/components/grid-cn/)。当点击标签 label 时,FormItem 提供的绑定函数也能自动为字段组件获得焦点。这里不再多加介绍。
|
||||
|
||||
### 使用与回顾
|
||||
|
||||
#### 创建 HOC 容器
|
||||
|
||||
结合上文,antd 使用 Form.create(options)(CustomizedForm) 形式为用户自定义表单包裹上 BaseForm 高阶组件,以此植入 props.form 表单操作函数集。
|
||||
|
||||
高阶组件影响对自定义表单设置 ref 引用。默认可使用 BaseForm 实例的 refs.wrappedComponent 属性访问 CustomizedForm 实例,其次也可以通过 props.wrappedComponentRef 为 CustomizedForm 实例配置 ref 引用(参考案例 —— 弹出层中的新建表单)。当自定义表单可切换或者需要对外交互时,设置 ref 引用通常是不可避免的。
|
||||
|
||||
高阶组件影响 props 传递。antd 既支持使用 options.mapPropsToFields 将 BaseForm 实例获得的 props 转化成表单的实时数据(需要结合 Form.createFormField 方法),又支持在 CustomizedForm 实例中调用 props.form.setFields 方法更新实时数据。当 options.mapPropsToFields, options.onFieldsChange 方法结合使用时,可用于完成自定义表单和上层组件、或者 view 层和 store 层的交互(参考案例 —— 表单数据存储于上层组件)。
|
||||
|
||||
一般认为,对整张表单的控制,需要借助于 Form.create 方法的首参 options 配置实现。
|
||||
|
||||
#### 操作函数集
|
||||
|
||||
通常情况下,CustomizedForm 实例可通过 props.form 获取到表单操作函数集。当然,开发者也可以通过 options.formPropName 指定操作函数集的 props 属性名。
|
||||
|
||||
操作函数集包含 getFieldProps, getFieldDecorator, getFieldInstance, setFields, setFieldsValue, setFieldsInitialValue, resetFields, validateFields, getFieldsValue, getFieldValue, getFieldsError, getFieldError, isFieldsValidating, isFieldValidating, isFieldsTouched, isFieldTouched 方法,即用于装饰字段组件(或其 props)、获取字段组件实例、设置或获取实时数据、重置或校验字段。
|
||||
|
||||
如上文所说,getFieldProps, getFieldDecorator 方法即用于自动为字段组件绑定监听函数,这样就可以在指定事件触发时,收集和校验字段的值。同时,可以通过这两个方法将视图中未加显示的字段存入 FieldsStore 中(这时,可以将 FieldsStore 视为一个内置于表单组件的状态管理器)。比如在包含其他选项的单选框场景中,就可以使用 getFieldDecorator 创建虚拟字段,通过绑定函数将单选框和输入框的值赋值到该虚拟字段中,并使用该虚拟字段的校验信息绘制 FormItem。参考案例 —— 动态增减表单项。
|
||||
|
||||
上述单选框场景,也可以使用自定义字段组件 CustomizedField 实现。参考案例 —— 自定义字段组件。当使用自定义字段组件时,通过 getFieldInstance 获取 CustomizedField 的实例可能是必不可少的,这样可以把略显复杂的数据校验方法集成在 CustomizedField 中。此外,在字段组件中,既可以通过 props.value 属性获得字段的值,也可以通过 props\['data-__meta'\], props\['data-__field'\] 获得字段的全量元数据和实时数据。
|
||||
|
||||
在 CustomizedForm 中,使用 getFieldValue 可以取得字段的实时更新值,这样就能根据指定字段的值控制另一个字段的显隐。此外,通过在字段组件的 onChange 绑定函数中调用 setFieldValue,也能对另一个字段组件加以赋值,这样就可以实现表单的联动效果,参考案例 —— 表单联动。若在字段组件的 onChange 绑定函数中调用 validateFields 方法,就可以实现关联字段的校验,比如表单中存在设置最大最小值的两个输入框,参考案例 —— 动态校验规则。
|
||||
|
||||
使用 getFieldError, isFieldValidating 获取到的校验信息可用于直接绘制 FormItem,这样就能更加细微地操控 FormItem 下字段组件的布局,比如放置多个字段组件。当然,对于多个字段组件公用校验信息的场景,也可以使用包含多个字段的 CustomizedField 实现。isFieldTouched 可判断用户是否对字段组件有触发数据收集和校验的行为,参考案例 —— 水平登录栏。介于 BaseForm 默认在 onChange 事件中收集并校验字段的值,在这种情形下,也可以通过 isFieldTouched 判断字段的值是否已作更新,而不需要在 CustomizedForm 中设置特殊的更新标识。
|
||||
|
||||
#### 其他
|
||||
|
||||
当不使用 Form.create 为字段组件自动绑定校验方法时,可以使用 Form, FormItem 组件设定表单的布局、校验信息的绘制,参考案例 —— 表单布局、自行处理表单数据、自定义校验。
|
||||
@@ -84,8 +84,7 @@ If the form has been decorated by `Form.create` then it has `this.props.form` pr
|
||||
| isFieldTouched | Check whether a field is touched by `getFieldDecorator`'s `options.trigger` event | (name: string) => boolean |
|
||||
| isFieldValidating | Check if the specified field is being validated. | Function(name) |
|
||||
| resetFields | Reset the specified fields' value(to `initialValue`) and status. If you don't specify a parameter, all the fields will be reset. | Function(\[names: string\[]]) |
|
||||
| setFields | Set the value and error of a field. [Code Sample](https://github.com/react-component/form/blob/3b9959b57ab30b41d8890ff30c79a7e7c383cad3/examples/server-validate.js#L74-L79) | Function({ [fieldName]: { value: any, errors: [Error] } }) |
|
||||
| setFields | Set value and error state of fields | ({<br /> \[fieldName\]: {value: any, errors: \[Error\] }<br />}) => void |
|
||||
| setFields | Set value and error state of fields. [Code Sample](https://github.com/react-component/form/blob/3b9959b57ab30b41d8890ff30c79a7e7c383cad3/examples/server-validate.js#L74-L79) | ({<br /> \[fieldName\]: {value: any, errors: \[Error\] }<br />}) => void |
|
||||
| setFieldsValue | Set the value of a field. (Note: please don't use it in `componentWillReceiveProps`, otherwise, it will cause an endless loop, [reason](https://github.com/ant-design/ant-design/issues/2985)) | ({ \[fieldName\]: value }) => void |
|
||||
| validateFields | Validate the specified fields and get theirs values and errors. If you don't specify the parameter of fieldNames, you will validate all fields. | (<br /> \[fieldNames: string\[]],<br /> \[options: object\],<br /> callback(errors, values)<br />) => void |
|
||||
| validateFieldsAndScroll | This function is similar to `validateFields`, but after validation, if the target field is not in visible area of form, form will be automatically scrolled to the target field area. | same as `validateFields` |
|
||||
|
||||
@@ -74,12 +74,6 @@ input[type='checkbox'] {
|
||||
margin-bottom: @form-item-margin-bottom;
|
||||
vertical-align: top;
|
||||
|
||||
// nested FormItem
|
||||
&-control > &:last-child,
|
||||
& [class^='@{ant-prefix}-col-'] > &:only-child {
|
||||
margin-bottom: -@form-item-margin-bottom;
|
||||
}
|
||||
|
||||
&-control {
|
||||
line-height: @form-component-max-height - 0.0001px; // https://github.com/ant-design/ant-design/issues/8220
|
||||
position: relative;
|
||||
@@ -455,6 +449,9 @@ form {
|
||||
.@{ant-prefix}-select {
|
||||
&-selection {
|
||||
border-color: @warning-color;
|
||||
&:hover {
|
||||
border-color: @warning-color;
|
||||
}
|
||||
}
|
||||
&-open .@{ant-prefix}-select-selection,
|
||||
&-focused .@{ant-prefix}-select-selection {
|
||||
@@ -501,6 +498,9 @@ form {
|
||||
.@{ant-prefix}-select {
|
||||
&-selection {
|
||||
border-color: @error-color;
|
||||
&:hover {
|
||||
border-color: @error-color;
|
||||
}
|
||||
}
|
||||
&-open .@{ant-prefix}-select-selection,
|
||||
&-focused .@{ant-prefix}-select-selection {
|
||||
|
||||
@@ -25,6 +25,24 @@
|
||||
.active(@border-color);
|
||||
}
|
||||
|
||||
// Input prefix
|
||||
.@{ant-prefix}-input-affix-wrapper {
|
||||
.@{ant-prefix}-input {
|
||||
&,
|
||||
&:hover {
|
||||
border-color: @border-color;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
.active(@border-color);
|
||||
}
|
||||
}
|
||||
|
||||
&:hover .@{ant-prefix}-input:not(.@{ant-prefix}-input-disabled) {
|
||||
border-color: @border-color;
|
||||
}
|
||||
}
|
||||
|
||||
.@{ant-prefix}-input-prefix {
|
||||
color: @text-color;
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ export default class Row extends React.Component<RowProps, RowState> {
|
||||
getGutter(): number | undefined {
|
||||
const { gutter } = this.props;
|
||||
if (typeof gutter === 'object') {
|
||||
for (let i = 0; i <= responsiveArray.length; i++) {
|
||||
for (let i = 0; i < responsiveArray.length; i++) {
|
||||
const breakpoint: Breakpoint = responsiveArray[i];
|
||||
if (this.state.screens[breakpoint] && gutter[breakpoint] !== undefined) {
|
||||
return gutter[breakpoint];
|
||||
|
||||
@@ -138,7 +138,7 @@ const Icon: IconComponent<IconProps> = props => {
|
||||
);
|
||||
}
|
||||
computedType = withThemeSuffix(
|
||||
removeTypeTheme(alias(type)),
|
||||
removeTypeTheme(alias(computedType)),
|
||||
dangerousTheme || theme || defaultTheme,
|
||||
);
|
||||
innerNode = (
|
||||
|
||||
@@ -267,28 +267,26 @@
|
||||
&-wrap,
|
||||
> .@{inputClass} {
|
||||
&:not(:first-child):not(:last-child) {
|
||||
border-right-width: 1px;
|
||||
border-right-color: transparent;
|
||||
border-right-width: @border-width-base;
|
||||
&:hover {
|
||||
.hover();
|
||||
z-index: 1;
|
||||
}
|
||||
&:focus {
|
||||
.active();
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
& > * {
|
||||
border-radius: 0;
|
||||
border-right-width: 0;
|
||||
vertical-align: top; // https://github.com/ant-design/ant-design-pro/issues/139
|
||||
float: none;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/11863
|
||||
& > span:not(:last-child) > .@{inputClass} {
|
||||
border-right-width: 0;
|
||||
& > *:not(:last-child) {
|
||||
border-right-width: @border-width-base;
|
||||
margin-right: -@border-width-base;
|
||||
}
|
||||
|
||||
// Undo float for .ant-input-group .ant-input
|
||||
@@ -304,13 +302,12 @@
|
||||
& > .@{ant-prefix}-mention-wrapper .@{ant-prefix}-mention-editor,
|
||||
& > .@{ant-prefix}-time-picker .@{ant-prefix}-time-picker-input {
|
||||
border-radius: 0;
|
||||
border-right-width: 1px;
|
||||
border-right-color: transparent;
|
||||
border-right-width: @border-width-base;
|
||||
&:hover {
|
||||
.hover();
|
||||
z-index: 1;
|
||||
}
|
||||
&:focus {
|
||||
.active();
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,17 +332,7 @@
|
||||
& > .@{ant-prefix}-time-picker:last-child .@{ant-prefix}-time-picker-input {
|
||||
border-top-right-radius: @border-radius-base;
|
||||
border-bottom-right-radius: @border-radius-base;
|
||||
border-right-width: 1px;
|
||||
border-right-color: @input-border-color;
|
||||
&:hover {
|
||||
.hover();
|
||||
}
|
||||
&:focus {
|
||||
.active();
|
||||
.@{ant-prefix}-cascader-input {
|
||||
.active();
|
||||
}
|
||||
}
|
||||
border-right-width: @border-width-base;
|
||||
}
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/12493
|
||||
@@ -365,13 +352,14 @@
|
||||
}
|
||||
|
||||
.@{inputClass} {
|
||||
position: static;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.@{inputClass}-prefix,
|
||||
.@{inputClass}-suffix {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
z-index: 2;
|
||||
transform: translateY(-50%);
|
||||
line-height: 0;
|
||||
color: @input-color;
|
||||
|
||||
@@ -90,7 +90,7 @@ The sidebar.
|
||||
| breakpoint | [breakpoints](/components/grid#api) of the responsive layout | Enum { 'xs', 'sm', 'md', 'lg', 'xl', 'xxl' } | - |
|
||||
| className | container className | string | - |
|
||||
| collapsed | to set the current status | boolean | - |
|
||||
| collapsedWidth | width of the collapsed sidebar, by setting to `0` a special trigger will appear | number | 64 |
|
||||
| collapsedWidth | width of the collapsed sidebar, by setting to `0` a special trigger will appear | number | 80 |
|
||||
| collapsible | whether can be collapsed | boolean | false |
|
||||
| defaultCollapsed | to set the initial status | boolean | false |
|
||||
| reverseArrow | reverse direction of arrow, for a sider that expands from the right | boolean | false |
|
||||
|
||||
@@ -91,7 +91,7 @@ title: Layout
|
||||
| breakpoint | 触发响应式布局的[断点](/components/grid#api) | Enum { 'xs', 'sm', 'md', 'lg', 'xl', 'xxl' } | - |
|
||||
| className | 容器 className | string | - |
|
||||
| collapsed | 当前收起状态 | boolean | - |
|
||||
| collapsedWidth | 收缩宽度,设置为 0 会出现特殊 trigger | number | 64 |
|
||||
| collapsedWidth | 收缩宽度,设置为 0 会出现特殊 trigger | number | 80 |
|
||||
| collapsible | 是否可收起 | boolean | false |
|
||||
| defaultCollapsed | 是否默认收起 | boolean | false |
|
||||
| reverseArrow | 翻转折叠提示箭头的方向,当 Sider 在右边时可以使用 | boolean | false |
|
||||
|
||||
@@ -35,7 +35,11 @@ class Basic extends React.Component<BasicProps, any> {
|
||||
}
|
||||
}
|
||||
|
||||
class BasicLayout extends React.Component<BasicProps, any> {
|
||||
interface BasicLayoutState {
|
||||
siders: string[];
|
||||
}
|
||||
|
||||
class BasicLayout extends React.Component<BasicProps, BasicLayoutState> {
|
||||
static childContextTypes = {
|
||||
siderHook: PropTypes.object,
|
||||
};
|
||||
@@ -45,14 +49,14 @@ class BasicLayout extends React.Component<BasicProps, any> {
|
||||
return {
|
||||
siderHook: {
|
||||
addSider: (id: string) => {
|
||||
this.setState({
|
||||
siders: [...this.state.siders, id],
|
||||
});
|
||||
this.setState(state => ({
|
||||
siders: [...state.siders, id],
|
||||
}));
|
||||
},
|
||||
removeSider: (id: string) => {
|
||||
this.setState({
|
||||
siders: this.state.siders.filter(currentId => currentId !== id),
|
||||
});
|
||||
this.setState(state => ({
|
||||
siders: state.siders.filter(currentId => currentId !== id),
|
||||
}));
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -8,7 +8,9 @@ export interface LocaleReceiverProps {
|
||||
children: (locale: object, localeCode?: string) => React.ReactElement<any>;
|
||||
}
|
||||
|
||||
interface LocaleInterface { [key: string]: any }
|
||||
interface LocaleInterface {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export interface LocaleReceiverContext {
|
||||
antLocale?: LocaleInterface;
|
||||
@@ -27,7 +29,8 @@ export default class LocaleReceiver extends React.Component<LocaleReceiverProps>
|
||||
|
||||
getLocale() {
|
||||
const { componentName, defaultLocale } = this.props;
|
||||
const locale: object | Function = defaultLocale || (defaultLocaleData as LocaleInterface)[componentName || 'global'];
|
||||
const locale: object | Function =
|
||||
defaultLocale || (defaultLocaleData as LocaleInterface)[componentName || 'global'];
|
||||
const { antLocale } = this.context;
|
||||
const localeFromContext = componentName && antLocale ? antLocale[componentName] : {};
|
||||
return {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -20,7 +20,7 @@ export interface Locale {
|
||||
|
||||
export interface LocaleProviderProps {
|
||||
locale: Locale;
|
||||
children?: React.ReactElement<any>;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
function setMomentLocale(locale: Locale) {
|
||||
|
||||
@@ -47,7 +47,7 @@ When need to mention someone or something.
|
||||
| value | core state of mention | ContentState | null |
|
||||
| onBlur | Callback function called when mention component blur | function(e) | null |
|
||||
| onChange | Callback function called when content of input changes | function(contentState: ContentState) | null |
|
||||
| onFocus | Callback function called when mention component get focus | functione) | null |
|
||||
| onFocus | Callback function called when mention component get focus | function | null |
|
||||
| onSearchChange | Callback function called when search content changes | function(value:string, trigger: string) | \[] |
|
||||
| onSelect | Callback function called when select from suggestions | function(suggestion: string, data?: any) | null |
|
||||
|
||||
|
||||
@@ -103,6 +103,7 @@ class Mention extends React.Component<MentionProps, MentionState> {
|
||||
this.props.onFocus(ev);
|
||||
}
|
||||
};
|
||||
|
||||
onBlur = (ev: React.FocusEvent<HTMLElement>) => {
|
||||
this.setState({
|
||||
focus: false,
|
||||
@@ -111,12 +112,15 @@ class Mention extends React.Component<MentionProps, MentionState> {
|
||||
this.props.onBlur(ev);
|
||||
}
|
||||
};
|
||||
|
||||
focus = () => {
|
||||
this.mentionEle._editor.focusEditor();
|
||||
};
|
||||
|
||||
mentionRef = (ele: any) => {
|
||||
this.mentionEle = ele;
|
||||
};
|
||||
|
||||
render() {
|
||||
const { className = '', prefixCls, loading, placement } = this.props;
|
||||
const { suggestions, focus } = this.state;
|
||||
@@ -124,7 +128,6 @@ class Mention extends React.Component<MentionProps, MentionState> {
|
||||
[`${prefixCls}-active`]: focus,
|
||||
[`${prefixCls}-placement-top`]: placement === 'top',
|
||||
});
|
||||
|
||||
const notFoundContent = loading ? <Icon type="loading" /> : this.props.notFoundContent;
|
||||
|
||||
return (
|
||||
|
||||
@@ -21,12 +21,15 @@ class MenuItem extends React.Component<MenuItemProps, any> {
|
||||
static isMenuItem = 1;
|
||||
context: any;
|
||||
private menuItem: any;
|
||||
|
||||
onKeyDown = (e: React.MouseEvent<HTMLElement>) => {
|
||||
this.menuItem.onKeyDown(e);
|
||||
};
|
||||
|
||||
saveMenuItem = (menuItem: any) => {
|
||||
this.menuItem = menuItem;
|
||||
};
|
||||
|
||||
render() {
|
||||
const { inlineCollapsed } = this.context;
|
||||
const { level, children, rootPrefixCls } = this.props;
|
||||
|
||||
@@ -11,12 +11,15 @@ class SubMenu extends React.Component<any, any> {
|
||||
static isSubMenu = 1;
|
||||
context: any;
|
||||
private subMenu: any;
|
||||
|
||||
onKeyDown = (e: React.MouseEvent<HTMLElement>) => {
|
||||
this.subMenu.onKeyDown(e);
|
||||
};
|
||||
|
||||
saveSubMenu = (subMenu: any) => {
|
||||
this.subMenu = subMenu;
|
||||
};
|
||||
|
||||
render() {
|
||||
const { rootPrefixCls, className } = this.props;
|
||||
const theme = this.context.antdMenuTheme;
|
||||
|
||||
@@ -78,9 +78,11 @@ export default class Menu extends React.Component<MenuProps, MenuState> {
|
||||
siderCollapsed: PropTypes.bool,
|
||||
collapsedWidth: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
||||
};
|
||||
|
||||
context: any;
|
||||
switchingModeFromInline: boolean;
|
||||
inlineOpenKeys: string[] = [];
|
||||
|
||||
constructor(props: MenuProps) {
|
||||
super(props);
|
||||
|
||||
@@ -106,20 +108,24 @@ export default class Menu extends React.Component<MenuProps, MenuState> {
|
||||
openKeys: openKeys || [],
|
||||
};
|
||||
}
|
||||
|
||||
getChildContext() {
|
||||
return {
|
||||
inlineCollapsed: this.getInlineCollapsed(),
|
||||
antdMenuTheme: this.props.theme,
|
||||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps: MenuProps, nextContext: SiderContext) {
|
||||
if (this.props.mode === 'inline' && nextProps.mode !== 'inline') {
|
||||
this.switchingModeFromInline = true;
|
||||
}
|
||||
|
||||
if ('openKeys' in nextProps) {
|
||||
this.setState({ openKeys: nextProps.openKeys! });
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
(nextProps.inlineCollapsed && !this.props.inlineCollapsed) ||
|
||||
(nextContext.siderCollapsed && !this.context.siderCollapsed)
|
||||
@@ -128,6 +134,7 @@ export default class Menu extends React.Component<MenuProps, MenuState> {
|
||||
this.inlineOpenKeys = this.state.openKeys;
|
||||
this.setState({ openKeys: [] });
|
||||
}
|
||||
|
||||
if (
|
||||
(!nextProps.inlineCollapsed && this.props.inlineCollapsed) ||
|
||||
(!nextContext.siderCollapsed && this.context.siderCollapsed)
|
||||
@@ -136,12 +143,14 @@ export default class Menu extends React.Component<MenuProps, MenuState> {
|
||||
this.inlineOpenKeys = [];
|
||||
}
|
||||
}
|
||||
|
||||
restoreModeVerticalFromInline() {
|
||||
if (this.switchingModeFromInline) {
|
||||
this.switchingModeFromInline = false;
|
||||
this.setState({});
|
||||
}
|
||||
}
|
||||
|
||||
// Restore vertical mode when menu is collapsed responsively when mounted
|
||||
// https://github.com/ant-design/ant-design/issues/13104
|
||||
// TODO: not a perfect solution, looking a new way to avoid setting switchingModeFromInline in this situation
|
||||
@@ -152,6 +161,7 @@ export default class Menu extends React.Component<MenuProps, MenuState> {
|
||||
onMouseEnter(e);
|
||||
}
|
||||
};
|
||||
|
||||
handleTransitionEnd = (e: TransitionEvent) => {
|
||||
// when inlineCollapsed menu width animation finished
|
||||
// https://github.com/ant-design/ant-design/issues/12864
|
||||
@@ -164,6 +174,7 @@ export default class Menu extends React.Component<MenuProps, MenuState> {
|
||||
this.restoreModeVerticalFromInline();
|
||||
}
|
||||
};
|
||||
|
||||
handleClick = (e: ClickParam) => {
|
||||
this.handleOpenChange([]);
|
||||
|
||||
@@ -172,6 +183,7 @@ export default class Menu extends React.Component<MenuProps, MenuState> {
|
||||
onClick(e);
|
||||
}
|
||||
};
|
||||
|
||||
handleOpenChange = (openKeys: string[]) => {
|
||||
this.setOpenKeys(openKeys);
|
||||
|
||||
@@ -180,11 +192,13 @@ export default class Menu extends React.Component<MenuProps, MenuState> {
|
||||
onOpenChange(openKeys);
|
||||
}
|
||||
};
|
||||
|
||||
setOpenKeys(openKeys: string[]) {
|
||||
if (!('openKeys' in this.props)) {
|
||||
this.setState({ openKeys });
|
||||
}
|
||||
}
|
||||
|
||||
getRealMenuMode() {
|
||||
const inlineCollapsed = this.getInlineCollapsed();
|
||||
if (this.switchingModeFromInline && inlineCollapsed) {
|
||||
@@ -193,6 +207,7 @@ export default class Menu extends React.Component<MenuProps, MenuState> {
|
||||
const { mode } = this.props;
|
||||
return inlineCollapsed ? 'vertical' : mode;
|
||||
}
|
||||
|
||||
getInlineCollapsed() {
|
||||
const { inlineCollapsed } = this.props;
|
||||
if (this.context.siderCollapsed !== undefined) {
|
||||
@@ -200,30 +215,24 @@ export default class Menu extends React.Component<MenuProps, MenuState> {
|
||||
}
|
||||
return inlineCollapsed;
|
||||
}
|
||||
|
||||
getMenuOpenAnimation(menuMode: MenuMode) {
|
||||
const { openAnimation, openTransitionName } = this.props;
|
||||
let menuOpenAnimation = openAnimation || openTransitionName;
|
||||
if (openAnimation === undefined && openTransitionName === undefined) {
|
||||
switch (menuMode) {
|
||||
case 'horizontal':
|
||||
menuOpenAnimation = 'slide-up';
|
||||
break;
|
||||
case 'vertical':
|
||||
case 'vertical-left':
|
||||
case 'vertical-right':
|
||||
// When mode switch from inline
|
||||
// submenu should hide without animation
|
||||
if (this.switchingModeFromInline) {
|
||||
menuOpenAnimation = '';
|
||||
this.switchingModeFromInline = false;
|
||||
} else {
|
||||
menuOpenAnimation = 'zoom-big';
|
||||
}
|
||||
break;
|
||||
case 'inline':
|
||||
menuOpenAnimation = animation;
|
||||
break;
|
||||
default:
|
||||
if (menuMode === 'horizontal') {
|
||||
menuOpenAnimation = 'slide-up';
|
||||
} else if (menuMode === 'inline') {
|
||||
menuOpenAnimation = animation;
|
||||
} else {
|
||||
// When mode switch from inline
|
||||
// submenu should hide without animation
|
||||
if (this.switchingModeFromInline) {
|
||||
menuOpenAnimation = '';
|
||||
this.switchingModeFromInline = false;
|
||||
} else {
|
||||
menuOpenAnimation = 'zoom-big';
|
||||
}
|
||||
}
|
||||
}
|
||||
return menuOpenAnimation;
|
||||
|
||||
@@ -136,7 +136,7 @@ export default function confirm(config: ModalFuncProps) {
|
||||
if (unmountResult && div.parentNode) {
|
||||
div.parentNode.removeChild(div);
|
||||
}
|
||||
const triggerCancel = args && args.length && args.some(param => param && param.triggerCancel);
|
||||
const triggerCancel = args.some(param => param && param.triggerCancel);
|
||||
if (config.onCancel && triggerCancel) {
|
||||
config.onCancel(...args);
|
||||
}
|
||||
|
||||
@@ -100,10 +100,6 @@ export default class Pagination extends React.Component<PaginationProps, {}> {
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<LocaleReceiver componentName="Pagination">
|
||||
{this.renderPagination}
|
||||
</LocaleReceiver>
|
||||
);
|
||||
return <LocaleReceiver componentName="Pagination">{this.renderPagination}</LocaleReceiver>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,6 +101,7 @@
|
||||
|
||||
&-arrow {
|
||||
background: @popover-bg;
|
||||
background-color: inherit;
|
||||
width: sqrt(@popover-arrow-width * @popover-arrow-width * 2);
|
||||
height: sqrt(@popover-arrow-width * @popover-arrow-width * 2);
|
||||
transform: rotate(45deg);
|
||||
|
||||
@@ -89,6 +89,33 @@ exports[`Progress render negetive successPercent 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Progress render normal progress 1`] = `
|
||||
<div
|
||||
class="ant-progress ant-progress-line ant-progress-status-normal ant-progress-show-info ant-progress-default"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
class="ant-progress-outer"
|
||||
>
|
||||
<div
|
||||
class="ant-progress-inner"
|
||||
>
|
||||
<div
|
||||
class="ant-progress-bg"
|
||||
style="width: 0%; height: 8px; border-radius: 100px;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<span
|
||||
class="ant-progress-text"
|
||||
title="0%"
|
||||
>
|
||||
0%
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Progress render out-of-range progress 1`] = `
|
||||
<div
|
||||
class="ant-progress ant-progress-line ant-progress-status-success ant-progress-show-info ant-progress-default"
|
||||
|
||||
@@ -46,4 +46,9 @@ describe('Progress', () => {
|
||||
const wrapper = mount(<Progress type="circle" percent={50} strokeColor="red" />);
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('render normal progress', () => {
|
||||
const wrapper = mount(<Progress status="normal" />);
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -22,7 +22,7 @@ If it will take a long time to complete an operation, you can use `Progress` to
|
||||
| gapPosition `(type=circle)` | the gap position, options: `top` `bottom` `left` `right` | string | `top` |
|
||||
| percent | to set the completion percentage | number | 0 |
|
||||
| showInfo | whether to display the progress value and the status icon | boolean | true |
|
||||
| status | to set the status of the Progress, options: `success` `exception` `active` | string | - |
|
||||
| status | to set the status of the Progress, options: `success` `exception` `active` `normal` | string | - |
|
||||
| strokeWidth `(type=line)` | to set the width of the progress bar, unit: `px` | number | 10 |
|
||||
| strokeWidth `(type=circle)` | to set the width of the circular progress bar, unit: percentage of the canvas width | number | 6 |
|
||||
| strokeLinecap | to set the style of the progress linecap | Enum{ 'round', 'square' } | `round` |
|
||||
|
||||
@@ -23,7 +23,7 @@ title: Progress
|
||||
| gapPosition `(type=circle)` | 圆形进度条缺口位置 | Enum{ 'top', 'bottom', 'left', 'right' } | `top` |
|
||||
| percent | 百分比 | number | 0 |
|
||||
| showInfo | 是否显示进度数值或状态图标 | boolean | true |
|
||||
| status | 状态,可选:`success` `exception` `active` | string | - |
|
||||
| status | 状态,可选:`success` `exception` `active` `normal` | string | - |
|
||||
| strokeWidth `(type=line)` | 进度条线的宽度,单位 px | number | 10 |
|
||||
| strokeWidth `(type=circle)` | 圆形进度条线的宽度,单位是进度条画布宽度的百分比 | number | 6 |
|
||||
| strokeLinecap | | Enum{ 'round', 'square' } | `round` |
|
||||
|
||||
@@ -20,7 +20,7 @@ export interface ProgressProps {
|
||||
percent?: number;
|
||||
successPercent?: number;
|
||||
format?: (percent?: number, successPercent?: number) => React.ReactNode;
|
||||
status?: 'success' | 'active' | 'exception';
|
||||
status?: 'success' | 'active' | 'exception' | 'normal';
|
||||
showInfo?: boolean;
|
||||
strokeWidth?: number;
|
||||
strokeLinecap?: string;
|
||||
|
||||
@@ -2,6 +2,7 @@ import * as React from 'react';
|
||||
import * as PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
import shallowEqual from 'shallowequal';
|
||||
import { polyfill } from 'react-lifecycles-compat';
|
||||
import Radio from './radio';
|
||||
import {
|
||||
RadioGroupProps,
|
||||
@@ -22,7 +23,7 @@ function getCheckedValue(children: React.ReactNode) {
|
||||
return matched ? { value } : undefined;
|
||||
}
|
||||
|
||||
export default class RadioGroup extends React.Component<RadioGroupProps, RadioGroupState> {
|
||||
class RadioGroup extends React.Component<RadioGroupProps, RadioGroupState> {
|
||||
static defaultProps = {
|
||||
disabled: false,
|
||||
prefixCls: 'ant-radio',
|
||||
@@ -33,6 +34,22 @@ export default class RadioGroup extends React.Component<RadioGroupProps, RadioGr
|
||||
radioGroup: PropTypes.any,
|
||||
};
|
||||
|
||||
static getDerivedStateFromProps(nextProps: RadioGroupProps) {
|
||||
if ('value' in nextProps) {
|
||||
return {
|
||||
value: nextProps.value,
|
||||
};
|
||||
} else {
|
||||
const checkedValue = getCheckedValue(nextProps.children);
|
||||
if (checkedValue) {
|
||||
return {
|
||||
value: checkedValue.value,
|
||||
};
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
constructor(props: RadioGroupProps) {
|
||||
super(props);
|
||||
let value;
|
||||
@@ -60,21 +77,6 @@ export default class RadioGroup extends React.Component<RadioGroupProps, RadioGr
|
||||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps: RadioGroupProps) {
|
||||
if ('value' in nextProps) {
|
||||
this.setState({
|
||||
value: nextProps.value,
|
||||
});
|
||||
} else {
|
||||
const checkedValue = getCheckedValue(nextProps.children);
|
||||
if (checkedValue) {
|
||||
this.setState({
|
||||
value: checkedValue.value,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps: RadioGroupProps, nextState: RadioGroupState) {
|
||||
return !shallowEqual(this.props, nextProps) || !shallowEqual(this.state, nextState);
|
||||
}
|
||||
@@ -157,3 +159,6 @@ export default class RadioGroup extends React.Component<RadioGroupProps, RadioGr
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
polyfill(RadioGroup);
|
||||
export default RadioGroup;
|
||||
|
||||
@@ -116,6 +116,7 @@
|
||||
.@{radio-inner-prefix-cls} {
|
||||
border-color: @border-color-base !important;
|
||||
background-color: @input-disabled-bg;
|
||||
cursor: not-allowed;
|
||||
&:after {
|
||||
background-color: #ccc;
|
||||
}
|
||||
|
||||
@@ -355,6 +355,55 @@ exports[`renders ./components/select/demo/custom-dropdown-menu.md correctly 1`]
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/select/demo/hide-selected.md correctly 1`] = `
|
||||
<div
|
||||
class="ant-select ant-select-enabled"
|
||||
style="width:100%"
|
||||
>
|
||||
<div
|
||||
aria-autocomplete="list"
|
||||
aria-controls="test-uuid"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
class="ant-select-selection
|
||||
ant-select-selection--multiple"
|
||||
role="combobox"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selection__rendered"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selection__placeholder"
|
||||
style="display:block;user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
>
|
||||
Inserted are removed
|
||||
</div>
|
||||
<ul>
|
||||
<li
|
||||
class="ant-select-search ant-select-search--inline"
|
||||
>
|
||||
<div
|
||||
class="ant-select-search__field__wrap"
|
||||
>
|
||||
<input
|
||||
autocomplete="off"
|
||||
class="ant-select-search__field"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
class="ant-select-search__field__mirror"
|
||||
>
|
||||
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/select/demo/label-in-value.md correctly 1`] = `
|
||||
<div
|
||||
class="ant-select ant-select-enabled"
|
||||
|
||||
52
components/select/demo/hide-selected.md
Normal file
52
components/select/demo/hide-selected.md
Normal file
@@ -0,0 +1,52 @@
|
||||
---
|
||||
order: 22
|
||||
title:
|
||||
zh-CN: 隐藏已选择选项
|
||||
en-US: Hide Already Selected
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
隐藏下拉列表中已选择的选项。
|
||||
|
||||
## en-US
|
||||
|
||||
Hide already selected options in the dropdown.
|
||||
|
||||
````jsx
|
||||
import { Select } from 'antd';
|
||||
|
||||
const OPTIONS = ['Apples', 'Nails', 'Bananas', 'Helicopters'];
|
||||
|
||||
class SelectWithHiddenSelectedOptions extends React.Component {
|
||||
state = {
|
||||
selectedItems: [],
|
||||
};
|
||||
|
||||
handleChange = selectedItems => {
|
||||
this.setState({ selectedItems });
|
||||
};
|
||||
|
||||
render() {
|
||||
const { selectedItems } = this.state;
|
||||
const filteredOptions = OPTIONS.filter(o => !selectedItems.includes(o));
|
||||
return (
|
||||
<Select
|
||||
mode="multiple"
|
||||
placeholder="Inserted are removed"
|
||||
value={selectedItems}
|
||||
onChange={this.handleChange}
|
||||
style={{ width: '100%' }}
|
||||
>
|
||||
{filteredOptions.map(item => (
|
||||
<Select.Option key={item} value={item}>
|
||||
{item}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(<SelectWithHiddenSelectedOptions />, mountNode);
|
||||
````
|
||||
@@ -37,7 +37,7 @@ export interface AbstractSelectProps {
|
||||
open?: boolean;
|
||||
onDropdownVisibleChange?: (open: boolean) => void;
|
||||
autoClearSearchValue?: boolean;
|
||||
dropdownRender?: (menu: React.ReactNode) => React.ReactNode;
|
||||
dropdownRender?: (menu?: React.ReactNode, props?: SelectProps) => React.ReactNode;
|
||||
loading?: boolean;
|
||||
}
|
||||
|
||||
@@ -131,8 +131,8 @@ export default class Select<T = SelectValue> extends React.Component<SelectProps
|
||||
|
||||
warning(
|
||||
props.mode !== 'combobox',
|
||||
'The combobox mode of Select is deprecated,' +
|
||||
'it will be removed in next major version,' +
|
||||
'The combobox mode of Select is deprecated, ' +
|
||||
'it will be removed in next major version, ' +
|
||||
'please use AutoComplete instead',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import demoTest from '../../../tests/shared/demoTest';
|
||||
|
||||
demoTest('slider');
|
||||
demoTest('slider', { skip: process.env.LIB_DIR === 'dist' && ['show-tooltip.md'] });
|
||||
|
||||
@@ -5,19 +5,16 @@ title:
|
||||
en-US: Control visible of ToolTip
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
## zh-CN
|
||||
|
||||
当 `tooltipVisible` 为 `true` 时,将始终显示ToolTip;反之则始终不显示,即使在拖动、移入时也是如此。
|
||||
当 `tooltipVisible` 为 `true` 时,将始终显示ToolTip;反之则始终不显示,即使在拖动、移入时也是如此。
|
||||
|
||||
## en-US
|
||||
## en-US
|
||||
|
||||
When `tooltipVisible` is `true`, ToolTip will show always, or ToolTip will not show anyway, even if dragging or hovering.
|
||||
When `tooltipVisible` is `true`, ToolTip will show always, or ToolTip will not show anyway, even if dragging or hovering.
|
||||
|
||||
````jsx
|
||||
import { Slider } from 'antd';
|
||||
|
||||
````jsx
|
||||
|
||||
import Slider from '..';
|
||||
|
||||
ReactDOM.render(<Slider defaultValue={30} tooltipVisible />, mountNode);
|
||||
|
||||
````
|
||||
ReactDOM.render(<Slider defaultValue={30} tooltipVisible />, mountNode);
|
||||
````
|
||||
|
||||
@@ -81,12 +81,7 @@ export default class Slider extends React.Component<SliderProps, SliderState> {
|
||||
const { tooltipPrefixCls, tipFormatter, tooltipVisible } = this.props;
|
||||
const { visibles } = this.state;
|
||||
const isTipFormatter = tipFormatter ? visibles[index] || dragging : false;
|
||||
let visible;
|
||||
if (tooltipVisible) {
|
||||
visible = tooltipVisible || isTipFormatter;
|
||||
} else if (tooltipVisible === undefined) {
|
||||
visible = isTipFormatter;
|
||||
}
|
||||
const visible = tooltipVisible || (tooltipVisible === undefined && isTipFormatter);
|
||||
return (
|
||||
<Tooltip
|
||||
prefixCls={tooltipPrefixCls}
|
||||
|
||||
@@ -14,7 +14,7 @@ describe('Spin', () => {
|
||||
.find('.ant-spin-nested-loading')
|
||||
.at(0)
|
||||
.prop('style'),
|
||||
).toBe(null);
|
||||
).toBeFalsy();
|
||||
expect(
|
||||
wrapper
|
||||
.find('.ant-spin')
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import * as React from 'react';
|
||||
import * as PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
import Animate from 'rc-animate';
|
||||
import omit from 'omit.js';
|
||||
|
||||
export type SpinSize = 'small' | 'default' | 'large';
|
||||
@@ -93,13 +92,6 @@ class Spin extends React.Component<SpinProps, SpinState> {
|
||||
return !!(this.props && this.props.children);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { spinning, delay } = this.props;
|
||||
if (shouldDelay(spinning, delay)) {
|
||||
this.delayTimeout = window.setTimeout(this.delayUpdateSpinning, delay);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.debounceTimeout) {
|
||||
clearTimeout(this.debounceTimeout);
|
||||
@@ -145,7 +137,7 @@ class Spin extends React.Component<SpinProps, SpinState> {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { className, size, prefixCls, tip, wrapperClassName, ...restProps } = this.props;
|
||||
const { className, size, prefixCls, tip, wrapperClassName, style, ...restProps } = this.props;
|
||||
const { spinning } = this.state;
|
||||
|
||||
const spinClassName = classNames(
|
||||
@@ -163,33 +155,22 @@ class Spin extends React.Component<SpinProps, SpinState> {
|
||||
const divProps = omit(restProps, ['spinning', 'delay', 'indicator']);
|
||||
|
||||
const spinElement = (
|
||||
<div {...divProps} className={spinClassName}>
|
||||
<div {...divProps} style={style} className={spinClassName}>
|
||||
{renderIndicator(this.props)}
|
||||
{tip ? <div className={`${prefixCls}-text`}>{tip}</div> : null}
|
||||
</div>
|
||||
);
|
||||
if (this.isNestedPattern()) {
|
||||
let animateClassName = prefixCls + '-nested-loading';
|
||||
if (wrapperClassName) {
|
||||
animateClassName += ' ' + wrapperClassName;
|
||||
}
|
||||
const containerClassName = classNames({
|
||||
[`${prefixCls}-container`]: true,
|
||||
const containerClassName = classNames(`${prefixCls}-container`, {
|
||||
[`${prefixCls}-blur`]: spinning,
|
||||
});
|
||||
return (
|
||||
<Animate
|
||||
{...divProps}
|
||||
component="div"
|
||||
className={animateClassName}
|
||||
style={null}
|
||||
transitionName="fade"
|
||||
>
|
||||
<div {...divProps} className={classNames(`${prefixCls}-nested-loading`, wrapperClassName)}>
|
||||
{spinning && <div key="loading">{spinElement}</div>}
|
||||
<div className={containerClassName} key="container">
|
||||
{this.props.children}
|
||||
</div>
|
||||
</Animate>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return spinElement;
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
display: block;
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
max-height: 360px;
|
||||
max-height: 400px;
|
||||
width: 100%;
|
||||
z-index: 4;
|
||||
.@{spin-prefix-cls}-dot {
|
||||
@@ -75,19 +75,6 @@
|
||||
&-container {
|
||||
position: relative;
|
||||
transition: opacity 0.3s;
|
||||
.clearfix;
|
||||
}
|
||||
|
||||
&-blur {
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
overflow: hidden;
|
||||
opacity: 0.5;
|
||||
-webkit-filter: blur(0.5px);
|
||||
filter: blur(0.5px);
|
||||
|
||||
/* autoprefixer: off */
|
||||
filter: ~'progid\:DXImageTransform\.Microsoft\.Blur(PixelRadius\=1, MakeShadow\=false)';
|
||||
|
||||
&:after {
|
||||
content: '';
|
||||
@@ -97,12 +84,27 @@
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
background: #fff;
|
||||
opacity: 0.3;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: all 0.3s;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
z-index: 10;
|
||||
}
|
||||
}
|
||||
|
||||
&-blur {
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
overflow: hidden;
|
||||
opacity: 0.5;
|
||||
|
||||
&:after {
|
||||
opacity: 0.4;
|
||||
pointer-events: auto;
|
||||
}
|
||||
}
|
||||
|
||||
// tip
|
||||
// ------------------------------
|
||||
&-tip {
|
||||
|
||||
@@ -27,6 +27,7 @@ The whole of the step bar.
|
||||
|
||||
| Property | Description | Type | Default |
|
||||
| -------- | ----------- | ---- | ------- |
|
||||
| className | additional class to Steps | string | - |
|
||||
| current | to set the current step, counting from 0. You can overwrite this state by using `status` of `Step` | number | 0 |
|
||||
| direction | to specify the direction of the step bar, `horizontal` or `vertical` | string | `horizontal` |
|
||||
| labelPlacement | place title and description with `horizontal` or `vertical` direction | string | `horizontal` |
|
||||
|
||||
@@ -6,6 +6,7 @@ import Icon from '../icon';
|
||||
export interface StepsProps {
|
||||
prefixCls?: string;
|
||||
iconPrefix?: string;
|
||||
className?: string;
|
||||
current?: number;
|
||||
initial?: number;
|
||||
labelPlacement?: 'horizontal' | 'vertical';
|
||||
|
||||
@@ -28,6 +28,7 @@ title: Steps
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
| className | 步骤条类名 | string | - |
|
||||
| current | 指定当前步骤,从 0 开始记数。在子 Step 元素中,可以通过 `status` 属性覆盖状态 | number | 0 |
|
||||
| direction | 指定步骤条方向。目前支持水平(`horizontal`)和竖直(`vertical`)两种方向 | string | horizontal |
|
||||
| labelPlacement | 指定标签放置位置,默认水平放图标右侧,可选 `vertical` 放图标下方 | string | `horizontal` |
|
||||
|
||||
@@ -356,6 +356,7 @@
|
||||
@table-expanded-row-bg: #fbfbfb;
|
||||
@table-padding-vertical: 16px;
|
||||
@table-padding-horizontal: 16px;
|
||||
@table-border-radius-base : @border-radius-base;
|
||||
|
||||
// Tag
|
||||
// --
|
||||
@@ -420,6 +421,8 @@
|
||||
@tabs-bar-margin: 0 0 16px 0;
|
||||
@tabs-horizontal-margin: 0 32px 0 0;
|
||||
@tabs-horizontal-padding: 12px 16px;
|
||||
@tabs-horizontal-padding-lg: 16px;
|
||||
@tabs-horizontal-padding-sm: 8px 16px;
|
||||
@tabs-vertical-padding: 8px 24px;
|
||||
@tabs-vertical-margin: 0 0 16px 0;
|
||||
@tabs-scrolling-size: 32px;
|
||||
|
||||
@@ -58,8 +58,13 @@ export default class SelectionCheckboxAll<T> extends React.Component<
|
||||
});
|
||||
}
|
||||
|
||||
checkSelection(data: T[], type: string, byDefaultChecked: boolean) {
|
||||
const { store, getCheckboxPropsByItem, getRecordKey } = this.props;
|
||||
checkSelection(
|
||||
props: SelectionCheckboxAllProps<T>,
|
||||
data: T[],
|
||||
type: string,
|
||||
byDefaultChecked: boolean,
|
||||
) {
|
||||
const { store, getCheckboxPropsByItem, getRecordKey } = props || this.props;
|
||||
// type should be 'every' | 'some'
|
||||
if (type === 'every' || type === 'some') {
|
||||
return byDefaultChecked
|
||||
@@ -93,8 +98,9 @@ export default class SelectionCheckboxAll<T> extends React.Component<
|
||||
checked = false;
|
||||
} else {
|
||||
checked = store.getState().selectionDirty
|
||||
? this.checkSelection(data, 'every', false)
|
||||
: this.checkSelection(data, 'every', false) || this.checkSelection(data, 'every', true);
|
||||
? this.checkSelection(props, data, 'every', false)
|
||||
: this.checkSelection(props, data, 'every', false) ||
|
||||
this.checkSelection(props, data, 'every', true);
|
||||
}
|
||||
return checked;
|
||||
}
|
||||
@@ -106,15 +112,17 @@ export default class SelectionCheckboxAll<T> extends React.Component<
|
||||
indeterminate = false;
|
||||
} else {
|
||||
indeterminate = store.getState().selectionDirty
|
||||
? this.checkSelection(data, 'some', false) && !this.checkSelection(data, 'every', false)
|
||||
: (this.checkSelection(data, 'some', false) &&
|
||||
!this.checkSelection(data, 'every', false)) ||
|
||||
(this.checkSelection(data, 'some', true) && !this.checkSelection(data, 'every', true));
|
||||
? this.checkSelection(props, data, 'some', false) &&
|
||||
!this.checkSelection(props, data, 'every', false)
|
||||
: (this.checkSelection(props, data, 'some', false) &&
|
||||
!this.checkSelection(props, data, 'every', false)) ||
|
||||
(this.checkSelection(props, data, 'some', true) &&
|
||||
!this.checkSelection(props, data, 'every', true));
|
||||
}
|
||||
return indeterminate;
|
||||
}
|
||||
|
||||
handleSelectAllChagne = (e: CheckboxChangeEvent) => {
|
||||
handleSelectAllChange = (e: CheckboxChangeEvent) => {
|
||||
const checked = e.target.checked;
|
||||
this.props.onSelect(checked ? 'all' : 'removeAll', 0, null);
|
||||
};
|
||||
@@ -171,7 +179,7 @@ export default class SelectionCheckboxAll<T> extends React.Component<
|
||||
checked={checked}
|
||||
indeterminate={indeterminate}
|
||||
disabled={disabled}
|
||||
onChange={this.handleSelectAllChagne}
|
||||
onChange={this.handleSelectAllChange}
|
||||
/>
|
||||
{customSelections}
|
||||
</div>
|
||||
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
TableComponents,
|
||||
RowSelectionType,
|
||||
TableLocale,
|
||||
AdditionalCellProps,
|
||||
ColumnProps,
|
||||
CompareFn,
|
||||
TableStateFilters,
|
||||
@@ -488,7 +489,7 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
|
||||
let selectedRowKeys = this.store.getState().selectedRowKeys.concat(defaultSelection);
|
||||
const key = this.getRecordKey(record, rowIndex);
|
||||
const { pivot } = this.state;
|
||||
const rows = this.getFlatCurrentPageData();
|
||||
const rows = this.getFlatCurrentPageData(this.props.childrenColumnName);
|
||||
let realIndex = rowIndex;
|
||||
if (this.props.expandedRowRender) {
|
||||
realIndex = rows.findIndex(row => this.getRecordKey(row, rowIndex) === key);
|
||||
@@ -553,10 +554,8 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
|
||||
handleRadioSelect = (record: T, rowIndex: number, e: RadioChangeEvent) => {
|
||||
const checked = e.target.checked;
|
||||
const nativeEvent = e.nativeEvent;
|
||||
const defaultSelection = this.store.getState().selectionDirty ? [] : this.getDefaultSelection();
|
||||
let selectedRowKeys = this.store.getState().selectedRowKeys.concat(defaultSelection);
|
||||
const key = this.getRecordKey(record, rowIndex);
|
||||
selectedRowKeys = [key];
|
||||
const selectedRowKeys = [key];
|
||||
this.store.setState({
|
||||
selectionDirty: true,
|
||||
});
|
||||
@@ -570,7 +569,7 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
|
||||
};
|
||||
|
||||
handleSelectRow = (selectionKey: string, index: number, onSelectFunc: SelectionItemSelectFn) => {
|
||||
const data = this.getFlatCurrentPageData();
|
||||
const data = this.getFlatCurrentPageData(this.props.childrenColumnName);
|
||||
const defaultSelection = this.store.getState().selectionDirty ? [] : this.getDefaultSelection();
|
||||
const selectedRowKeys = this.store.getState().selectedRowKeys.concat(defaultSelection);
|
||||
const changeableRowKeys = data
|
||||
@@ -722,10 +721,10 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
|
||||
};
|
||||
|
||||
renderRowSelection(locale: TableLocale) {
|
||||
const { prefixCls, rowSelection } = this.props;
|
||||
const { prefixCls, rowSelection, childrenColumnName } = this.props;
|
||||
const columns = this.columns.concat();
|
||||
if (rowSelection) {
|
||||
const data = this.getFlatCurrentPageData().filter((item, index) => {
|
||||
const data = this.getFlatCurrentPageData(childrenColumnName).filter((item, index) => {
|
||||
if (rowSelection.getCheckboxProps) {
|
||||
return !this.getCheckboxPropsByItem(item, index).disabled;
|
||||
}
|
||||
@@ -777,7 +776,7 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
|
||||
}
|
||||
|
||||
getColumnKey(column: ColumnProps<T>, index?: number) {
|
||||
return column.key || column.dataIndex || index;
|
||||
return column.key || (column.dataIndex as string) || index;
|
||||
}
|
||||
|
||||
getMaxCurrent(total: number) {
|
||||
@@ -805,6 +804,7 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
|
||||
const key = this.getColumnKey(column, i) as string;
|
||||
let filterDropdown;
|
||||
let sortButton;
|
||||
let onHeaderCell = column.onHeaderCell;
|
||||
const sortTitle = this.getColumnTitle(column.title, {}) || locale.sortTitle;
|
||||
const isSortColumn = this.isSortColumn(column);
|
||||
if ((column.filters && column.filters.length > 0) || column.filterDropdown) {
|
||||
@@ -839,7 +839,27 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
onHeaderCell = (col: Column<T>) => {
|
||||
let colProps: AdditionalCellProps = {};
|
||||
// Get original first
|
||||
if (column.onHeaderCell) {
|
||||
colProps = {
|
||||
...column.onHeaderCell(col),
|
||||
};
|
||||
}
|
||||
// Add sorter logic
|
||||
const onHeaderCellClick = colProps.onClick;
|
||||
colProps.onClick = (...args) => {
|
||||
this.toggleSortOrder(column);
|
||||
if (onHeaderCellClick) {
|
||||
onHeaderCellClick(...args);
|
||||
}
|
||||
};
|
||||
return colProps;
|
||||
};
|
||||
}
|
||||
const sortTitleString = sortButton && typeof sortTitle === 'string' ? sortTitle : undefined;
|
||||
return {
|
||||
...column,
|
||||
className: classNames(column.className, {
|
||||
@@ -851,15 +871,15 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
|
||||
title: [
|
||||
<div
|
||||
key="title"
|
||||
title={sortButton ? sortTitle : undefined}
|
||||
title={sortTitleString}
|
||||
className={sortButton ? `${prefixCls}-column-sorters` : undefined}
|
||||
onClick={() => this.toggleSortOrder(column)}
|
||||
>
|
||||
{this.renderColumnTitle(column.title)}
|
||||
{sortButton}
|
||||
</div>,
|
||||
filterDropdown,
|
||||
],
|
||||
onHeaderCell,
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -882,8 +902,8 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
|
||||
}
|
||||
if (!(title instanceof Function) && typeof title !== 'string' && typeof title !== 'number') {
|
||||
const props = title.props;
|
||||
const { children } = props;
|
||||
if (props && props.children) {
|
||||
const { children } = props;
|
||||
return this.getColumnTitle(children, props);
|
||||
}
|
||||
} else {
|
||||
@@ -1003,8 +1023,8 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
|
||||
return flatArray(this.getLocalData(null, false));
|
||||
}
|
||||
|
||||
getFlatCurrentPageData() {
|
||||
return flatArray(this.getCurrentPageData());
|
||||
getFlatCurrentPageData(childrenColumnName: string | undefined) {
|
||||
return flatArray(this.getCurrentPageData(), childrenColumnName);
|
||||
}
|
||||
|
||||
recursiveSort(data: T[], sorterFn: (a: any, b: any) => number): T[] {
|
||||
|
||||
@@ -615,4 +615,40 @@ describe('Table.rowSelection', () => {
|
||||
expect(onChange.mock.calls[1][0].length).toBe(2);
|
||||
expect(onChange.mock.calls[1][1].length).toBe(2);
|
||||
});
|
||||
|
||||
it('render correctly when set childrenColumnName', () => {
|
||||
const newDatas = [
|
||||
{
|
||||
key: 1,
|
||||
name: 'Jack',
|
||||
children: [
|
||||
{
|
||||
key: 11,
|
||||
name: 'John Brown',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 2,
|
||||
name: 'Lucy',
|
||||
children: [
|
||||
{
|
||||
key: 21,
|
||||
name: 'Lucy Brown',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
const wrapper = mount(
|
||||
<Table columns={columns} dataSource={newDatas} childrenColumnName="test" rowSelection={{}} />,
|
||||
);
|
||||
const checkboxes = wrapper.find('input');
|
||||
const checkboxAll = wrapper.find('SelectionCheckboxAll');
|
||||
|
||||
checkboxes.at(1).simulate('change', { target: { checked: true } });
|
||||
expect(checkboxAll.instance().state).toEqual({ indeterminate: true, checked: false });
|
||||
|
||||
checkboxes.at(2).simulate('change', { target: { checked: true } });
|
||||
expect(checkboxAll.instance().state).toEqual({ indeterminate: false, checked: true });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -240,13 +240,11 @@ exports[`renders ./components/table/demo/basic.md correctly 1`] = `
|
||||
<span>
|
||||
<div
|
||||
class="ant-tag ant-tag-blue"
|
||||
data-show="true"
|
||||
>
|
||||
nice
|
||||
</div>
|
||||
<div
|
||||
class="ant-tag ant-tag-blue"
|
||||
data-show="true"
|
||||
>
|
||||
developer
|
||||
</div>
|
||||
@@ -305,7 +303,6 @@ exports[`renders ./components/table/demo/basic.md correctly 1`] = `
|
||||
<span>
|
||||
<div
|
||||
class="ant-tag ant-tag-blue"
|
||||
data-show="true"
|
||||
>
|
||||
loser
|
||||
</div>
|
||||
@@ -364,13 +361,11 @@ exports[`renders ./components/table/demo/basic.md correctly 1`] = `
|
||||
<span>
|
||||
<div
|
||||
class="ant-tag ant-tag-blue"
|
||||
data-show="true"
|
||||
>
|
||||
cool
|
||||
</div>
|
||||
<div
|
||||
class="ant-tag ant-tag-blue"
|
||||
data-show="true"
|
||||
>
|
||||
teacher
|
||||
</div>
|
||||
@@ -1038,8 +1033,12 @@ exports[`renders ./components/table/demo/custom-filter-panel.md correctly 1`] =
|
||||
class=""
|
||||
>
|
||||
<colgroup>
|
||||
<col />
|
||||
<col />
|
||||
<col
|
||||
style="width:30%;min-width:30%"
|
||||
/>
|
||||
<col
|
||||
style="width:20%;min-width:20%"
|
||||
/>
|
||||
<col />
|
||||
</colgroup>
|
||||
<thead
|
||||
@@ -1053,31 +1052,48 @@ exports[`renders ./components/table/demo/custom-filter-panel.md correctly 1`] =
|
||||
Name
|
||||
</div>
|
||||
<i
|
||||
class="anticon anticon-smile-o ant-table-filter-icon ant-dropdown-trigger"
|
||||
style="color:#aaa"
|
||||
class="anticon anticon-search ant-table-filter-icon ant-dropdown-trigger"
|
||||
title="Filter menu"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="smile"
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M288 421a48 48 0 1 0 96 0 48 48 0 1 0-96 0zm352 0a48 48 0 1 0 96 0 48 48 0 1 0-96 0zM512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm263 711c-34.2 34.2-74 61-118.3 79.8C611 874.2 562.3 884 512 884c-50.3 0-99-9.8-144.8-29.2A370.4 370.4 0 0 1 248.9 775c-34.2-34.2-61-74-79.8-118.3C149.8 611 140 562.3 140 512s9.8-99 29.2-144.8A370.4 370.4 0 0 1 249 248.9c34.2-34.2 74-61 118.3-79.8C413 149.8 461.7 140 512 140c50.3 0 99 9.8 144.8 29.2A370.4 370.4 0 0 1 775.1 249c34.2 34.2 61 74 79.8 118.3C874.2 413 884 461.7 884 512s-9.8 99-29.2 144.8A368.89 368.89 0 0 1 775 775zM664 533h-48.1c-4.2 0-7.8 3.2-8.1 7.4C604 589.9 562.5 629 512 629s-92.1-39.1-95.8-88.6c-.3-4.2-3.9-7.4-8.1-7.4H360a8 8 0 0 0-8 8.4c4.4 84.3 74.5 151.6 160 151.6s155.6-67.3 160-151.6a8 8 0 0 0-8-8.4z"
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0 0 11.6 0l43.6-43.5a8.2 8.2 0 0 0 0-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
</th>
|
||||
<th
|
||||
class=""
|
||||
class="ant-table-column-has-actions ant-table-column-has-filters"
|
||||
>
|
||||
<div>
|
||||
Age
|
||||
</div>
|
||||
<i
|
||||
class="anticon anticon-search ant-table-filter-icon ant-dropdown-trigger"
|
||||
title="Filter menu"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0 0 11.6 0l43.6-43.5a8.2 8.2 0 0 0 0-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
</th>
|
||||
<th
|
||||
class="ant-table-column-has-actions ant-table-column-has-filters"
|
||||
@@ -1086,20 +1102,20 @@ exports[`renders ./components/table/demo/custom-filter-panel.md correctly 1`] =
|
||||
Address
|
||||
</div>
|
||||
<i
|
||||
class="anticon anticon-filter ant-dropdown-trigger"
|
||||
class="anticon anticon-search ant-table-filter-icon ant-dropdown-trigger"
|
||||
title="Filter menu"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="filter"
|
||||
data-icon="search"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M349 838c0 17.7 14.2 32 31.8 32h262.4c17.6 0 31.8-14.3 31.8-32V642H349v196zm531.1-684H143.9c-24.5 0-39.8 26.7-27.5 48l221.3 376h348.8l221.3-376c12.1-21.3-3.2-48-27.7-48z"
|
||||
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0 0 11.6 0l43.6-43.5a8.2 8.2 0 0 0 0-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
@@ -1120,17 +1136,35 @@ exports[`renders ./components/table/demo/custom-filter-panel.md correctly 1`] =
|
||||
class="ant-table-row-indent indent-level-0"
|
||||
style="padding-left:0px"
|
||||
/>
|
||||
John Brown
|
||||
</td>
|
||||
<td
|
||||
class=""
|
||||
>
|
||||
32
|
||||
<span>
|
||||
<span
|
||||
class=""
|
||||
>
|
||||
John Brown
|
||||
</span>
|
||||
</span>
|
||||
</td>
|
||||
<td
|
||||
class="ant-table-column-has-actions ant-table-column-has-filters"
|
||||
>
|
||||
New York No. 1 Lake Park
|
||||
<span>
|
||||
<span
|
||||
class=""
|
||||
>
|
||||
32
|
||||
</span>
|
||||
</span>
|
||||
</td>
|
||||
<td
|
||||
class="ant-table-column-has-actions ant-table-column-has-filters"
|
||||
>
|
||||
<span>
|
||||
<span
|
||||
class=""
|
||||
>
|
||||
New York No. 1 Lake Park
|
||||
</span>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr
|
||||
@@ -1144,17 +1178,35 @@ exports[`renders ./components/table/demo/custom-filter-panel.md correctly 1`] =
|
||||
class="ant-table-row-indent indent-level-0"
|
||||
style="padding-left:0px"
|
||||
/>
|
||||
Joe Black
|
||||
</td>
|
||||
<td
|
||||
class=""
|
||||
>
|
||||
42
|
||||
<span>
|
||||
<span
|
||||
class=""
|
||||
>
|
||||
Joe Black
|
||||
</span>
|
||||
</span>
|
||||
</td>
|
||||
<td
|
||||
class="ant-table-column-has-actions ant-table-column-has-filters"
|
||||
>
|
||||
London No. 1 Lake Park
|
||||
<span>
|
||||
<span
|
||||
class=""
|
||||
>
|
||||
42
|
||||
</span>
|
||||
</span>
|
||||
</td>
|
||||
<td
|
||||
class="ant-table-column-has-actions ant-table-column-has-filters"
|
||||
>
|
||||
<span>
|
||||
<span
|
||||
class=""
|
||||
>
|
||||
London No. 1 Lake Park
|
||||
</span>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr
|
||||
@@ -1168,17 +1220,35 @@ exports[`renders ./components/table/demo/custom-filter-panel.md correctly 1`] =
|
||||
class="ant-table-row-indent indent-level-0"
|
||||
style="padding-left:0px"
|
||||
/>
|
||||
Jim Green
|
||||
</td>
|
||||
<td
|
||||
class=""
|
||||
>
|
||||
32
|
||||
<span>
|
||||
<span
|
||||
class=""
|
||||
>
|
||||
Jim Green
|
||||
</span>
|
||||
</span>
|
||||
</td>
|
||||
<td
|
||||
class="ant-table-column-has-actions ant-table-column-has-filters"
|
||||
>
|
||||
Sidney No. 1 Lake Park
|
||||
<span>
|
||||
<span
|
||||
class=""
|
||||
>
|
||||
32
|
||||
</span>
|
||||
</span>
|
||||
</td>
|
||||
<td
|
||||
class="ant-table-column-has-actions ant-table-column-has-filters"
|
||||
>
|
||||
<span>
|
||||
<span
|
||||
class=""
|
||||
>
|
||||
Sidney No. 1 Lake Park
|
||||
</span>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr
|
||||
@@ -1192,17 +1262,35 @@ exports[`renders ./components/table/demo/custom-filter-panel.md correctly 1`] =
|
||||
class="ant-table-row-indent indent-level-0"
|
||||
style="padding-left:0px"
|
||||
/>
|
||||
Jim Red
|
||||
</td>
|
||||
<td
|
||||
class=""
|
||||
>
|
||||
32
|
||||
<span>
|
||||
<span
|
||||
class=""
|
||||
>
|
||||
Jim Red
|
||||
</span>
|
||||
</span>
|
||||
</td>
|
||||
<td
|
||||
class="ant-table-column-has-actions ant-table-column-has-filters"
|
||||
>
|
||||
London No. 2 Lake Park
|
||||
<span>
|
||||
<span
|
||||
class=""
|
||||
>
|
||||
32
|
||||
</span>
|
||||
</span>
|
||||
</td>
|
||||
<td
|
||||
class="ant-table-column-has-actions ant-table-column-has-filters"
|
||||
>
|
||||
<span>
|
||||
<span
|
||||
class=""
|
||||
>
|
||||
London No. 2 Lake Park
|
||||
</span>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -9556,13 +9644,11 @@ exports[`renders ./components/table/demo/jsx.md correctly 1`] = `
|
||||
<span>
|
||||
<div
|
||||
class="ant-tag ant-tag-blue"
|
||||
data-show="true"
|
||||
>
|
||||
nice
|
||||
</div>
|
||||
<div
|
||||
class="ant-tag ant-tag-blue"
|
||||
data-show="true"
|
||||
>
|
||||
developer
|
||||
</div>
|
||||
@@ -9622,7 +9708,6 @@ exports[`renders ./components/table/demo/jsx.md correctly 1`] = `
|
||||
<span>
|
||||
<div
|
||||
class="ant-tag ant-tag-blue"
|
||||
data-show="true"
|
||||
>
|
||||
loser
|
||||
</div>
|
||||
@@ -9682,13 +9767,11 @@ exports[`renders ./components/table/demo/jsx.md correctly 1`] = `
|
||||
<span>
|
||||
<div
|
||||
class="ant-tag ant-tag-blue"
|
||||
data-show="true"
|
||||
>
|
||||
cool
|
||||
</div>
|
||||
<div
|
||||
class="ant-tag ant-tag-blue"
|
||||
data-show="true"
|
||||
>
|
||||
teacher
|
||||
</div>
|
||||
|
||||
@@ -17,6 +17,7 @@ Implement a customized column search example via `filterDropdown`.
|
||||
import {
|
||||
Table, Input, Button, Icon,
|
||||
} from 'antd';
|
||||
import Highlighter from 'react-highlight-words';
|
||||
|
||||
const data = [{
|
||||
key: '1',
|
||||
@@ -45,12 +46,60 @@ class App extends React.Component {
|
||||
searchText: '',
|
||||
};
|
||||
|
||||
handleSearch = (selectedKeys, confirm) => () => {
|
||||
getColumnSearchProps = (dataIndex) => ({
|
||||
filterDropdown: ({
|
||||
setSelectedKeys, selectedKeys, confirm, clearFilters,
|
||||
}) => (
|
||||
<div className="custom-filter-dropdown">
|
||||
<Input
|
||||
ref={node => { this.searchInput = node; }}
|
||||
placeholder={`Search ${dataIndex}`}
|
||||
value={selectedKeys[0]}
|
||||
onChange={e => setSelectedKeys(e.target.value ? [e.target.value] : [])}
|
||||
onPressEnter={() => this.handleSearch(selectedKeys, confirm)}
|
||||
style={{ width: 188, marginBottom: 8, display: 'block' }}
|
||||
/>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => this.handleSearch(selectedKeys, confirm)}
|
||||
icon="search"
|
||||
size="small"
|
||||
style={{ width: 90, marginRight: 8 }}
|
||||
>
|
||||
Search
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => this.handleReset(clearFilters)}
|
||||
size="small"
|
||||
style={{ width: 90 }}
|
||||
>
|
||||
Reset
|
||||
</Button>
|
||||
</div>
|
||||
),
|
||||
filterIcon: filtered => <Icon type="search" style={{ color: filtered ? '#1890ff' : undefined }} />,
|
||||
onFilter: (value, record) => record[dataIndex].toString().toLowerCase().includes(value.toLowerCase()),
|
||||
onFilterDropdownVisibleChange: (visible) => {
|
||||
if (visible) {
|
||||
setTimeout(() => this.searchInput.select());
|
||||
}
|
||||
},
|
||||
render: (text) => (
|
||||
<Highlighter
|
||||
highlightStyle={{ backgroundColor: '#ffc069', padding: 0 }}
|
||||
searchWords={[this.state.searchText]}
|
||||
autoEscape
|
||||
textToHighlight={text.toString()}
|
||||
/>
|
||||
),
|
||||
})
|
||||
|
||||
handleSearch = (selectedKeys, confirm) => {
|
||||
confirm();
|
||||
this.setState({ searchText: selectedKeys[0] });
|
||||
}
|
||||
|
||||
handleReset = clearFilters => () => {
|
||||
handleReset = (clearFilters) => {
|
||||
clearFilters();
|
||||
this.setState({ searchText: '' });
|
||||
}
|
||||
@@ -60,57 +109,19 @@ class App extends React.Component {
|
||||
title: 'Name',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
filterDropdown: ({
|
||||
setSelectedKeys, selectedKeys, confirm, clearFilters,
|
||||
}) => (
|
||||
<div className="custom-filter-dropdown">
|
||||
<Input
|
||||
ref={ele => this.searchInput = ele}
|
||||
placeholder="Search name"
|
||||
value={selectedKeys[0]}
|
||||
onChange={e => setSelectedKeys(e.target.value ? [e.target.value] : [])}
|
||||
onPressEnter={this.handleSearch(selectedKeys, confirm)}
|
||||
/>
|
||||
<Button type="primary" onClick={this.handleSearch(selectedKeys, confirm)}>Search</Button>
|
||||
<Button onClick={this.handleReset(clearFilters)}>Reset</Button>
|
||||
</div>
|
||||
),
|
||||
filterIcon: filtered => <Icon type="smile-o" style={{ color: filtered ? '#108ee9' : '#aaa' }} />,
|
||||
onFilter: (value, record) => record.name.toLowerCase().includes(value.toLowerCase()),
|
||||
onFilterDropdownVisibleChange: (visible) => {
|
||||
if (visible) {
|
||||
setTimeout(() => {
|
||||
this.searchInput.focus();
|
||||
});
|
||||
}
|
||||
},
|
||||
render: (text) => {
|
||||
const { searchText } = this.state;
|
||||
return searchText ? (
|
||||
<span>
|
||||
{text.split(new RegExp(`(${searchText})`, 'gi')).map((fragment, i) => (
|
||||
fragment.toLowerCase() === searchText.toLowerCase()
|
||||
? <span key={i} className="highlight">{fragment}</span> : fragment // eslint-disable-line
|
||||
))}
|
||||
</span>
|
||||
) : text;
|
||||
},
|
||||
width: '30%',
|
||||
...this.getColumnSearchProps('name'),
|
||||
}, {
|
||||
title: 'Age',
|
||||
dataIndex: 'age',
|
||||
key: 'age',
|
||||
width: '20%',
|
||||
...this.getColumnSearchProps('age'),
|
||||
}, {
|
||||
title: 'Address',
|
||||
dataIndex: 'address',
|
||||
key: 'address',
|
||||
filters: [{
|
||||
text: 'London',
|
||||
value: 'London',
|
||||
}, {
|
||||
text: 'New York',
|
||||
value: 'New York',
|
||||
}],
|
||||
onFilter: (value, record) => record.address.indexOf(value) === 0,
|
||||
...this.getColumnSearchProps('address'),
|
||||
}];
|
||||
return <Table columns={columns} dataSource={data} />;
|
||||
}
|
||||
@@ -122,21 +133,8 @@ ReactDOM.render(<App />, mountNode);
|
||||
````css
|
||||
.custom-filter-dropdown {
|
||||
padding: 8px;
|
||||
border-radius: 6px;
|
||||
border-radius: 4px;
|
||||
background: #fff;
|
||||
box-shadow: 0 1px 6px rgba(0, 0, 0, .2);
|
||||
}
|
||||
|
||||
.custom-filter-dropdown input {
|
||||
width: 130px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.custom-filter-dropdown button {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
color: #f50;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, .15);
|
||||
}
|
||||
````
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
order: 7
|
||||
order: 6
|
||||
title:
|
||||
en-US: Filter and sorter
|
||||
zh-CN: 筛选和排序
|
||||
|
||||
@@ -61,6 +61,7 @@ const columns = [{
|
||||
| defaultExpandedRowKeys | Initial expanded row keys | string\[] | - |
|
||||
| expandedRowKeys | Current expanded row keys | string\[] | - |
|
||||
| expandedRowRender | Expanded container render for each row | Function(record, index, indent, expanded):ReactNode | - |
|
||||
| expandIcon | Customize row expand Icon. Ref [example](http://react-component.github.io/table/examples/expandIcon.html) | Function(props):ReactNode | - |
|
||||
| expandRowByClick | Whether to expand row by clicking anywhere in the whole row | boolean | `false` |
|
||||
| footer | Table footer renderer | Function(currentPageData) | |
|
||||
| indentSize | Indent size in pixels of tree data | number | 15 |
|
||||
|
||||
@@ -66,6 +66,7 @@ const columns = [{
|
||||
| defaultExpandedRowKeys | 默认展开的行 | string\[] | - |
|
||||
| expandedRowKeys | 展开的行,控制属性 | string\[] | - |
|
||||
| expandedRowRender | 额外的展开行 | Function(record, index, indent, expanded):ReactNode | - |
|
||||
| expandIcon | 自定义展开图标,参考[示例](http://react-component.github.io/table/examples/expandIcon.html) | Function(props):ReactNode | - |
|
||||
| expandRowByClick | 通过点击行来展开子行 | boolean | `false` |
|
||||
| footer | 表格尾部 | Function(currentPageData) | |
|
||||
| indentSize | 展示树形数据时,每层缩进的宽度,以 px 为单位 | number | 15 |
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user