Merge from "master"

This commit is contained in:
afc163 2017-02-20 12:18:41 +08:00
commit a9a564779e
139 changed files with 7871 additions and 7637 deletions

View File

@ -3,4 +3,3 @@ components/**/*.jsx
!.eslintrc.js
!components/*/__tests__/*
!components/*/demo/*
!components/*/style/*

View File

@ -3,6 +3,7 @@
"rules": {
"at-rule-empty-line-before": null,
"at-rule-name-space-after": null,
"comment-empty-line-before": null,
"declaration-bang-space-before": null,
"declaration-empty-line-before": null,
"function-comma-newline-after": null,

View File

@ -17,6 +17,36 @@ If you want to read change logs before `2.0.0`, please visit [GitHub](https://gi
---
## 2.7.2
`2017-02-17`
- Fix that `antd.version` doesn't work as expected. [#4844](https://github.com/ant-design/ant-design/issues/4844)
- Fix that dist files don't include locales. [#4910](https://github.com/ant-design/ant-design/pull/4910)
- Fix that disabled option is selectable in search mode of Cascader. [#4699](https://github.com/ant-design/ant-design/issues/4699)
- **Button**
- Fix click animation of `Button[type=danger]`.
- Fix broken style with `loading`. [#4875](https://github.com/ant-design/ant-design/issues/4875)
- **Menu**
- Fix that `openKeys` should be controlled property in `vertical` mode. [#4876](https://github.com/ant-design/ant-design/issues/4876)
- Fix selected animation of Menu.Item.
- Fix broken style of Menu.SubMenu. [#4906](https://github.com/ant-design/ant-design/issues/4906)
- **Table**
- Fix broken style of table which use small size and fixed header. [#4850](https://github.com/ant-design/ant-design/issues/4850)
- Fix placeholder style. [#4851](https://github.com/ant-design/ant-design/pull/4851)
- Simplify DOM structure. [#4868](https://github.com/ant-design/ant-design/issues/4868)
- Fix that Radio should support number `0` as children. [#4874](https://github.com/ant-design/ant-design/issues/4874) [@HQidea](https://github.com/HQidea)
- Fix that RangePicker should work with `style.width` which is small than 300. [#4920](https://github.com/ant-design/ant-design/issues/4920)
- Fix CSS compile error caused by Spin. [#4915](https://github.com/ant-design/ant-design/issues/4915)
- Fix that Tooltip should work with disabled button in Chrome. [#4865](https://github.com/ant-design/ant-design/pull/4865)
- Fix UX of Tree while dragging. [#4858](https://github.com/ant-design/ant-design/issues/4858)
- Fix failed style of Upload. [#4810](https://github.com/ant-design/ant-design/issues/4810)
- Fix that `Menu[vertical]`'s SubMenu cannot popup in Layout.Sider. [#4890](https://github.com/ant-design/ant-design/issues/4890)
- Improve animation of Button and `Badge[status=processing]`.
![Badge animation](https://camo.githubusercontent.com/6874b2333f2fac3fac346404c6e70684e4dafc1a/68747470733a2f2f7a6f732e616c697061796f626a656374732e636f6d2f726d73706f7274616c2f73516b72756c716346734b4e54785158615971512e676966)
![Button animation](https://camo.githubusercontent.com/3963d12b45de4f522c2799361dbc3177e7bd93d1/68747470733a2f2f7a6f732e616c697061796f626a656374732e636f6d2f726d73706f7274616c2f46624b776d636f766d795364666c557468494e522e676966)
## 2.7.1
`2017-02-10`

View File

@ -10,13 +10,43 @@ timeline: true
#### 发布周期
* patch 版本:每周末会进行日常 bugfix 更新。(如果有紧急的 bugfix则任何时候都可发布
* minor 版本:每月发布一个带有新特性的版本。
* minor 版本:每月发布一个带有新特性的向下兼容的版本。
* 大版本号:含有破坏性更新和新特性,不在发布周期内。
如果需要查看 `2.0.0` 之前的更新日志,请移步 [GitHub](https://github.com/ant-design/ant-design/blob/1.x-stable/CHANGELOG.md)。
---
## 2.7.2
`2017-02-17`
- 修复 `antd.version` 无法正常使用的问题。 [#4844](https://github.com/ant-design/ant-design/issues/4844)
- 修复 dist 文件没有 locales 的问题。 [#4910](https://github.com/ant-design/ant-design/pull/4910)
- 修复 Cascader 搜索模式下可以选择已禁用选项的问题。 [#4699](https://github.com/ant-design/ant-design/issues/4699)
- **Button**
- 修复 `Button[type=danger]` 的点击动画。
- 修复设置 `loading` 时的样式问题。 [#4875](https://github.com/ant-design/ant-design/issues/4875)
- **Menu**
- 修复 `vertical` 模式下 `openKeys` 为受控属性。 [#4876](https://github.com/ant-design/ant-design/issues/4876)
- 修复 Menu.Item 选中时的动画问题。
- 修复 Menu.SubMenu 的样式问题。 [#4906](https://github.com/ant-design/ant-design/issues/4906)
- **Table**
- 修复在混合使用固定表头和小尺寸时的样式问题。 [#4850](https://github.com/ant-design/ant-design/issues/4850)
- 修复无数据时的占位符样式问题。 [#4851](https://github.com/ant-design/ant-design/pull/4851)
- 精简了 DOM 结构。 [#4868](https://github.com/ant-design/ant-design/issues/4868)
- 修复 Radio 组件 children 无法为数字 `0` 的问题。 [#4874](https://github.com/ant-design/ant-design/issues/4874) [@HQidea](https://github.com/HQidea)
- 修复 RangePicker `style.width` 无法小于 300 的问题。 [#4920](https://github.com/ant-design/ant-design/issues/4920)
- 修复 Spin 样式在打包时会导致编译错误的问题。 [#4915](https://github.com/ant-design/ant-design/issues/4915)
- 修复 Chrome 下 Tooltip 无法在 disabled 的按钮上使用的问题。 [#4865](https://github.com/ant-design/ant-design/pull/4865)
- 修复 Tree 节点在拖动时会导致整棵树抖动的问题。 [#4858](https://github.com/ant-design/ant-design/issues/4858)
- 修复 Upload 上传失败的样式问题。 [#4810](https://github.com/ant-design/ant-design/issues/4810)
- 修复 `Menu[vertical]` 和 Layout.Sider 配合使用时二级菜单无法弹出的问题。 [#4890](https://github.com/ant-design/ant-design/issues/4890)
- 优化 Button、`Badge[status=processing]` 的动画。
![Badge animation](https://camo.githubusercontent.com/6874b2333f2fac3fac346404c6e70684e4dafc1a/68747470733a2f2f7a6f732e616c697061796f626a656374732e636f6d2f726d73706f7274616c2f73516b72756c716346734b4e54785158615971512e676966)
![Button animation](https://camo.githubusercontent.com/3963d12b45de4f522c2799361dbc3177e7bd93d1/68747470733a2f2f7a6f732e616c697061796f626a656374732e636f6d2f726d73706f7274616c2f46624b776d636f766d795364666c557468494e522e676966)
## 2.7.1
`2017-02-10`

View File

@ -81,7 +81,7 @@ tsconfig.json
- [React 基础组件](http://react-component.github.io/)
- [移动端组件](http://mobile.ant.design)
- [动效](https://motion.ant.design)
- [设计规范速查手册](https://os.alipayobjects.com/rmsportal/HTXUgPGkyyxEivE.png)
- [设计规范速查手册](https://github.com/ant-design/ant-design/wiki/Ant-Design-%E8%AE%BE%E8%AE%A1%E5%9F%BA%E7%A1%80%E7%AE%80%E7%89%88)
- [开发者说明](https://github.com/ant-design/ant-design/wiki/Development)
- [版本发布规则](https://github.com/ant-design/ant-design/wiki/%E8%BD%AE%E5%80%BC%E8%A7%84%E5%88%99%E5%92%8C%E7%89%88%E6%9C%AC%E5%8F%91%E5%B8%83%E6%B5%81%E7%A8%8B)
- [社区贡献脚手架和范例](https://github.com/ant-design/ant-design/issues/129)

View File

@ -20,13 +20,12 @@ function onSelect(value) {
console.log('onSelect', value);
}
const Complete = React.createClass({
getInitialState() {
return {
class Complete extends React.Component {
state = {
dataSource: [],
};
},
handleChange(value) {
}
handleChange = (value) => {
this.setState({
dataSource: !value ? [] : [
value,
@ -34,10 +33,12 @@ const Complete = React.createClass({
value + value + value,
],
});
},
handleKeyPress(ev) {
}
handleKeyPress = (ev) => {
console.log('handleKeyPress', ev);
},
}
render() {
const { dataSource } = this.state;
return (
@ -51,8 +52,8 @@ const Complete = React.createClass({
<textarea onKeyPress={this.handleKeyPress} style={{ height: 50 }} />
</AutoComplete>
);
},
});
}
}
ReactDOM.render(<Complete />, mountNode);
````

View File

@ -20,13 +20,12 @@ function onSelect(value) {
console.log('onSelect', value);
}
const Complete = React.createClass({
getInitialState() {
return {
class Complete extends React.Component {
state = {
dataSource: [],
};
},
handleChange(value) {
}
handleChange = (value) => {
this.setState({
dataSource: !value ? [] : [
value,
@ -34,7 +33,8 @@ const Complete = React.createClass({
value + value + value,
],
});
},
}
render() {
const { dataSource } = this.state;
return (
@ -46,8 +46,8 @@ const Complete = React.createClass({
placeholder="input here"
/>
);
},
});
}
}
ReactDOM.render(<Complete />, mountNode);
````

View File

@ -19,12 +19,14 @@ import { AutoComplete } from 'antd';
const dataSource = ['Burns Bay Road', 'Downing Street', 'Wall Street'];
function Complete() {
return (<AutoComplete
return (
<AutoComplete
style={{ width: 200 }}
dataSource={dataSource}
placeholder="try to type `b`"
filterOption={(inputValue, option) => option.props.children.toUpperCase().indexOf(inputValue.toUpperCase()) !== -1}
/>);
/>
);
}
ReactDOM.render(<Complete />, mountNode);

View File

@ -18,13 +18,12 @@ import { AutoComplete } from 'antd';
const Option = AutoComplete.Option;
const Complete = React.createClass({
getInitialState() {
return {
class Complete extends React.Component {
state = {
result: [],
};
},
handleChange(value) {
}
handleChange = (value) => {
let result;
if (!value || value.indexOf('@') >= 0) {
result = [];
@ -32,7 +31,8 @@ const Complete = React.createClass({
result = ['gmail.com', '163.com', 'qq.com'].map(domain => `${value}@${domain}`);
}
this.setState({ result });
},
}
render() {
const { result } = this.state;
const children = result.map((email) => {
@ -47,8 +47,8 @@ const Complete = React.createClass({
{children}
</AutoComplete>
);
},
});
}
}
ReactDOM.render(<Complete />, mountNode);
````

View File

@ -47,24 +47,24 @@ function renderOption(item) {
{item.category}
</a>
区块中
<span style={{ float: 'right' }}>约 {item.count} 个结果</span>
<span className="global-search-item-count">约 {item.count} 个结果</span>
</Option>
);
}
const Complete = React.createClass({
getInitialState() {
return {
class Complete extends React.Component {
state = {
dataSource: [],
};
},
handleChange(value) {
}
handleChange = (value) => {
if (value) {
this.setState({
dataSource: searchResult(value),
});
}
},
}
render() {
const { dataSource } = this.state;
return (
@ -89,8 +89,8 @@ const Complete = React.createClass({
</AutoComplete>
</div>
);
},
});
}
}
ReactDOM.render(<Complete />, mountNode);
````
@ -128,11 +128,17 @@ ReactDOM.render(<Complete />, mountNode);
}
.global-search.ant-select-auto-complete .ant-input-preSuffix-wrapper .ant-input-suffix {
right: 0;
right: 1px;
}
.global-search.ant-select-auto-complete .ant-input-preSuffix-wrapper .ant-input-suffix button {
border-radius: 3px;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.global-search-item-count {
position: absolute;
right: 16px;
}
````

View File

@ -1,7 +1,7 @@
---
category: Components
type: Data Entry
cols: 1
cols: 2
title: AutoComplete
---

View File

@ -39,17 +39,18 @@ export interface AutoCompleteProps extends AbstractSelectProps {
}
class InputElement extends React.Component<any, any> {
private ele: Element;
private ele: HTMLInputElement;
focus = () => {
(findDOMNode(this.ele) as HTMLInputElement).focus();
this.ele.focus ? this.ele.focus() : (findDOMNode(this.ele) as HTMLInputElement).focus();
}
blur = () => {
(findDOMNode(this.ele) as HTMLInputElement).blur();
this.ele.blur ? this.ele.blur() : (findDOMNode(this.ele) as HTMLInputElement).blur();
}
render() {
return React.cloneElement(this.props.children, {
...this.props,
ref: ele => this.ele = ele,
ref: ele => this.ele = (ele as HTMLInputElement),
}, null);
}
}

View File

@ -17,27 +17,29 @@ The count will be animated as it changes.
import { Badge, Button, Icon, Switch } from 'antd';
const ButtonGroup = Button.Group;
const Test = React.createClass({
getInitialState() {
return {
class Demo extends React.Component {
state = {
count: 5,
show: true,
};
},
increase() {
}
increase = () => {
const count = this.state.count + 1;
this.setState({ count });
},
decline() {
}
decline = () => {
let count = this.state.count - 1;
if (count < 0) {
count = 0;
}
this.setState({ count });
},
onChange(show) {
}
onChange = (show) => {
this.setState({ show });
},
}
render() {
return (
<div>
@ -62,8 +64,8 @@ const Test = React.createClass({
</div>
</div>
);
},
});
}
}
ReactDOM.render(<Test />, mountNode);
ReactDOM.render(<Demo />, mountNode);
````

View File

@ -16,14 +16,16 @@ This will simply display a red badge, without a specific count.
````jsx
import { Badge, Icon } from 'antd';
ReactDOM.render(<div>
ReactDOM.render(
<div>
<Badge dot>
<Icon type="notification" />
</Badge>
<Badge dot>
<a href="#">Link something</a>
</Badge>
</div>, mountNode);
</div>
, mountNode);
````
<style>

View File

@ -18,9 +18,11 @@ Used in standalone when children is empty.
````jsx
import { Badge } from 'antd';
ReactDOM.render(<div>
ReactDOM.render(
<div>
<Badge count={25} />
<Badge count={4} style={{ backgroundColor: '#fff', color: '#999', boxShadow: '0 0 0 1px #d9d9d9 inset' }} />
<Badge count={109} style={{ backgroundColor: '#87d068' }} />
</div>, mountNode);
</div>
, mountNode);
````

View File

@ -16,7 +16,8 @@ title:
````jsx
import { Badge } from 'antd';
ReactDOM.render(<div>
ReactDOM.render(
<div>
<Badge count={99}>
<a href="#" className="head-example" />
</Badge>
@ -29,5 +30,6 @@ ReactDOM.render(<div>
<Badge count={1000} overflowCount={999}>
<a href="#" className="head-example" />
</Badge>
</div>, mountNode);
</div>
, mountNode);
````

View File

@ -68,7 +68,7 @@
width: 100%;
height: 100%;
border-radius: 50%;
background-color: @primary-color;
border: 1px solid @primary-color;
content: '';
animation: antStatusProcessing 1.2s infinite ease-in-out;
}

View File

@ -351,6 +351,19 @@ exports[`test renders ./components/button/demo/loading.md correctly 1`] = `
Click me!
</span>
</button>
<br />
<button
class="ant-btn ant-btn-circle ant-btn-loading"
type="button">
<i
class="anticon anticon-spin anticon-loading" />
</button>
<button
class="ant-btn ant-btn-primary ant-btn-circle ant-btn-loading"
type="button">
<i
class="anticon anticon-spin anticon-loading" />
</button>
</div>
`;

View File

@ -1,5 +1,5 @@
import React from 'react';
import { render } from 'enzyme';
import { render, mount } from 'enzyme';
import { renderToJson } from 'enzyme-to-json';
import Button from '..';
@ -17,4 +17,12 @@ describe('Button', () => {
);
expect(renderToJson(wrapper)).toMatchSnapshot();
});
it('have static perperty for type detecting', () => {
const wrapper = mount(
<Button>Button Text</Button>
);
// eslint-disable-next-line
expect(wrapper.type().__ANT_BUTTON).toBe(true);
});
});

View File

@ -46,6 +46,7 @@ export interface ButtonProps {
export default class Button extends React.Component<ButtonProps, any> {
static Group: any;
static __ANT_BUTTON = true;
static defaultProps = {
prefixCls: 'ant-btn',

View File

@ -16,19 +16,20 @@ A loading indicator can be added to a button by setting the `loading` property o
````jsx
import { Button } from 'antd';
const App = React.createClass({
getInitialState() {
return {
class App extends React.Component {
state = {
loading: false,
iconLoading: false,
};
},
enterLoading() {
}
enterLoading = () => {
this.setState({ loading: true });
},
enterIconLoading() {
}
enterIconLoading = () => {
this.setState({ iconLoading: true });
},
}
render() {
return (
<div>
@ -45,10 +46,13 @@ const App = React.createClass({
<Button type="primary" icon="poweroff" loading={this.state.iconLoading} onClick={this.enterIconLoading}>
Click me!
</Button>
<br />
<Button shape="circle" loading />
<Button type="primary" shape="circle" loading />
</div>
);
},
});
}
}
ReactDOM.render(<App />, mountNode);
````

View File

@ -78,20 +78,24 @@
display: none;
}
&&-loading {
&&-loading:before {
display: block;
}
.@{iconfont-css-prefix} {
transition: all .3s @ease-in-out;
}
&&-loading:not(&-circle):not(&-circle-outline) {
padding-left: 29px;
pointer-events: none;
position: relative;
.@{iconfont-css-prefix} {
margin-left: -14px;
transition: all .3s @ease-in-out;
}
&:before {
display: block;
}
}
&-sm&-loading {
&-sm&-loading:not(&-circle):not(&-circle-outline) {
padding-left: 24px;
.@{iconfont-css-prefix} {
margin-left: -17px;
@ -121,12 +125,16 @@
bottom: -1px;
right: -1px;
border-radius: inherit;
border: 0 solid @primary-color;
border: 1.5px solid @primary-color;
opacity: 0.4;
animation: buttonEffect 0.36s ease-out forwards;
animation: buttonEffect 0.4s ease-in-out forwards;
display: block;
}
&-danger&-clicked:after {
border-color: @btn-danger-bg;
}
&-background-ghost {
background: transparent!important;
border-color: #fff;
@ -145,6 +153,5 @@
left: -6px;
bottom: -6px;
right: -6px;
border-width: 6px;
}
}

View File

@ -32,17 +32,16 @@ const options = [{
}],
}];
const CitySwitcher = React.createClass({
getInitialState() {
return {
class CitySwitcher extends React.Component {
state = {
text: 'Unselect',
};
},
onChange(value, selectedOptions) {
onChange = (value, selectedOptions) => {
this.setState({
text: selectedOptions.map(o => o.label).join(', '),
});
},
}
render() {
return (
<span>
@ -53,8 +52,8 @@ const CitySwitcher = React.createClass({
</Cascader>
</span>
);
},
});
}
}
ReactDOM.render(<CitySwitcher />, mountNode);
````

View File

@ -20,14 +20,12 @@ const CheckboxGroup = Checkbox.Group;
const plainOptions = ['Apple', 'Pear', 'Orange'];
const defaultCheckedList = ['Apple', 'Orange'];
const App = React.createClass({
getInitialState() {
return {
class App extends React.Component {
state = {
checkedList: defaultCheckedList,
indeterminate: true,
checkAll: false,
};
},
render() {
return (
<div>
@ -44,22 +42,22 @@ const App = React.createClass({
<CheckboxGroup options={plainOptions} value={this.state.checkedList} onChange={this.onChange} />
</div>
);
},
onChange(checkedList) {
}
onChange = (checkedList) => {
this.setState({
checkedList,
indeterminate: !!checkedList.length && (checkedList.length < plainOptions.length),
checkAll: checkedList.length === plainOptions.length,
});
},
onCheckAllChange(e) {
}
onCheckAllChange = (e) => {
this.setState({
checkedList: e.target.checked ? plainOptions : [],
indeterminate: false,
checkAll: e.target.checked,
});
},
});
}
}
ReactDOM.render(<App />, mountNode);
````

View File

@ -16,13 +16,11 @@ Communicated with other components.
````jsx
import { Checkbox, Button } from 'antd';
const App = React.createClass({
getInitialState() {
return {
class App extends React.Component {
state = {
checked: true,
disabled: false,
};
},
render() {
const label = `${this.state.checked ? 'Checked' : 'Unchecked'}-${this.state.disabled ? 'Disabled' : 'Enabled'}`;
return (
@ -50,20 +48,20 @@ const App = React.createClass({
</p>
</div>
);
},
toggleChecked() {
}
toggleChecked = () => {
this.setState({ checked: !this.state.checked });
},
toggleDisable() {
}
toggleDisable = () => {
this.setState({ disabled: !this.state.disabled });
},
onChange(e) {
}
onChange = (e) => {
console.log('checked = ', e.target.checked);
this.setState({
checked: e.target.checked,
});
},
});
}
}
ReactDOM.render(<App />, mountNode);
````

View File

@ -16,9 +16,11 @@ Disabled checkbox.
````jsx
import { Checkbox } from 'antd';
ReactDOM.render(<div>
ReactDOM.render(
<div>
<Checkbox defaultChecked={false} disabled />
<br />
<Checkbox defaultChecked disabled />
</div>, mountNode);
</div>
, mountNode);
````

View File

@ -4,15 +4,15 @@
@collapse-prefix-cls: ~"@{ant-prefix}-collapse";
.collapse-close() {
.iconfont-size-under-12px(7px, 270deg);
.iconfont-size-under-12px(9px, 0);
}
.collapse-open() {
.iconfont-size-under-12px(7px, 360deg);
.iconfont-size-under-12px(9px, 90deg);
}
.@{collapse-prefix-cls} {
background-color: @background-color-base;
border-radius: 3px;
border-radius: @border-radius-base;
border: @border-width-base @border-style-base @border-color-base;
border-bottom: 0;
@ -25,18 +25,22 @@
color: @text-color;
cursor: pointer;
position: relative;
transition: all .3s;
&:active {
background-color: #eee!important;
}
.arrow {
.collapse-close();
.iconfont-mixin();
position: absolute;
color: @text-color;
color: @text-color-secondary;
display: inline-block;
margin-right: 8px;
font-weight: bold;
line-height: 40px;
content: "\e606";
vertical-align: middle;
transition: transform 0.24s ease;
transition: transform 0.24s;
top: 0;
left: 16px;
/* stylelint-disable declaration-block-no-duplicate-properties */
@ -44,7 +48,7 @@
left: ~"0 \9";
/* stylelint-enable declaration-block-no-duplicate-properties */
&:before {
content: "\e606";
content: "\E61F";
}
}
}
@ -72,7 +76,7 @@
&-item:last-child {
> .@{collapse-prefix-cls}-content {
border-radius: 0 0 3px 3px;
border-radius: 0 0 @border-radius-base @border-radius-base;
}
}

View File

@ -165,7 +165,7 @@ export default class RangePicker extends React.Component<any, any> {
// default width for showTime
const pickerStyle = {} as any;
if (props.showTime) {
pickerStyle.minWidth = 300;
pickerStyle.width = (style && style.width) || 300;
}
const clearIcon = (!props.disabled && props.allowClear && value && (value[0] || value[1]))

View File

@ -18,7 +18,7 @@ exports[`test renders ./components/date-picker/demo/basic.md correctly 1`] = `
<span>
<input
class="ant-calendar-picker-input ant-input"
placeholder="请选择日期"
placeholder="Select month"
readonly=""
value="" />
<span
@ -113,7 +113,7 @@ exports[`test renders ./components/date-picker/demo/disabled-date.md correctly 1
<div>
<span
class="ant-calendar-picker"
style="min-width:154px;">
style="width:154px;">
<span>
<input
class="ant-calendar-picker-input ant-input"
@ -127,7 +127,7 @@ exports[`test renders ./components/date-picker/demo/disabled-date.md correctly 1
<br />
<span
class="ant-calendar-picker"
style="min-width:300px;">
style="width:300px;">
<span
class="ant-calendar-picker-input ant-input">
<input
@ -213,7 +213,7 @@ exports[`test renders ./components/date-picker/demo/format.md correctly 1`] = `
exports[`test renders ./components/date-picker/demo/locale.md correctly 1`] = `
<span
class="ant-calendar-picker"
style="min-width:154px;">
style="width:154px;">
<span>
<input
class="ant-calendar-picker-input ant-input"
@ -255,7 +255,7 @@ exports[`test renders ./components/date-picker/demo/presetted-ranges.md correctl
<br />
<span
class="ant-calendar-picker"
style="min-width:300px;">
style="width:300px;">
<span
class="ant-calendar-picker-input ant-input">
<input
@ -384,7 +384,7 @@ exports[`test renders ./components/date-picker/demo/start-end.md correctly 1`] =
<div>
<span
class="ant-calendar-picker"
style="min-width:154px;">
style="width:154px;">
<span>
<input
class="ant-calendar-picker-input ant-input"
@ -397,7 +397,7 @@ exports[`test renders ./components/date-picker/demo/start-end.md correctly 1`] =
</span>
<span
class="ant-calendar-picker"
style="min-width:154px;">
style="width:154px;">
<span>
<input
class="ant-calendar-picker-input ant-input"
@ -415,7 +415,7 @@ exports[`test renders ./components/date-picker/demo/time.md correctly 1`] = `
<div>
<span
class="ant-calendar-picker"
style="min-width:154px;">
style="width:154px;">
<span>
<input
class="ant-calendar-picker-input ant-input"
@ -429,7 +429,7 @@ exports[`test renders ./components/date-picker/demo/time.md correctly 1`] = `
<br />
<span
class="ant-calendar-picker"
style="min-width:300px;">
style="width:300px;">
<span
class="ant-calendar-picker-input ant-input">
<input

View File

@ -143,7 +143,7 @@ export default function createPicker(TheCalendar) {
// default width for showTime
const pickerStyle = {} as any;
if (props.showTime) {
pickerStyle.minWidth = 154;
pickerStyle.width = (props.style && props.style.width) || 154;
}
const clearIcon = (!props.disabled && props.allowClear && value) ?

View File

@ -25,7 +25,7 @@ ReactDOM.render(
<div>
<DatePicker onChange={onChange} />
<br />
<MonthPicker onChange={onChange} />
<MonthPicker onChange={onChange} placeholder="Select month" />
<br />
<RangePicker onChange={onChange} />
</div>

View File

@ -16,20 +16,18 @@ The default is to close the menu when you click on menu items, this feature can
````jsx
import { Menu, Dropdown, Icon } from 'antd';
const OverlayVisible = React.createClass({
getInitialState() {
return {
class OverlayVisible extends React.Component {
state = {
visible: false,
};
},
handleMenuClick(e) {
handleMenuClick = (e) => {
if (e.key === '3') {
this.setState({ visible: false });
}
},
handleVisibleChange(flag) {
}
handleVisibleChange = (flag) => {
this.setState({ visible: flag });
},
}
render() {
const menu = (
<Menu onClick={this.handleMenuClick}>
@ -48,8 +46,8 @@ const OverlayVisible = React.createClass({
</a>
</Dropdown>
);
},
});
}
}
ReactDOM.render(<OverlayVisible />, mountNode);
````

View File

@ -58,13 +58,14 @@
color: @text-color;
white-space: nowrap;
cursor: pointer;
transition: background 0.3s ease;
transition: all .3s;
> a {
color: @text-color;
display: block;
padding: 7px 16px;
margin: -7px -16px;
transition: all .3s;
}
&:hover {
@ -83,15 +84,18 @@
}
}
&:first-child {
&:first-child,
&:first-child > a {
border-radius: @border-radius-base @border-radius-base 0 0;
}
&:last-child {
&:last-child,
&:last-child > a {
border-radius: 0 0 @border-radius-base @border-radius-base;
}
&:only-child {
&:only-child,
&:only-child > a {
border-radius: @border-radius-base;
}
@ -182,3 +186,31 @@
.iconfont-size-under-12px(10px);
}
}
// https://github.com/ant-design/ant-design/issues/4903
.@{dropdown-prefix-cls}-menu-dark {
&,
.@{dropdown-prefix-cls}-menu {
background: @menu-dark-bg;
}
.@{dropdown-prefix-cls}-menu-item,
.@{dropdown-prefix-cls}-menu-submenu-title,
.@{dropdown-prefix-cls}-menu-item > a {
color: @text-color-secondary-dark;
&:after {
color: @text-color-secondary-dark;
}
&:hover {
color: #fff;
background: transparent;
}
}
.@{dropdown-prefix-cls}-menu-item-selected {
&,
&:hover,
> a {
background: @primary-color;
color: #fff;
}
}
}

View File

@ -1086,7 +1086,7 @@ exports[`test renders ./components/form/demo/time-related-controls.md correctly
class="ant-form-item-control ">
<span
class="ant-calendar-picker"
style="min-width:154px;">
style="width:154px;">
<span>
<input
class="ant-calendar-picker-input ant-input ant-input-lg"
@ -1184,7 +1184,7 @@ exports[`test renders ./components/form/demo/time-related-controls.md correctly
class="ant-form-item-control ">
<span
class="ant-calendar-picker"
style="min-width:300px;">
style="width:300px;">
<span
class="ant-calendar-picker-input ant-input ant-input-lg">
<input
@ -1466,7 +1466,7 @@ exports[`test renders ./components/form/demo/validate-other.md correctly 1`] = `
<div
class="ant-slider-rail" />
<div
class="ant-slider-track ant-slider-track-1"
class="ant-slider-track"
style="visibility:visible;left:0%;width:0%;" />
<div
class="ant-slider-step">
@ -1490,7 +1490,7 @@ exports[`test renders ./components/form/demo/validate-other.md correctly 1`] = `
style="left:100%;" />
</div>
<div
class="ant-slider-handle ant-slider-handle-2 ant-slider-handle-upper"
class="ant-slider-handle"
style="left:0%;" />
<div
class="ant-slider-mark">

View File

@ -18,21 +18,21 @@ import { Form, Select, Input, Button } from 'antd';
const FormItem = Form.Item;
const Option = Select.Option;
const App = Form.create()(React.createClass({
handleSubmit(e) {
class App extends React.Component {
handleSubmit = (e) => {
e.preventDefault();
this.props.form.validateFields((err, values) => {
if (!err) {
console.log('Received values of form: ', values);
}
});
},
handleSelectChange(value) {
}
handleSelectChange = (value) => {
console.log(value);
this.props.form.setFieldsValue({
note: `Hi, ${value === 'male' ? 'man' : 'lady'}!`,
});
},
}
render() {
const { getFieldDecorator } = this.props.form;
return (
@ -70,8 +70,10 @@ const App = Form.create()(React.createClass({
</FormItem>
</Form>
);
},
}));
}
}
ReactDOM.render(<App />, mountNode);
const WrappedApp = Form.create()(App);
ReactDOM.render(<WrappedApp />, mountNode);
````

View File

@ -23,22 +23,24 @@ import { Form, Input, Select, Button } from 'antd';
const FormItem = Form.Item;
const Option = Select.Option;
const PriceInput = React.createClass({
getInitialState() {
class PriceInput extends React.Component {
constructor(props) {
super(props);
const value = this.props.value || {};
return {
this.state = {
number: value.number || 0,
currency: value.currency || 'rmb',
};
},
}
componentWillReceiveProps(nextProps) {
// Should be a controlled component.
if ('value' in nextProps) {
const value = nextProps.value;
this.setState(value);
}
},
handleNumberChange(e) {
}
handleNumberChange = (e) => {
const number = parseInt(e.target.value || 0, 10);
if (isNaN(number)) {
return;
@ -47,20 +49,20 @@ const PriceInput = React.createClass({
this.setState({ number });
}
this.triggerChange({ number });
},
handleCurrencyChange(currency) {
}
handleCurrencyChange = (currency) => {
if (!('value' in this.props)) {
this.setState({ currency });
}
this.triggerChange({ currency });
},
triggerChange(changedValue) {
}
triggerChange = (changedValue) => {
// Should provide an event to pass value to Form.
const onChange = this.props.onChange;
if (onChange) {
onChange(Object.assign({}, this.state, changedValue));
}
},
}
render() {
const { size } = this.props;
const state = this.state;
@ -84,25 +86,25 @@ const PriceInput = React.createClass({
</Select>
</span>
);
},
});
}
}
const Demo = Form.create()(React.createClass({
handleSubmit(e) {
class Demo extends React.Component {
handleSubmit = (e) => {
e.preventDefault();
this.props.form.validateFields((err, values) => {
if (!err) {
console.log('Received values of form: ', values);
}
});
},
checkPrice(rule, value, callback) {
}
checkPrice = (rule, value, callback) => {
if (value.number > 0) {
callback();
return;
}
callback('Price must greater than zero!');
},
}
render() {
const { getFieldDecorator } = this.props.form;
return (
@ -118,8 +120,10 @@ const Demo = Form.create()(React.createClass({
</FormItem>
</Form>
);
},
}));
}
}
ReactDOM.render(<Demo />, mountNode);
const WrappedDemo = Form.create()(Demo);
ReactDOM.render(<WrappedDemo />, mountNode);
````

View File

@ -56,17 +56,17 @@ const CollectionCreateForm = Form.create()(
}
);
const CollectionsPage = React.createClass({
getInitialState() {
return { visible: false };
},
showModal() {
class CollectionsPage extends React.Component {
state = {
visible: false,
};
showModal = () => {
this.setState({ visible: true });
},
handleCancel() {
}
handleCancel = () => {
this.setState({ visible: false });
},
handleCreate() {
}
handleCreate = () => {
const form = this.form;
form.validateFields((err, values) => {
if (err) {
@ -77,10 +77,10 @@ const CollectionsPage = React.createClass({
form.resetFields();
this.setState({ visible: false });
});
},
saveFormRef(form) {
}
saveFormRef = (form) => {
this.form = form;
},
}
render() {
return (
<div>
@ -93,8 +93,8 @@ const CollectionsPage = React.createClass({
/>
</div>
);
},
});
}
}
ReactDOM.render(<CollectionsPage />, mountNode);
````

View File

@ -45,21 +45,19 @@ const CustomizedForm = Form.create({
);
});
const Demo = React.createClass({
getInitialState() {
return {
class Demo extends React.Component {
state = {
fields: {
username: {
value: 'benjycui',
},
},
};
},
handleFormChange(changedFields) {
handleFormChange = (changedFields) => {
this.setState({
fields: { ...this.state.fields, ...changedFields },
});
},
}
render() {
const fields = this.state.fields;
return (
@ -70,8 +68,8 @@ const Demo = React.createClass({
</pre>
</div>
);
},
});
}
}
ReactDOM.render(<Demo />, mountNode);
````

View File

@ -21,19 +21,19 @@ function hasErrors(fieldsError) {
return Object.keys(fieldsError).some(field => fieldsError[field]);
}
const HorizontalLoginForm = Form.create()(React.createClass({
class HorizontalLoginForm extends React.Component {
componentDidMount() {
// To disabled submit button at the beginning.
this.props.form.validateFields();
},
handleSubmit(e) {
}
handleSubmit = (e) => {
e.preventDefault();
this.props.form.validateFields((err, values) => {
if (!err) {
console.log('Received values of form: ', values);
}
});
},
}
render() {
const { getFieldDecorator, getFieldsError, getFieldError, isFieldTouched } = this.props.form;
@ -73,8 +73,10 @@ const HorizontalLoginForm = Form.create()(React.createClass({
</FormItem>
</Form>
);
},
}));
}
}
ReactDOM.render(<HorizontalLoginForm />, mountNode);
const WrappedHorizontalLoginForm = Form.create()(HorizontalLoginForm);
ReactDOM.render(<WrappedHorizontalLoginForm />, mountNode);
````

View File

@ -17,15 +17,15 @@ Normal login form which can contain more elements.
import { Form, Icon, Input, Button, Checkbox } from 'antd';
const FormItem = Form.Item;
const NormalLoginForm = Form.create()(React.createClass({
handleSubmit(e) {
class NormalLoginForm extends React.Component {
handleSubmit = (e) => {
e.preventDefault();
this.props.form.validateFields((err, values) => {
if (!err) {
console.log('Received values of form: ', values);
}
});
},
}
render() {
const { getFieldDecorator } = this.props.form;
return (
@ -59,10 +59,12 @@ const NormalLoginForm = Form.create()(React.createClass({
</FormItem>
</Form>
);
},
}));
}
}
ReactDOM.render(<NormalLoginForm />, mountNode);
const WrappedNormalLoginForm = Form.create()(NormalLoginForm);
ReactDOM.render(<WrappedNormalLoginForm />, mountNode);
````
```css

View File

@ -42,39 +42,37 @@ const residences = [{
}],
}];
const RegistrationForm = Form.create()(React.createClass({
getInitialState() {
return {
class RegistrationForm extends React.Component {
state = {
passwordDirty: false,
};
},
handleSubmit(e) {
handleSubmit = (e) => {
e.preventDefault();
this.props.form.validateFieldsAndScroll((err, values) => {
if (!err) {
console.log('Received values of form: ', values);
}
});
},
handlePasswordBlur(e) {
}
handlePasswordBlur = (e) => {
const value = e.target.value;
this.setState({ passwordDirty: this.state.passwordDirty || !!value });
},
checkPassword(rule, value, callback) {
}
checkPassword = (rule, value, callback) => {
const form = this.props.form;
if (value && value !== form.getFieldValue('password')) {
callback('Two passwords that you enter is inconsistent!');
} else {
callback();
}
},
checkConfirm(rule, value, callback) {
}
checkConfirm = (rule, value, callback) => {
const form = this.props.form;
if (value && this.state.passwordDirty) {
form.validateFields(['confirm'], { force: true });
}
callback();
},
}
render() {
const { getFieldDecorator } = this.props.form;
const formItemLayout = {
@ -210,10 +208,12 @@ const RegistrationForm = Form.create()(React.createClass({
</FormItem>
</Form>
);
},
}));
}
}
ReactDOM.render(<RegistrationForm />, mountNode);
const WrappedRegistrationForm = Form.create()(RegistrationForm);
ReactDOM.render(<WrappedRegistrationForm />, mountNode);
````
````css

View File

@ -19,8 +19,8 @@ const FormItem = Form.Item;
const MonthPicker = DatePicker.MonthPicker;
const RangePicker = DatePicker.RangePicker;
const TimeRelatedForm = Form.create()(React.createClass({
handleSubmit(e) {
class TimeRelatedForm extends React.Component {
handleSubmit = (e) => {
e.preventDefault();
this.props.form.validateFields((err, fieldsValue) => {
@ -45,7 +45,7 @@ const TimeRelatedForm = Form.create()(React.createClass({
};
console.log('Received values of form: ', values);
});
},
}
render() {
const { getFieldDecorator } = this.props.form;
const formItemLayout = {
@ -113,8 +113,10 @@ const TimeRelatedForm = Form.create()(React.createClass({
</FormItem>
</Form>
);
},
}));
}
}
ReactDOM.render(<TimeRelatedForm />, mountNode);
const WrappedTimeRelatedForm = Form.create()(TimeRelatedForm);
ReactDOM.render(<WrappedTimeRelatedForm />, mountNode);
````

View File

@ -23,23 +23,21 @@ const Option = Select.Option;
const RadioButton = Radio.Button;
const RadioGroup = Radio.Group;
const Demo = Form.create()(React.createClass({
handleSubmit(e) {
class Demo extends React.Component {
handleSubmit = (e) => {
e.preventDefault();
this.props.form.validateFields((err, values) => {
if (!err) {
console.log('Received values of form: ', values);
}
});
},
normFile(e) {
}
normFile = (e) => {
if (Array.isArray(e)) {
return e;
}
return e && e.fileList;
},
}
render() {
const { getFieldDecorator } = this.props.form;
const formItemLayout = {
@ -149,7 +147,7 @@ const Demo = Form.create()(React.createClass({
>
{getFieldDecorator('upload', {
valuePropName: 'fileList',
normalize: this.normFile,
getValueFromEvent: this.normFile,
})(
<Upload name="logo" action="/upload.do" listType="picture" onChange={this.handleUpload}>
<Button>
@ -164,8 +162,10 @@ const Demo = Form.create()(React.createClass({
</FormItem>
</Form>
);
},
}));
}
}
ReactDOM.render(<Demo />, mountNode);
const WrappedDemo = Form.create()(Demo);
ReactDOM.render(<WrappedDemo />, mountNode);
````

View File

@ -1,25 +1,25 @@
---
order: 10
title:
zh-CN: 校验提示
en-US: Validation message
zh-CN: 自定义校验
en-US: Customized Validation
---
## zh-CN
我们为表单控件定义了三种校验状态,为 `<FormItem>` 定义 `validateStatus` 属性即可
我们提供了 `validateStatus` `help` `hasFeedback` 等属性,你可以不需要使用 `Form.create``getFieldDecorator`,自己定义校验的时机和内容
validateStatus: 'success', 'warning', 'error', 'validating'。
另外为输入框添加反馈图标,设置 `<FormItem>``hasFeedback` 属性值为 `true` 即可
1. `validateStatus`: 校验状态,可选 'success', 'warning', 'error', 'validating'。
2. `hasFeedback`:用于给输入框添加反馈图标。
3. `help`:设置校验文案
## en-US
We provide three kinds of validation status for form. You can use it just define `validateStatus` property on `<FormItem>`.
We provide properties like `validateStatus` `help` `hasFeedback` to customize your own validate status and message, without using `Form.create` and `getFieldDecorator`.
validateStatus: 'success', 'warning', 'error', 'validating'
To set `hasFeedback` property to `true` enable to display feed icon of input control.
1. `validateStatus`: validate status of form components which could be 'success', 'warning', 'error', 'validating'.
2. `hasFeedback`: display feed icon of input control
3. `help`: display validate message.
````jsx
import { Form, Input, DatePicker, Col } from 'antd';

View File

@ -36,7 +36,6 @@ class RawForm extends React.Component {
value: 11,
},
};
handleNumberChange = (value) => {
this.setState({
number: {
@ -45,7 +44,6 @@ class RawForm extends React.Component {
},
});
}
render() {
const formItemLayout = {
labelCol: { span: 7 },

View File

@ -6,6 +6,7 @@
@import "./mixin";
@form-prefix-cls: ~"@{ant-prefix}-form";
@form-component-height: @input-height-lg;
.reset-form();
@ -75,7 +76,7 @@ input[type="checkbox"] {
}
&-control {
line-height: 32px;
line-height: @form-component-height;
position: relative;
.clearfix;
}
@ -87,7 +88,7 @@ input[type="checkbox"] {
&-label {
text-align: right;
vertical-align: middle;
padding: 7px 0;
line-height: @form-component-height;
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;

View File

@ -385,7 +385,7 @@ exports[`test renders ./components/grid/demo/playground.md correctly 1`] = `
<div
class="ant-slider-rail" />
<div
class="ant-slider-track ant-slider-track-1"
class="ant-slider-track"
style="visibility:visible;left:0%;width:20%;" />
<div
class="ant-slider-step">
@ -409,7 +409,7 @@ exports[`test renders ./components/grid/demo/playground.md correctly 1`] = `
style="left:100%;" />
</div>
<div
class="ant-slider-handle ant-slider-handle-2 ant-slider-handle-upper"
class="ant-slider-handle"
style="left:20%;" />
<div
class="ant-slider-mark">
@ -457,7 +457,7 @@ exports[`test renders ./components/grid/demo/playground.md correctly 1`] = `
<div
class="ant-slider-rail" />
<div
class="ant-slider-track ant-slider-track-1"
class="ant-slider-track"
style="visibility:visible;left:0%;width:40%;" />
<div
class="ant-slider-step">
@ -481,7 +481,7 @@ exports[`test renders ./components/grid/demo/playground.md correctly 1`] = `
style="left:100%;" />
</div>
<div
class="ant-slider-handle ant-slider-handle-2 ant-slider-handle-upper"
class="ant-slider-handle"
style="left:40%;" />
<div
class="ant-slider-mark">

View File

@ -72,8 +72,8 @@
text-align: left;
outline: 0;
-moz-appearance: textfield;
line-height: 26px;
height: 26px;
line-height: @input-height-base - 2px;
height: @input-height-base - 2px;
transition: all 0.3s linear;
color: @text-color;
border: 0;
@ -87,48 +87,19 @@
&-lg {
padding: 0;
.@{input-number-prefix-cls}-handler {
height: 16px;
}
input {
height: 30px;
line-height: 30px;
}
.@{input-number-prefix-cls}-handler-up-inner {
top: 2px;
}
.@{input-number-prefix-cls}-handler-down-inner {
bottom: 2px;
}
.@{input-number-prefix-cls}-handler-up:hover {
height: 18px;
height: @input-height-lg - 2px;
line-height: @input-height-lg - 2px;
}
}
&-sm {
padding: 0;
.@{input-number-prefix-cls}-handler {
height: 11px;
}
input {
height: 20px;
line-height: 20px;
}
.@{input-number-prefix-cls}-handler-up-inner {
top: -1px;
}
.@{input-number-prefix-cls}-handler-down-inner {
bottom: -1px;
}
.@{input-number-prefix-cls}-handler-up:hover {
height: 13px;
}
.@{input-number-prefix-cls}-handler-down:hover .@{input-number-prefix-cls}-handler-down-inner {
bottom: 4px;
height: @input-height-sm - 2px;
line-height: @input-height-sm - 2px;
}
}
@ -145,6 +116,10 @@
transition: opacity 0.24s linear 0.1s;
}
&-handler-wrap:hover &-handler {
height: 40%;
}
&:hover &-handler-wrap {
opacity: 1;
}
@ -152,17 +127,15 @@
&-handler-up {
cursor: pointer;
&-inner {
top: 1px;
top: 50%;
margin-top: -6px;
&:before {
text-align: center;
content: "\e61e";
}
}
&:hover {
height: 16px;
}
&:hover &-inner {
margin-top: 2px;
height: 60%!important;
}
}
@ -171,14 +144,15 @@
top: -1px;
cursor: pointer;
&-inner {
top: 50%;
margin-top: -6px;
&:before {
text-align: center;
content: "\e61d";
}
}
&:hover {
height: 16px;
margin-top: -2px;
height: 60%!important;
}
}

View File

@ -405,15 +405,11 @@ exports[`test renders ./components/input/demo/textarea.md correctly 1`] = `
`;
exports[`test renders ./components/input/demo/tooltip.md correctly 1`] = `
<div
class="numeric-input-demo">
<div>
<input
<input
class="ant-input"
maxlength="25"
placeholder="input a number"
placeholder="Input a number"
style="width:120px;"
type="text"
value="" />
</div>
</div>
`;

View File

@ -40,26 +40,24 @@ class NumericInput extends React.Component {
this.props.onChange(value);
}
}
// '.' at the end or only '-' in the input box.
onBlur = () => {
const { value } = this.props;
const { value, onBlur, onChange } = this.props;
if (value.charAt(value.length - 1) === '.' || value === '-') {
this.props.onChange({ value: value.slice(0, -1) });
onChange({ value: value.slice(0, -1) });
}
if (this.props.onBlur) {
this.props.onBlur();
if (onBlur) {
onBlur();
}
}
render() {
const { value } = this.props;
const title = (value ?
(<span className="numeric-input-title">
const title = value ? (
<span className="numeric-input-title">
{value !== '-' ? formatNumber(value) : '-'}
</span>) : '');
</span>
) : 'Input a number';
return (
<div>
<Tooltip
trigger={['focus']}
title={title}
@ -70,11 +68,10 @@ class NumericInput extends React.Component {
{...this.props}
onChange={this.onChange}
onBlur={this.onBlur}
placeholder="input a number"
placeholder="Input a number"
maxLength="25"
/>
</Tooltip>
</div>
);
}
}
@ -88,12 +85,7 @@ class NumericInputDemo extends React.Component {
this.setState({ value });
}
render() {
const { value } = this.state;
return (
<div className="numeric-input-demo">
<NumericInput value={value} onChange={this.onChange} />
</div>
);
return <NumericInput style={{ width: 120 }} value={this.state.value} onChange={this.onChange} />;
}
}
@ -111,8 +103,4 @@ or the height is not enough when content is empty */
.numeric-input .numeric-input-title {
font-size: 14px;
}
.numeric-input-demo {
width: 120px;
}
````

View File

@ -81,6 +81,7 @@ export default class Sider extends React.Component<SiderProps, any> {
const divStyle = {
...style,
flex: `0 0 ${this.state.collapsed ? collapsedWidth : width}px`,
width: `${this.state.collapsed ? collapsedWidth : width}px`,
};
const iconObj = {
'expanded': reverseArrow ? <Icon type="right" /> : <Icon type="left" />,

View File

@ -25,7 +25,7 @@ exports[`test renders ./components/layout/demo/basic.md correctly 1`] = `
class="ant-layout ant-layout-has-sider">
<div
class="ant-layout-sider"
style="flex:0 0 200px;">
style="flex:0 0 200px;width:200px;">
Sider
</div>
<div
@ -52,7 +52,7 @@ exports[`test renders ./components/layout/demo/basic.md correctly 1`] = `
</div>
<div
class="ant-layout-sider"
style="flex:0 0 200px;">
style="flex:0 0 200px;width:200px;">
Sider
</div>
</div>
@ -65,7 +65,7 @@ exports[`test renders ./components/layout/demo/basic.md correctly 1`] = `
class="ant-layout ant-layout-has-sider">
<div
class="ant-layout-sider"
style="flex:0 0 200px;">
style="flex:0 0 200px;width:200px;">
Sider
</div>
<div
@ -92,7 +92,7 @@ exports[`test renders ./components/layout/demo/custom-trigger.md correctly 1`] =
class="ant-layout ant-layout-has-sider">
<div
class="ant-layout-sider"
style="flex:0 0 200px;">
style="flex:0 0 200px;width:200px;">
<div
class="logo" />
<ul
@ -160,7 +160,7 @@ exports[`test renders ./components/layout/demo/side.md correctly 1`] = `
class="ant-layout ant-layout-has-sider">
<div
class="ant-layout-sider"
style="flex:0 0 200px;">
style="flex:0 0 200px;width:200px;">
<div
class="logo" />
<ul
@ -169,75 +169,53 @@ exports[`test renders ./components/layout/demo/side.md correctly 1`] = `
role="menu"
tabindex="0">
<li
aria-selected="true"
class="ant-menu-item-selected ant-menu-item"
role="menuitem"
class="ant-menu-submenu-inline ant-menu-submenu">
<div
aria-expanded="false"
aria-haspopup="true"
aria-owns="sub1$Menu"
class="ant-menu-submenu-title"
style="padding-left:24px;">
<span>
<i
class="anticon anticon-user" />
<span
class="nav-text">
nav 1
User
</span>
</span>
</div>
</li>
<li
aria-selected="false"
class="ant-menu-item"
role="menuitem"
style="padding-left:24px;">
<i
class="anticon anticon-video-camera" />
<span
class="nav-text">
nav 2
</span>
</li>
<li
aria-selected="false"
class="ant-menu-item"
role="menuitem"
style="padding-left:24px;">
<i
class="anticon anticon-upload" />
<span
class="nav-text">
nav 3
</span>
</li>
<li
aria-selected="false"
class="ant-menu-item"
role="menuitem"
style="padding-left:24px;">
<i
class="anticon anticon-user" />
<span
class="nav-text">
nav 4
</span>
</li>
<li
aria-selected="false"
class="ant-menu-item"
role="menuitem"
style="padding-left:24px;">
<i
class="anticon anticon-heart-o" />
<span
class="nav-text">
nav 5
</span>
</li>
<li
aria-selected="false"
class="ant-menu-item"
role="menuitem"
class="ant-menu-submenu-inline ant-menu-submenu">
<div
aria-expanded="false"
aria-haspopup="true"
aria-owns="sub2$Menu"
class="ant-menu-submenu-title"
style="padding-left:24px;">
<span>
<i
class="anticon anticon-team" />
<span
class="nav-text">
nav 6
Team
</span>
</span>
</div>
</li>
<li
aria-selected="true"
class="ant-menu-item-selected ant-menu-item"
role="menuitem"
style="padding-left:24px;">
<span>
<i
class="anticon anticon-file" />
<span
class="nav-text">
File
</span>
</span>
</li>
</ul>
@ -261,7 +239,7 @@ exports[`test renders ./components/layout/demo/side.md correctly 1`] = `
<span>
<span
class="ant-breadcrumb-link">
Home
User
</span>
<span
class="ant-breadcrumb-separator">
@ -271,17 +249,7 @@ exports[`test renders ./components/layout/demo/side.md correctly 1`] = `
<span>
<span
class="ant-breadcrumb-link">
List
</span>
<span
class="ant-breadcrumb-separator">
/
</span>
</span>
<span>
<span
class="ant-breadcrumb-link">
App
Bill
</span>
<span
class="ant-breadcrumb-separator">
@ -291,7 +259,7 @@ exports[`test renders ./components/layout/demo/side.md correctly 1`] = `
</div>
<div
style="padding:24px;background:#fff;min-height:360px;">
content
Bill is a cat.
</div>
</div>
<div
@ -461,7 +429,7 @@ exports[`test renders ./components/layout/demo/top-side.md correctly 1`] = `
style="padding:24px 0;background:#fff;">
<div
class="ant-layout-sider"
style="background:#fff;flex:0 0 200px;">
style="background:#fff;flex:0 0 200px;width:200px;">
<ul
aria-activedescendant=""
class="ant-menu ant-menu-inline ant-menu-light ant-menu-root"

View File

@ -16,14 +16,19 @@ Be used in the two-columns layout.
````jsx
import { Layout, Menu, Breadcrumb, Icon } from 'antd';
const { Header, Content, Footer, Sider } = Layout;
const SubMenu = Menu.SubMenu;
class SiderDemo extends React.Component {
state = {
collapsed: false,
mode: 'inline',
};
onCollapse = (collapsed) => {
console.log(collapsed);
this.setState({ collapsed });
this.setState({
collapsed,
mode: collapsed ? 'vertical' : 'inline',
});
}
render() {
return (
@ -34,30 +39,27 @@ class SiderDemo extends React.Component {
onCollapse={this.onCollapse}
>
<div className="logo" />
<Menu theme="dark" mode="inline" defaultSelectedKeys={['1']}>
<Menu.Item key="1">
<Icon type="user" />
<span className="nav-text">nav 1</span>
</Menu.Item>
<Menu.Item key="2">
<Icon type="video-camera" />
<span className="nav-text">nav 2</span>
</Menu.Item>
<Menu.Item key="3">
<Icon type="upload" />
<span className="nav-text">nav 3</span>
</Menu.Item>
<Menu.Item key="4">
<Icon type="user" />
<span className="nav-text">nav 4</span>
</Menu.Item>
<Menu.Item key="5">
<Icon type="heart-o" />
<span className="nav-text">nav 5</span>
</Menu.Item>
<Menu theme="dark" mode={this.state.mode} defaultSelectedKeys={['6']}>
<SubMenu
key="sub1"
title={<span><Icon type="user" /><span className="nav-text">User</span></span>}
>
<Menu.Item key="1">Tom</Menu.Item>
<Menu.Item key="2">Bill</Menu.Item>
<Menu.Item key="3">Alex</Menu.Item>
</SubMenu>
<SubMenu
key="sub2"
title={<span><Icon type="team" /><span className="nav-text">Team</span></span>}
>
<Menu.Item key="4">Team 1</Menu.Item>
<Menu.Item key="5">Team 2</Menu.Item>
</SubMenu>
<Menu.Item key="6">
<Icon type="team" />
<span className="nav-text">nav 6</span>
<span>
<Icon type="file" />
<span className="nav-text">File</span>
</span>
</Menu.Item>
</Menu>
</Sider>
@ -65,12 +67,11 @@ class SiderDemo extends React.Component {
<Header style={{ background: '#fff', padding: 0 }} />
<Content style={{ margin: '0 16px' }}>
<Breadcrumb style={{ margin: '12px 0' }}>
<Breadcrumb.Item>Home</Breadcrumb.Item>
<Breadcrumb.Item>List</Breadcrumb.Item>
<Breadcrumb.Item>App</Breadcrumb.Item>
<Breadcrumb.Item>User</Breadcrumb.Item>
<Breadcrumb.Item>Bill</Breadcrumb.Item>
</Breadcrumb>
<div style={{ padding: 24, background: '#fff', minHeight: 360 }}>
content
Bill is a cat.
</div>
</Content>
<Footer style={{ textAlign: 'center' }}>
@ -100,4 +101,8 @@ ReactDOM.render(<SiderDemo />, mountNode);
#components-layout-demo-side .ant-layout-sider-collapsed .nav-text {
display: none;
}
#components-layout-demo-side .ant-layout-sider-collapsed .ant-menu-submenu-vertical > .ant-menu-submenu-title:after {
display: none;
}
````

View File

@ -37,8 +37,6 @@
}
&-sider {
flex: 0 0 200px;
overflow: hidden;
transition: all .3s @ease-out;
position: relative;
background: @layout-sider-background;
@ -51,10 +49,6 @@
order: 1;
}
&-collapsed {
flex: 0 0 64px;
}
&-trigger {
position: absolute;
text-align: center;

View File

@ -126,7 +126,7 @@ exports[`test renders ./components/locale-provider/demo/all.md correctly 1`] = `
<div
class="example">
<div
class="ant-select-show-search ant-select ant-select-enabled"
class="ant-select ant-select-enabled"
style="width:200px;">
<div
aria-autocomplete="list"
@ -1146,7 +1146,7 @@ exports[`test renders ./components/locale-provider/demo/all.md correctly 1`] = `
<div
class="example">
<div
class=" clearfix">
class="ant-table-wrapper">
<div
class="ant-spin-nested-loading">
<div
@ -1155,9 +1155,6 @@ exports[`test renders ./components/locale-provider/demo/all.md correctly 1`] = `
class="ant-table ant-table-large ant-table-empty ant-table-scroll-position-left">
<div
class="ant-table-content">
<div
class="">
<span>
<div
class="ant-table-body">
<table
@ -1190,7 +1187,6 @@ exports[`test renders ./components/locale-provider/demo/all.md correctly 1`] = `
class="ant-table-tbody" />
</table>
</div>
</span>
<div
class="ant-table-placeholder">
No Data
@ -1202,7 +1198,6 @@ exports[`test renders ./components/locale-provider/demo/all.md correctly 1`] = `
</div>
</div>
</div>
</div>
</div>
`;

View File

@ -46,7 +46,7 @@ describe('Menu', () => {
it('should accept openKeys in mode horizontal', () => {
const wrapper = mount(
<Menu openKeys={['1']} mode="horizontal">
<Menu openKeys={['1']} mode="horizontal" openTransitionName="">
<SubMenu key="1" title="submenu1">
<Menu.Item key="submenu1">Option 1</Menu.Item>
<Menu.Item key="submenu2">Option 2</Menu.Item>
@ -55,11 +55,15 @@ describe('Menu', () => {
</Menu>
);
expect(wrapper.find('.ant-menu-sub').at(0).hasClass('ant-menu-hidden')).not.toBe(true);
wrapper.setProps({ openKeys: [] });
expect(wrapper.find('.ant-menu-sub').at(0).hasClass('ant-menu-hidden')).toBe(true);
wrapper.setProps({ openKeys: ['1'] });
expect(wrapper.find('.ant-menu-sub').at(0).hasClass('ant-menu-hidden')).not.toBe(true);
});
it('should accept openKeys in mode inline', () => {
it.only('should accept openKeys in mode inline', () => {
const wrapper = mount(
<Menu openKeys={['1']} mode="inline">
<Menu openKeys={['1']} mode="inline" openAnimation="">
<SubMenu key="1" title="submenu1">
<Menu.Item key="submenu1">Option 1</Menu.Item>
<Menu.Item key="submenu2">Option 2</Menu.Item>
@ -68,11 +72,15 @@ describe('Menu', () => {
</Menu>
);
expect(wrapper.find('.ant-menu-sub').at(0).hasClass('ant-menu-hidden')).not.toBe(true);
wrapper.setProps({ openKeys: [] });
expect(wrapper.find('.ant-menu-sub').at(0).hasClass('ant-menu-hidden')).toBe(true);
wrapper.setProps({ openKeys: ['1'] });
expect(wrapper.find('.ant-menu-sub').at(0).hasClass('ant-menu-hidden')).not.toBe(true);
});
it('should accept openKeys in mode vertical', () => {
const wrapper = mount(
<Menu openKeys={['1']} mode="vertical">
<Menu openKeys={['1']} mode="vertical" openTransitionName="">
<SubMenu key="1" title="submenu1">
<Menu.Item key="submenu1">Option 1</Menu.Item>
<Menu.Item key="submenu2">Option 2</Menu.Item>
@ -81,6 +89,10 @@ describe('Menu', () => {
</Menu>
);
expect(wrapper.find('.ant-menu-sub').at(0).hasClass('ant-menu-hidden')).not.toBe(true);
wrapper.setProps({ openKeys: [] });
expect(wrapper.find('.ant-menu-sub').at(0).hasClass('ant-menu-hidden')).toBe(true);
wrapper.setProps({ openKeys: ['1'] });
expect(wrapper.find('.ant-menu-sub').at(0).hasClass('ant-menu-hidden')).not.toBe(true);
});
// https://github.com/ant-design/ant-design/pulls/4677
@ -98,4 +110,21 @@ describe('Menu', () => {
wrapper.update();
// just expect no error emit
});
it('should always follow openKeys when mode is switched', () => {
const wrapper = mount(
<Menu openKeys={['1']} mode="inline">
<SubMenu key="1" title="submenu1">
<Menu.Item key="submenu1">Option 1</Menu.Item>
<Menu.Item key="submenu2">Option 2</Menu.Item>
</SubMenu>
<Menu.Item key="2">menu2</Menu.Item>
</Menu>
);
expect(wrapper.find('.ant-menu-sub').at(0).hasClass('ant-menu-hidden')).not.toBe(true);
wrapper.setProps({ mode: 'vertical' });
expect(wrapper.find('.ant-menu-sub').at(0).hasClass('ant-menu-hidden')).not.toBe(true);
wrapper.setProps({ mode: 'inline' });
expect(wrapper.find('.ant-menu-sub').at(0).hasClass('ant-menu-hidden')).not.toBe(true);
});
});

View File

@ -19,31 +19,24 @@ const SubMenu = Menu.SubMenu;
const MenuItemGroup = Menu.ItemGroup;
const Sider = React.createClass({
getInitialState() {
return {
current: '1',
};
},
handleClick(e) {
console.log('click ', e);
this.setState({
current: e.key,
});
},
render() {
return (
<Menu onClick={this.handleClick}
<Menu
onClick={this.handleClick}
style={{ width: 240 }}
defaultSelectedKeys={['1']}
defaultOpenKeys={['sub1']}
selectedKeys={[this.state.current]}
mode="inline"
>
<SubMenu key="sub1" title={<span><Icon type="mail" /><span>Navigation One</span></span>}>
<MenuItemGroup title="Item 1">
<MenuItemGroup key="g1" title="Item 1">
<Menu.Item key="1">Option 1</Menu.Item>
<Menu.Item key="2">Option 2</Menu.Item>
</MenuItemGroup>
<MenuItemGroup title="Item 2">
<MenuItemGroup key="g2" title="Item 2">
<Menu.Item key="3">Option 3</Menu.Item>
<Menu.Item key="4">Option 4</Menu.Item>
</MenuItemGroup>
@ -66,5 +59,6 @@ const Sider = React.createClass({
);
},
});
ReactDOM.render(<Sider />, mountNode);
````

View File

@ -88,7 +88,7 @@ export default class Menu extends React.Component<MenuProps, any> {
this.switchModeFromInline = true;
}
if ('openKeys' in nextProps) {
this.setOpenKeys(nextProps.openKeys);
this.setState({ openKeys: nextProps.openKeys });
}
}
handleClick = (e) => {
@ -114,7 +114,7 @@ export default class Menu extends React.Component<MenuProps, any> {
}
render() {
let openAnimation = this.props.openAnimation || this.props.openTransitionName;
if (!openAnimation) {
if (this.props.openAnimation === undefined && this.props.openTransitionName === undefined) {
switch (this.props.mode) {
case 'horizontal':
openAnimation = 'slide-up';

View File

@ -38,6 +38,11 @@
transition: all 0.3s ease;
}
&-item:active,
&-submenu-title:active {
background: @primary-1;
}
&-submenu &-sub {
cursor: initial;
}
@ -70,6 +75,7 @@
&-item:hover,
&-item-active,
&-submenu-open,
&-submenu-active,
&-submenu-title:hover {
color: @primary-color;
@ -110,7 +116,7 @@
&-vertical {
border-right: @border-width-base @border-style-base @border-color-split;
.@{menu-prefix-cls}-item {
border-right: @border-width-base @border-style-base @border-color-split;
border-right: 3px @border-style-base transparent;
margin-left: -1px;
left: 1px;
position: relative;
@ -118,17 +124,26 @@
}
}
&-vertical &-sub {
&-vertical&-sub {
border-right: 0;
.@{menu-prefix-cls}-item {
border-right: 0;
margin-left: 0;
left: 0;
}
> .@{menu-prefix-cls}-item:first-child {
border-radius: @border-radius-base @border-radius-base 0 0;
}
> .@{menu-prefix-cls}-item:last-child,
> .@{menu-prefix-cls}-item-group:last-child > .@{menu-prefix-cls}-item-group-list:last-child > .@{menu-prefix-cls}-item:last-child {
border-radius: 0 0 @border-radius-base @border-radius-base;
}
}
&-inline {
.@{menu-prefix-cls}-selected,
.@{menu-prefix-cls}-item-selected {
border-right: 3px solid @primary-color;
border-right-color: @primary-color;
transform: translateZ(0);
}
}
@ -247,6 +262,7 @@
&:hover,
&-active,
&-open,
&-selected {
border-bottom: 2px solid @primary-color;
color: @primary-color;
@ -270,11 +286,10 @@
}
&-vertical,
&-inline,
&-item-group-list {
& > .@{menu-prefix-cls}-item,
& > .@{menu-prefix-cls}-submenu > .@{menu-prefix-cls}-submenu-title {
padding: 0 16px 0 28px;
&-inline {
.@{menu-prefix-cls}-item,
.@{menu-prefix-cls}-submenu-title {
padding: 0 16px;
font-size: @font-size-base;
line-height: 42px;
height: 42px;
@ -283,6 +298,13 @@
}
}
&-item-group-list {
.@{menu-prefix-cls}-item,
.@{menu-prefix-cls}-submenu-title {
padding: 0 16px 0 28px;
}
}
&-vertical&-sub {
padding: 0;
transform-origin: 0 0;
@ -373,6 +395,7 @@
&-dark &-item:hover,
&-dark &-item-active,
&-dark &-submenu-active,
&-dark &-submenu-open,
&-dark &-submenu-selected,
&-dark &-submenu:hover,
&-dark &-submenu-title:hover {

View File

@ -9,22 +9,23 @@
width: 100%;
top: 16px;
left: 0;
pointer-events: none;
&-notice {
width: auto;
vertical-align: middle;
position: absolute;
left: 50%;
padding: 8px;
text-align: center;
&:first-child {
margin-top: -8px;
}
}
&-notice-content {
position: relative;
right: 50%;
padding: 8px 16px;
border-radius: @border-radius-base;
box-shadow: @shadow-2;
background: @component-background;
display: block;
display: inline-block;
pointer-events: all;
}
&-success .@{iconfont-css-prefix} {
@ -50,4 +51,22 @@
top: 1px;
position: relative;
}
&-notice.move-up-leave.move-up-leave-active {
animation-name: MessageMoveOut;
overflow: hidden;
}
}
@keyframes MessageMoveOut {
0% {
opacity: 1;
max-height: 60px;
padding: 8px;
}
100% {
opacity: 0;
max-height: 0;
padding: 0;
}
}

View File

@ -2,19 +2,23 @@
order: 2
title:
zh-CN: 自定义页脚
en-US: Customized footer
en-US: Customized Footer
---
## zh-CN
更复杂的例子,自定义了页脚的按钮,点击提交后进入 loading 状态,完成后关闭。
不需要默认确定取消按钮时,你可以把 `footer` 设为 `null`
## en-US
A more complex example, as illustrated in this example, we define a customized footer button bar,
the dialog will change to loading state after clicking submit button , when the loading is over,
A more complex example which define a customized footer button bar,
the dialog will change to loading state after clicking submit button, when the loading is over,
the modal dialog will be closed.
You could set `footer` to `null` if you don't need default footer buttons.
````jsx
import { Modal, Button } from 'antd';

View File

@ -25,7 +25,7 @@ and so on.
| onOk | Specify a function that will be called when a user clicked OK button | function | no |
| onCancel | Specify a function that will be called when a user clicked mask, close button on top right or cancel button | function(e) | no |
| width | Width of a modal dialog | string\|number | 520 |
| footer | Footer content | string\|ReactNode | OK and cancel button |
| footer | Footer content, set as `footer={null}` when you don't need default buttons | string\|ReactNode | OK and cancel button |
| okText | Text of the OK button | string | OK |
| cancelText | Text of the Cancel button | string | Cancel |
| maskClosable | Determine whether to close the modal dialog when clicked mask of it. | boolean | true |

View File

@ -24,7 +24,7 @@ title: Modal
| onOk | 点击确定回调 | function | 无 |
| onCancel | 点击遮罩层或右上角叉或取消按钮的回调 | function(e) | 无 |
| width | 宽度 | string\|number | 520 |
| footer | 底部内容 | string\|ReactNode | 确定取消按钮 |
| footer | 底部内容,当不需要默认底部按钮时,可以设为 `footer={null}` | string\|ReactNode | 确定取消按钮 |
| okText | 确认按钮文字 | string | 确定 |
| cancelText | 取消按钮文字 | string | 取消 |
| maskClosable | 点击蒙层是否允许关闭 | boolean | true |

View File

@ -322,7 +322,6 @@ exports[`test renders ./components/pagination/demo/mini.md correctly 1`] = `
<a />
</li>
</ul>
<br />
<ul
class="ant-pagination mini"
unselectable="unselectable">
@ -410,7 +409,6 @@ exports[`test renders ./components/pagination/demo/mini.md correctly 1`] = `
</div>
</div>
</ul>
<br />
<ul
class="ant-pagination mini"
unselectable="unselectable">
@ -472,45 +470,57 @@ exports[`test renders ./components/pagination/demo/more.md correctly 1`] = `
class="ant-pagination "
unselectable="unselectable">
<li
class="ant-pagination-disabled ant-pagination-prev"
class=" ant-pagination-prev"
title="上一页">
<a />
</li>
<li
class="ant-pagination-item ant-pagination-item-1 ant-pagination-item-active"
class="ant-pagination-item ant-pagination-item-1"
title="1">
<a>
1
</a>
</li>
<li
class="ant-pagination-item ant-pagination-item-2"
title="2">
<a>
2
</a>
class="ant-pagination-jump-prev"
title="向前 5 页">
<a />
</li>
<li
class="ant-pagination-item ant-pagination-item-3"
title="3">
<a>
3
</a>
</li>
<li
class="ant-pagination-item ant-pagination-item-4"
class="ant-pagination-item ant-pagination-item-4 ant-pagination-item-after-jump-prev"
title="4">
<a>
4
</a>
</li>
<li
class="ant-pagination-item ant-pagination-item-5 ant-pagination-item-before-jump-next"
class="ant-pagination-item ant-pagination-item-5"
title="5">
<a>
5
</a>
</li>
<li
class="ant-pagination-item ant-pagination-item-6 ant-pagination-item-active"
title="6">
<a>
6
</a>
</li>
<li
class="ant-pagination-item ant-pagination-item-7"
title="7">
<a>
7
</a>
</li>
<li
class="ant-pagination-item ant-pagination-item-8 ant-pagination-item-before-jump-next"
title="8">
<a>
8
</a>
</li>
<li
class="ant-pagination-jump-next"
title="向后 5 页">

View File

@ -23,10 +23,14 @@ function showTotal(total) {
ReactDOM.render(
<div>
<Pagination size="small" total={50} />
<br />
<Pagination size="small" total={50} showSizeChanger showQuickJumper />
<br />
<Pagination size="small" total={50} showTotal={showTotal} />
</div>
, mountNode);
````
<style>
#components-pagination-demo-mini .ant-pagination:not(:last-child) {
margin-bottom: 24px;
}
</style>

View File

@ -17,6 +17,6 @@ More pages.
import { Pagination } from 'antd';
ReactDOM.render(
<Pagination defaultCurrent={1} total={500} />
<Pagination defaultCurrent={6} total={500} />
, mountNode);
````

View File

@ -2,6 +2,7 @@
category: Components
type: Navigation
title: Pagination
cols: 1
---
A long list can be divided into several pages by `Pagination`, and only one page will be loaded at a time.

View File

@ -3,6 +3,7 @@ category: Components
subtitle: 分页
type: Navigation
title: Pagination
cols: 1
---
采用分页的形式分隔长列表,每次只加载一个页面。

View File

@ -49,7 +49,7 @@ export default class Radio extends React.Component<RadioProps, any> {
onMouseLeave={this.props.onMouseLeave}
>
<RcRadio {...this.props} className={classString} style={null} children={null} />
{children ? <span>{children}</span> : null}
{children !== undefined ? <span>{children}</span> : null}
</label>
);
}

View File

@ -115,7 +115,7 @@ span.@{radio-prefix-cls} + * {
.@{radio-prefix-cls}-button-wrapper {
margin: 0;
height: @input-height-base;
line-height: 26px;
line-height: @input-height-base - 2;
color: @btn-default-color;
display: inline-block;
transition: all 0.3s ease;
@ -138,12 +138,12 @@ span.@{radio-prefix-cls} + * {
.@{radio-group-prefix-cls}-large & {
height: @input-height-lg;
line-height: 30px;
line-height: @input-height-lg - 2px;
}
.@{radio-group-prefix-cls}-small & {
height: @input-height-sm;
line-height: 20px;
line-height: @input-height-sm - 2;
padding: 0 12px;
&:first-child {
border-radius: @border-radius-sm 0 0 @border-radius-sm;

View File

@ -323,7 +323,7 @@ exports[`test renders ./components/select/demo/optgroup.md correctly 1`] = `
exports[`test renders ./components/select/demo/search.md correctly 1`] = `
<div
class="ant-select-show-search ant-select ant-select-enabled"
class="ant-select ant-select-enabled"
style="width:200px;">
<div
aria-autocomplete="list"

View File

@ -23,9 +23,9 @@ function handleChange(value) {
}
ReactDOM.render(
<Select defaultValue="lucy"
<Select
defaultValue="lucy"
style={{ width: 200 }}
showSearch={false}
onChange={handleChange}
>
<OptGroup label="Manager">

View File

@ -92,7 +92,6 @@ export default class Select extends React.Component<SelectProps, any> {
className = '',
size,
combobox,
showSearch,
} = this.props;
let { notFoundContent = 'Not Found', optionLabelProp } = this.props;
@ -100,7 +99,6 @@ export default class Select extends React.Component<SelectProps, any> {
const cls = classNames({
[`${prefixCls}-lg`]: size === 'large',
[`${prefixCls}-sm`]: size === 'small',
[`${prefixCls}-show-search`]: showSearch,
}, className);
const { antLocale } = this.context;

View File

@ -5,12 +5,12 @@ exports[`test renders ./components/slider/demo/basic.md correctly 1`] = `
<div
class="ant-slider-rail" />
<div
class="ant-slider-track ant-slider-track-1"
class="ant-slider-track"
style="visibility:visible;left:0%;width:30%;" />
<div
class="ant-slider-step" />
<div
class="ant-slider-handle ant-slider-handle-2 ant-slider-handle-upper"
class="ant-slider-handle"
style="left:30%;" />
<div
class="ant-slider-mark" />
@ -25,10 +25,10 @@ exports[`test renders ./components/slider/demo/basic.md correctly 1`] = `
<div
class="ant-slider-step" />
<div
class="ant-slider-handle ant-slider-handle-1 ant-slider-handle-lower"
class="ant-slider-handle ant-slider-handle-1"
style="left:20%;" />
<div
class="ant-slider-handle ant-slider-handle-2 ant-slider-handle-upper"
class="ant-slider-handle ant-slider-handle-2"
style="left:50%;" />
<div
class="ant-slider-mark" />
@ -50,12 +50,12 @@ exports[`test renders ./components/slider/demo/event.md correctly 1`] = `
<div
class="ant-slider-rail" />
<div
class="ant-slider-track ant-slider-track-1"
class="ant-slider-track"
style="visibility:visible;left:0%;width:30%;" />
<div
class="ant-slider-step" />
<div
class="ant-slider-handle ant-slider-handle-2 ant-slider-handle-upper"
class="ant-slider-handle"
style="left:30%;" />
<div
class="ant-slider-mark" />
@ -70,10 +70,10 @@ exports[`test renders ./components/slider/demo/event.md correctly 1`] = `
<div
class="ant-slider-step" />
<div
class="ant-slider-handle ant-slider-handle-1 ant-slider-handle-lower"
class="ant-slider-handle ant-slider-handle-1"
style="left:20%;" />
<div
class="ant-slider-handle ant-slider-handle-2 ant-slider-handle-upper"
class="ant-slider-handle ant-slider-handle-2"
style="left:50%;" />
<div
class="ant-slider-mark" />
@ -91,12 +91,12 @@ exports[`test renders ./components/slider/demo/icon-slider.md correctly 1`] = `
<div
class="ant-slider-rail" />
<div
class="ant-slider-track ant-slider-track-1"
class="ant-slider-track"
style="visibility:visible;left:0%;width:0%;" />
<div
class="ant-slider-step" />
<div
class="ant-slider-handle ant-slider-handle-2 ant-slider-handle-upper"
class="ant-slider-handle"
style="left:0%;" />
<div
class="ant-slider-mark" />
@ -117,12 +117,12 @@ exports[`test renders ./components/slider/demo/input-number.md correctly 1`] = `
<div
class="ant-slider-rail" />
<div
class="ant-slider-track ant-slider-track-1"
class="ant-slider-track"
style="visibility:visible;left:0%;width:0%;" />
<div
class="ant-slider-step" />
<div
class="ant-slider-handle ant-slider-handle-2 ant-slider-handle-upper"
class="ant-slider-handle"
style="left:0%;" />
<div
class="ant-slider-mark" />
@ -171,12 +171,12 @@ exports[`test renders ./components/slider/demo/input-number.md correctly 1`] = `
<div
class="ant-slider-rail" />
<div
class="ant-slider-track ant-slider-track-1"
class="ant-slider-track"
style="visibility:visible;left:0%;width:0%;" />
<div
class="ant-slider-step" />
<div
class="ant-slider-handle ant-slider-handle-2 ant-slider-handle-upper"
class="ant-slider-handle"
style="left:0%;" />
<div
class="ant-slider-mark" />
@ -229,7 +229,7 @@ exports[`test renders ./components/slider/demo/mark.md correctly 1`] = `
<div
class="ant-slider-rail" />
<div
class="ant-slider-track ant-slider-track-1"
class="ant-slider-track"
style="visibility:visible;left:0%;width:37%;" />
<div
class="ant-slider-step">
@ -247,7 +247,7 @@ exports[`test renders ./components/slider/demo/mark.md correctly 1`] = `
style="left:100%;" />
</div>
<div
class="ant-slider-handle ant-slider-handle-2 ant-slider-handle-upper"
class="ant-slider-handle"
style="left:37%;" />
<div
class="ant-slider-mark">
@ -298,10 +298,10 @@ exports[`test renders ./components/slider/demo/mark.md correctly 1`] = `
style="left:100%;" />
</div>
<div
class="ant-slider-handle ant-slider-handle-1 ant-slider-handle-lower"
class="ant-slider-handle ant-slider-handle-1"
style="left:26%;" />
<div
class="ant-slider-handle ant-slider-handle-2 ant-slider-handle-upper"
class="ant-slider-handle ant-slider-handle-2"
style="left:37%;" />
<div
class="ant-slider-mark">
@ -337,7 +337,7 @@ exports[`test renders ./components/slider/demo/mark.md correctly 1`] = `
<div
class="ant-slider-rail" />
<div
class="ant-slider-track ant-slider-track-1"
class="ant-slider-track"
style="visibility:hidden;left:0%;width:37%;" />
<div
class="ant-slider-step">
@ -355,7 +355,7 @@ exports[`test renders ./components/slider/demo/mark.md correctly 1`] = `
style="left:100%;" />
</div>
<div
class="ant-slider-handle ant-slider-handle-2 ant-slider-handle-upper"
class="ant-slider-handle"
style="left:37%;" />
<div
class="ant-slider-mark">
@ -391,7 +391,7 @@ exports[`test renders ./components/slider/demo/mark.md correctly 1`] = `
<div
class="ant-slider-rail" />
<div
class="ant-slider-track ant-slider-track-1"
class="ant-slider-track"
style="visibility:visible;left:0%;width:37%;" />
<div
class="ant-slider-step">
@ -409,7 +409,7 @@ exports[`test renders ./components/slider/demo/mark.md correctly 1`] = `
style="left:100%;" />
</div>
<div
class="ant-slider-handle ant-slider-handle-2 ant-slider-handle-upper"
class="ant-slider-handle"
style="left:37%;" />
<div
class="ant-slider-mark">
@ -445,7 +445,7 @@ exports[`test renders ./components/slider/demo/mark.md correctly 1`] = `
<div
class="ant-slider-rail" />
<div
class="ant-slider-track ant-slider-track-1"
class="ant-slider-track"
style="visibility:visible;left:0%;width:37%;" />
<div
class="ant-slider-step">
@ -463,7 +463,7 @@ exports[`test renders ./components/slider/demo/mark.md correctly 1`] = `
style="left:100%;" />
</div>
<div
class="ant-slider-handle ant-slider-handle-2 ant-slider-handle-upper"
class="ant-slider-handle"
style="left:37%;" />
<div
class="ant-slider-mark">
@ -501,12 +501,12 @@ exports[`test renders ./components/slider/demo/tip-formatter.md correctly 1`] =
<div
class="ant-slider-rail" />
<div
class="ant-slider-track ant-slider-track-1"
class="ant-slider-track"
style="visibility:visible;left:0%;width:0%;" />
<div
class="ant-slider-step" />
<div
class="ant-slider-handle ant-slider-handle-2 ant-slider-handle-upper"
class="ant-slider-handle"
style="left:0%;" />
<div
class="ant-slider-mark" />
@ -516,12 +516,12 @@ exports[`test renders ./components/slider/demo/tip-formatter.md correctly 1`] =
<div
class="ant-slider-rail" />
<div
class="ant-slider-track ant-slider-track-1"
class="ant-slider-track"
style="visibility:visible;left:0%;width:0%;" />
<div
class="ant-slider-step" />
<div
class="ant-slider-handle ant-slider-handle-2 ant-slider-handle-upper"
class="ant-slider-handle"
style="left:0%;" />
<div
class="ant-slider-mark" />
@ -539,12 +539,12 @@ exports[`test renders ./components/slider/demo/vertical.md correctly 1`] = `
<div
class="ant-slider-rail" />
<div
class="ant-slider-track ant-slider-track-1"
class="ant-slider-track"
style="visibility:visible;bottom:0%;height:30%;" />
<div
class="ant-slider-step" />
<div
class="ant-slider-handle ant-slider-handle-2 ant-slider-handle-upper"
class="ant-slider-handle"
style="bottom:30%;" />
<div
class="ant-slider-mark" />
@ -562,10 +562,10 @@ exports[`test renders ./components/slider/demo/vertical.md correctly 1`] = `
<div
class="ant-slider-step" />
<div
class="ant-slider-handle ant-slider-handle-1 ant-slider-handle-lower"
class="ant-slider-handle ant-slider-handle-1"
style="bottom:20%;" />
<div
class="ant-slider-handle ant-slider-handle-2 ant-slider-handle-upper"
class="ant-slider-handle ant-slider-handle-2"
style="bottom:50%;" />
<div
class="ant-slider-mark" />
@ -596,10 +596,10 @@ exports[`test renders ./components/slider/demo/vertical.md correctly 1`] = `
style="bottom:100%;" />
</div>
<div
class="ant-slider-handle ant-slider-handle-1 ant-slider-handle-lower"
class="ant-slider-handle ant-slider-handle-1"
style="bottom:26%;" />
<div
class="ant-slider-handle ant-slider-handle-2 ant-slider-handle-upper"
class="ant-slider-handle ant-slider-handle-2"
style="bottom:37%;" />
<div
class="ant-slider-mark">

View File

@ -1,6 +1,8 @@
import React from 'react';
import { PropTypes } from 'react';
import RcSlider from 'rc-slider';
import RcSlider from 'rc-slider/lib/Slider';
import RcRange from 'rc-slider/lib/Range';
import RcHandle from 'rc-slider/lib/Handle';
import Tooltip from '../tooltip';
export interface SliderMarks {
[key: number]: React.ReactNode | {
@ -12,6 +14,8 @@ export interface SliderMarks {
export type SliderValue = number | [number, number];
export interface SliderProps {
prefixCls?: string;
tooltipPrefixCls?: string;
range?: boolean;
min?: number;
max?: number;
@ -32,15 +36,46 @@ export default class Slider extends React.Component<SliderProps, any> {
static defaultProps = {
prefixCls: 'ant-slider',
tooltipPrefixCls: 'ant-tooltip',
tipTransitionName: 'zoom-down',
tipFormatter(value) {
return value.toString();
},
};
static propTypes = {
prefixCls: PropTypes.string,
tipTransitionName: PropTypes.string,
};
constructor(props) {
super(props);
this.state = { visibles: {} };
}
handleTooltipVisibleChange = (index, visible) => {
this.setState({
visibles: {
...this.state.visibles,
[index]: visible,
},
});
}
handleWithTooltip = ({ value, dragging, index, ...restProps }) => {
const { tooltipPrefixCls, tipFormatter } = this.props;
return (
<Tooltip
prefixCls={tooltipPrefixCls}
title={tipFormatter ? tipFormatter(value) : ''}
visible={tipFormatter && (this.state.visibles[index] || dragging)}
onVisibleChange={visible => this.handleTooltipVisibleChange(index, visible)}
placement="top"
transitionName="zoom-down"
key={index}
>
<RcHandle {...restProps} />
</Tooltip>
);
}
render() {
return <RcSlider {...this.props} />;
const { range, ...restProps } = this.props;
if (range) {
return <RcRange {...restProps} handle={this.handleWithTooltip} />;
}
return <RcSlider {...restProps} handle={this.handleWithTooltip} />;
}
}

View File

@ -75,11 +75,12 @@
&-blur {
opacity: 0.7;
-webkit-filter: blur(1px);
filter: blur(1px);
-webkit-filter: blur(0.8px);
filter: blur(0.8px);
/* IE6~IE9 */
filter: ~"progid\:DXImageTransform\.Microsoft\.Blur(PixelRadius\=1, MakeShadow\=false)"; // lesshint duplicateProperty: false
/* autoprefixer: off */
filter: ~"progid\:DXImageTransform\.Microsoft\.Blur(PixelRadius\=1, MakeShadow\=false)";
/* autoprefixer: on */
// workround for a strange style bug in safari:
// https://github.com/ant-design/ant-design/issues/4622
// have no clue why this works
@ -91,7 +92,9 @@
right: 0;
top: 0;
bottom: 0;
background: transparent;
background: #fff;
opacity: 0.2;
transition: all .3s;
}
}

View File

@ -10,6 +10,6 @@
.ant-motion-collapse {
overflow: hidden;
&-active {
transition: height .2s @ease-out;
transition: height .24s ease-in;
}
}

View File

@ -504,7 +504,7 @@ export default class Table<T> extends React.Component<TableProps<T>, any> {
});
}
handlePageChange = (current) => {
handlePageChange = (current, ...otherArguments) => {
const props = this.props;
let pagination = assign({}, this.state.pagination);
if (current) {
@ -512,7 +512,7 @@ export default class Table<T> extends React.Component<TableProps<T>, any> {
} else {
pagination.current = pagination.current || 1;
}
pagination.onChange(pagination.current);
pagination.onChange(pagination.current, ...otherArguments);
const newState = {
pagination,
@ -724,6 +724,7 @@ export default class Table<T> extends React.Component<TableProps<T>, any> {
let total = pagination.total || this.getLocalData().length;
return (total > 0) ?
<Pagination
key="pagination"
{...pagination}
className={`${this.props.prefixCls}-pagination`}
onChange={this.handlePageChange}
@ -734,9 +735,12 @@ export default class Table<T> extends React.Component<TableProps<T>, any> {
/> : null;
}
// Get pagination, filters, sorter
prepareParamsArguments(state: any): [any, string[], Object] {
// 准备筛选、排序、分页的参数
const pagination = state.pagination;
const pagination = { ...state.pagination };
// remove useless handle function in Table.onChange
delete pagination.onChange;
delete pagination.onShowSizeChange;
const filters = state.filters;
const sorter: any = {};
if (state.sortColumn && state.sortOrder) {
@ -858,8 +862,9 @@ export default class Table<T> extends React.Component<TableProps<T>, any> {
expandIconColumnIndex = restProps.expandIconColumnIndex as number;
}
let table = (
const table = (
<RcTable
key="table"
{...restProps}
prefixCls={prefixCls}
data={data}
@ -871,21 +876,25 @@ export default class Table<T> extends React.Component<TableProps<T>, any> {
emptyText={() => locale.emptyText}
/>
);
// if there is no pagination or no data,
// the height of spin should decrease by half of pagination
const paginationPatchClass = (this.hasPagination() && data && data.length !== 0)
? `${prefixCls}-with-pagination`
: `${prefixCls}-without-pagination`;
? `${prefixCls}-with-pagination` : `${prefixCls}-without-pagination`;
let loading = this.props.loading;
if (typeof (loading) === 'boolean') {
if (typeof loading === 'boolean') {
loading = {
spinning: loading,
};
}
const spinClassName = this.props.loading ? `${paginationPatchClass} ${prefixCls}-spin-holder` : '';
return (
<div className={`${className} clearfix`} style={style}>
<Spin className={spinClassName} {...loading}>
<div className={classNames(`${prefixCls}-wrapper`, className)} style={style}>
<Spin
{...loading}
className={loading ? `${paginationPatchClass} ${prefixCls}-spin-holder` : ''}
>
{table}
{this.renderPagination()}
</Spin>

View File

@ -56,9 +56,10 @@ describe('Table.pagination', () => {
it('fires change event', () => {
const handleChange = jest.fn();
const handlePaginationChange = jest.fn();
const noop = () => {};
const wrapper = mount(createTable({
pagination: { ...pagination, onChange: noop, onShowSizeChange: noop },
pagination: { ...pagination, onChange: handlePaginationChange, onShowSizeChange: noop },
onChange: handleChange,
}));
@ -67,13 +68,13 @@ describe('Table.pagination', () => {
expect(handleChange).toBeCalledWith(
{
current: 2,
onChange: noop,
onShowSizeChange: noop,
pageSize: 2,
},
{},
{}
);
expect(handlePaginationChange).toBeCalledWith(2, 2);
});
// https://github.com/ant-design/ant-design/issues/4532

View File

@ -14,7 +14,7 @@ exports[`Table.filter renders custom content correctly 1`] = `
exports[`Table.filter renders filter correctly 1`] = `
<div
class=" clearfix">
class="ant-table-wrapper">
<div
class="ant-spin-nested-loading">
<div
@ -23,9 +23,6 @@ exports[`Table.filter renders filter correctly 1`] = `
class="ant-table ant-table-large ant-table-scroll-position-left">
<div
class="ant-table-content">
<div
class="">
<span>
<div
class="ant-table-body">
<table
@ -92,8 +89,6 @@ exports[`Table.filter renders filter correctly 1`] = `
</tbody>
</table>
</div>
</span>
</div>
</div>
</div>
</div>

View File

@ -1,6 +1,6 @@
exports[`Table.pagination renders pagination correctly 1`] = `
<div
class=" clearfix">
class="ant-table-wrapper">
<div
class="ant-spin-nested-loading">
<div
@ -9,9 +9,6 @@ exports[`Table.pagination renders pagination correctly 1`] = `
class="ant-table ant-table-large ant-table-scroll-position-left">
<div
class="ant-table-content">
<div
class="">
<span>
<div
class="ant-table-body">
<table
@ -55,8 +52,6 @@ exports[`Table.pagination renders pagination correctly 1`] = `
</tbody>
</table>
</div>
</span>
</div>
</div>
</div>
<ul

View File

@ -1,6 +1,6 @@
exports[`Table renders JSX correctly 1`] = `
<div
class=" clearfix">
class="ant-table-wrapper">
<div
class="ant-spin-nested-loading">
<div
@ -9,9 +9,6 @@ exports[`Table renders JSX correctly 1`] = `
class="ant-table ant-table-large ant-table-scroll-position-left">
<div
class="ant-table-content">
<div
class="">
<span>
<div
class="ant-table-body">
<table
@ -95,8 +92,6 @@ exports[`Table renders JSX correctly 1`] = `
</tbody>
</table>
</div>
</span>
</div>
</div>
</div>
</div>

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
---
order: 24
order: 25
title:
en-US: Dynamic Settings
zh-CN: 动态控制表格属性

View File

@ -9,18 +9,22 @@ title:
适合同时展示有大量数据和数据列。
> 若列头与内容不对齐,请指定列宽度 `width`
> 若列头与内容不对齐,请指定列宽度 `width`
> 建议指定 `scroll.x` 为固定宽度。注意,非固定列宽度之和不要超过 `scroll.x`
> 如果希望 `scroll.x` 为自适应内容宽度,可以指定 `scroll={{ x: true }}`,然后使用 `white-space: nowrap` 样式强制单元格不自动换行。
## en-US
Suitable for large amounts of data with long columns.
A Solution for displaying large amounts of data with long columns.
> Specify the width of each column if header and cell do not align properly.
> Specify the width of columns if header and cell do not align properly.
> A fixed width for `scroll.x` is recommended. The sum of unfixed columns should not greater than `scroll.x`.
> If you hope the `scroll.x` will adapt content's witdh, you can set `scroll={{ x: true }}` ant then use css `white-space: nowrap` to make sure table cell will not be wrapped.
````jsx
import { Table } from 'antd';

View File

@ -9,17 +9,21 @@ title:
对于列数很多的数据,可以固定前后的列,横向滚动查看其它数据,需要和 `scroll.x` 配合使用。
> 若列头与内容不对齐,请指定列宽度 `width`
> 若列头与内容不对齐,请指定列宽度 `width`
> 建议指定 scroll.x 为固定宽度。
> 建议指定 `scroll.x` 为固定宽度。注意,非固定列宽度之和不要超过 `scroll.x`
> 如果希望 `scroll.x` 为自适应内容宽度,可以指定 `scroll={{ x: true }}`,然后使用 `white-space: nowrap` 样式强制单元格不自动换行。
## en-US
Fix some columns and scroll in other columns. You must set `scoll.x` meanwhile.
To fix some columns and scroll inside other columns, and you must set `scoll.x` meanwhile.
> Specify the width of each column if header and cell do not align properly.
> Specify the width of columns if header and cell do not align properly.
> A fixed width for `scroll.x` is recommended.
> A fixed width for `scroll.x` is recommended. The sum of unfixed columns should not greater than `scroll.x`.
> If you hope the `scroll.x` will adapt content's witdh, you can set `scroll={{ x: true }}` ant then use css `white-space: nowrap` to make sure table cell will not be wrapped.
````jsx
import { Table } from 'antd';

View File

@ -0,0 +1,138 @@
---
order: 24
title:
en-US: Nested tables
zh-CN: 嵌套子表格
---
## zh-CN
展示每行数据更详细的信息。
## en-US
Showing more detailed info of every row.
````jsx
import { Table, Badge, Menu, Dropdown, Icon } from 'antd';
const menu = (
<Menu>
<Menu.Item>
Action 1
</Menu.Item>
<Menu.Item>
Action 2
</Menu.Item>
</Menu>
);
function NestedTable() {
const expandedRowRender = () => {
const columns = [
{ title: 'Date', dataIndex: 'date', key: 'date' },
{ title: 'Name', dataIndex: 'name', key: 'name' },
{ title: 'Status', key: 'state', render: () => <span><Badge status="success" />Finished</span> },
{ title: 'Upgrade Status', dataIndex: 'upgradeNum', key: 'upgradeNum' },
{
title: 'Action',
dataIndex: 'operation',
key: 'operation',
render: () => (
<span className={'table-operation'}>
<a href="#">Pause</a>
<a href="#">Stop</a>
<Dropdown overlay={menu}>
<a href="#">
More <Icon type="down" />
</a>
</Dropdown>
</span>
),
},
];
const data = [];
for (let i = 0; i < 3; ++i) {
data.push({
key: i,
date: '2014-12-24 23:12:00',
name: 'This is production name',
upgradeNum: 'Upgraded: 56',
});
}
return (
<Table
columns={columns}
dataSource={data}
pagination={false}
/>
);
};
const columns = [
{ title: 'Name', dataIndex: 'name', key: 'name' },
{ title: 'Platform', dataIndex: 'platform', key: 'platform' },
{ title: 'Version', dataIndex: 'version', key: 'version' },
{ title: 'Upgraded', dataIndex: 'upgradeNum', key: 'upgradeNum' },
{ title: 'Creator', dataIndex: 'creator', key: 'creator' },
{ title: 'Date', dataIndex: 'createdAt', key: 'createdAt' },
{ title: 'Action', key: 'operation', render: () => <a href="#">Publish</a> },
];
const data = [];
for (let i = 0; i < 3; ++i) {
data.push({
key: i,
name: 'Screem',
platform: 'iOS',
version: '10.3.4.5654',
upgradeNum: 500,
creator: 'Jack',
createdAt: '2014-12-24 23:12:00',
});
}
return (
<Table
className="components-table-demo-nested"
columns={columns}
expandedRowRender={expandedRowRender}
dataSource={data}
/>
);
}
ReactDOM.render(<NestedTable />, mountNode);
````
````css
.components-table-demo-nested .ant-table-expanded-row > td:last-child {
padding: 0 48px 0 8px;
}
.components-table-demo-nested .ant-table-expanded-row > td:last-child .ant-table-thead th {
border-bottom: 1px solid #e9e9e9;
}
.components-table-demo-nested .ant-table-expanded-row > td:last-child .ant-table-thead th:first-child {
padding-left: 0;
}
.components-table-demo-nested .ant-table-expanded-row > td:last-child .ant-table-row td:first-child {
padding-left: 0;
}
.components-table-demo-nested .ant-table-expanded-row .ant-table-row:last-child td {
border: none;
}
.components-table-demo-nested .ant-table-expanded-row .ant-table-thead > tr > th {
background: none;
}
.components-table-demo-nested .table-operation a:not(:last-child) {
margin-right: 24px;
}
````

View File

@ -1,55 +0,0 @@
---
order: 6
title:
en-US: Pagination
zh-CN: 分页
---
## zh-CN
表格中的分页器可以通过一个配置对象来配置,当 `pagination={false}` 时,会隐藏分页器。
## en-US
The pagination in table could be configured with an object, and you can use `pagination={false}` to turn off pagination.
````jsx
import { Table } from 'antd';
const columns = [{
title: 'Name',
dataIndex: 'name',
render: text => <a href="#">{text}</a>,
}, {
title: 'Age',
dataIndex: 'age',
}, {
title: 'Address',
dataIndex: 'address',
}];
const data = [];
for (let i = 0; i < 46; i++) {
data.push({
key: i,
name: `Edward King ${i}`,
age: 32,
address: `London, Park Lane no. ${i}`,
});
}
const pagination = {
total: data.length,
showSizeChanger: true,
onShowSizeChange: (current, pageSize) => {
console.log('Current: ', current, '; PageSize: ', pageSize);
},
onChange: (current) => {
console.log('Current: ', current);
},
};
ReactDOM.render(
<Table columns={columns} dataSource={data} pagination={pagination} />
, mountNode);
````

View File

@ -156,7 +156,7 @@ class NameColumn extends Table.Column<IUser> {}
## Note
According to [React documentation](http://facebook.github.io/react/docs/multiple-components.html#dynamic-children), every child in array should be assigned a unique key. The value inside `dataSource` and `columns` should follow this in Table, and `dataSource[i].key` would be treated as key value defaultly for `dataSource`.
According to [React documentation](https://facebook.github.io/react/docs/lists-and-keys.html#keys), every child in array should be assigned a unique key. The value inside `dataSource` and `columns` should follow this in Table, and `dataSource[i].key` would be treated as key value defaultly for `dataSource`.
If `dataSource[i].key` is not existed, then you should specify the primary key of dataSource value via `rowKey`. If not, warnings like above will show in browser console.

View File

@ -156,7 +156,7 @@ class NameColumn extends Table.Column<IUser> {}
## 注意
按照 React 的[规范](http://facebook.github.io/react/docs/multiple-components.html#dynamic-children),所有的组件数组必须绑定 key。在 Table 中,`dataSource` 和 `columns` 里的数据值都需要指定 `key` 值。对于 `dataSource` 默认将每列数据的 `key` 属性作为唯一的标识。
按照 [React 的规范](https://facebook.github.io/react/docs/lists-and-keys.html#keys),所有的组件数组必须绑定 key。在 Table 中,`dataSource` 和 `columns` 里的数据值都需要指定 `key` 值。对于 `dataSource` 默认将每列数据的 `key` 属性作为唯一的标识。
如果你的数据没有这个属性,务必使用 `rowKey` 来指定数据列的主键。若没有指定,控制台会出现以下的提示,表格组件也会出现各类奇怪的错误。

View File

@ -4,6 +4,10 @@
@table-prefix-cls: ~"@{ant-prefix}-table";
@table-head-background-color: @background-color-base;
.@{table-prefix-cls}-wrapper {
.clearfix;
}
.@{table-prefix-cls} {
font-size: @font-size-base;
color: @text-color;
@ -333,10 +337,15 @@
display: none;
}
}
.@{table-prefix-cls}-placeholder {
border: 0;
}
}
}
&-placeholder {
position: relative;
padding: 16px 8px;
background: @component-background;
border-bottom: @border-width-base @border-style-base @border-color-split;
@ -364,6 +373,8 @@
border: 0;
box-shadow: none;
border-radius: @border-radius-base @border-radius-base 0 0;
max-height: 400px;
overflow-x: hidden;
&-item > label + span {
padding: 0;
@ -486,10 +497,8 @@
&-fixed-header &-scroll &-header {
overflow: scroll;
// Fix https://github.com/ant-design/ant-design/issues/4637
&::-webkit-scrollbar {
display: none;
}
padding-bottom: 20px;
margin-bottom: -20px;
}
/* fix firefox scrollbar bug */
@ -503,7 +512,6 @@
position: absolute;
top: 0;
overflow: hidden;
z-index: 1;
transition: box-shadow .3s ease;
border-radius: 0;
table {

View File

@ -17,31 +17,33 @@ Hide default plus icon, and bind event for customized trigger.
import { Tabs, Button } from 'antd';
const TabPane = Tabs.TabPane;
const Demo = React.createClass({
getInitialState() {
class Demo extends React.Component {
constructor(props) {
super(props);
this.newTabIndex = 0;
const panes = [
{ title: 'Tab 1', content: 'Content of Tab Pane 1', key: '1' },
{ title: 'Tab 2', content: 'Content of Tab Pane 2', key: '2' },
];
return {
this.state = {
activeKey: panes[0].key,
panes,
};
},
onChange(activeKey) {
}
onChange = (activeKey) => {
this.setState({ activeKey });
},
onEdit(targetKey, action) {
}
onEdit = (targetKey, action) => {
this[action](targetKey);
},
add() {
}
add = () => {
const panes = this.state.panes;
const activeKey = `newTab${this.newTabIndex++}`;
panes.push({ title: 'New Tab', content: 'New Tab Pane', key: activeKey });
this.setState({ panes, activeKey });
},
remove(targetKey) {
}
remove = (targetKey) => {
let activeKey = this.state.activeKey;
let lastIndex;
this.state.panes.forEach((pane, i) => {
@ -54,7 +56,7 @@ const Demo = React.createClass({
activeKey = panes[lastIndex].key;
}
this.setState({ panes, activeKey });
},
}
render() {
return (
<div>
@ -72,8 +74,8 @@ const Demo = React.createClass({
</Tabs>
</div>
);
},
});
}
}
ReactDOM.render(<Demo />, mountNode);
````

View File

@ -19,31 +19,34 @@ Only card type Tabs support adding & closable.
import { Tabs } from 'antd';
const TabPane = Tabs.TabPane;
const Demo = React.createClass({
getInitialState() {
class Demo extends React.Component {
constructor(props) {
super(props);
this.newTabIndex = 0;
const panes = [
{ title: 'Tab 1', content: 'Content of Tab 1', key: '1', closable: false },
{ title: 'Tab 2', content: 'Content of Tab 2', key: '2' },
];
return {
this.state = {
activeKey: panes[0].key,
panes,
};
},
onChange(activeKey) {
}
onChange = (activeKey) => {
this.setState({ activeKey });
},
onEdit(targetKey, action) {
}
onEdit = (targetKey, action) => {
this[action](targetKey);
},
add() {
}
add = () => {
const panes = this.state.panes;
const activeKey = `newTab${this.newTabIndex++}`;
panes.push({ title: 'New Tab', content: 'Content of new Tab', key: activeKey });
this.setState({ panes, activeKey });
},
remove(targetKey) {
}
remove = (targetKey) => {
let activeKey = this.state.activeKey;
let lastIndex;
this.state.panes.forEach((pane, i) => {
@ -56,7 +59,7 @@ const Demo = React.createClass({
activeKey = panes[lastIndex].key;
}
this.setState({ panes, activeKey });
},
}
render() {
return (
<Tabs
@ -68,8 +71,8 @@ const Demo = React.createClass({
{this.state.panes.map(pane => <TabPane tab={pane.title} key={pane.key} closable={pane.closable}>{pane.content}</TabPane>)}
</Tabs>
);
},
});
}
}
ReactDOM.render(<Demo />, mountNode);
````

View File

@ -18,15 +18,14 @@ import { Tabs, Select } from 'antd';
const TabPane = Tabs.TabPane;
const Option = Select.Option;
const Demo = React.createClass({
getInitialState() {
return {
class Demo extends React.Component {
state = {
tabPosition: 'top',
};
},
changeTabPosition(tabPosition) {
}
changeTabPosition = (tabPosition) => {
this.setState({ tabPosition });
},
}
render() {
return (
<div>
@ -48,8 +47,8 @@ const Demo = React.createClass({
</Tabs>
</div>
);
},
});
}
}
ReactDOM.render(<Demo />, mountNode);
````

View File

@ -1,6 +1,7 @@
import React from 'react';
import { mount } from 'enzyme';
import Tooltip from '..';
import Button from '../../button';
describe('Tooltip', () => {
it('check `onVisibleChange` arguments', () => {
@ -49,4 +50,67 @@ describe('Tooltip', () => {
expect(onVisibleChange.mock.calls.length).toBe(lastCount); // no change with lastCount
expect(wrapper.ref('tooltip').prop('visible')).toBe(false);
});
it('should hide when mouse leave native disabled button', () => {
const onVisibleChange = jest.fn();
const wrapper = mount(
<Tooltip
title="xxxxx"
mouseEnterDelay={0}
mouseLeaveDelay={0}
onVisibleChange={onVisibleChange}
>
<button disabled>Hello world!</button>
</Tooltip>
);
expect(wrapper.find('span')).toHaveLength(1);
const button = wrapper.find('span').at(0);
button.simulate('mouseenter');
expect(onVisibleChange).toBeCalledWith(true);
expect(wrapper.ref('tooltip').prop('visible')).toBe(true);
button.simulate('mouseleave');
expect(onVisibleChange).toBeCalledWith(false);
expect(wrapper.ref('tooltip').prop('visible')).toBe(false);
});
it('should hide when mouse leave antd disabled Button', () => {
const onVisibleChange = jest.fn();
const wrapper = mount(
<Tooltip
title="xxxxx"
mouseEnterDelay={0}
mouseLeaveDelay={0}
onVisibleChange={onVisibleChange}
>
<Button disabled>Hello world!</Button>
</Tooltip>
);
expect(wrapper.getDOMNode().tagName).toBe('SPAN');
const button = wrapper.find('span').at(0);
button.simulate('mouseenter');
expect(onVisibleChange).toBeCalledWith(true);
expect(wrapper.ref('tooltip').prop('visible')).toBe(true);
button.simulate('mouseleave');
expect(onVisibleChange).toBeCalledWith(false);
expect(wrapper.ref('tooltip').prop('visible')).toBe(false);
});
it('should render disabled Button style properly', () => {
const wrapper1 = mount(
<Tooltip title="xxxxx">
<Button disabled>Hello world!</Button>
</Tooltip>
);
const wrapper2 = mount(
<Tooltip title="xxxxx">
<Button disabled style={{ display: 'block' }}>Hello world!</Button>
</Tooltip>
);
expect(wrapper1.getDOMNode().style.display).toBe('inline-block');
expect(wrapper2.getDOMNode().style.display).toBe('block');
});
});

View File

@ -85,6 +85,32 @@ export default class Tooltip extends React.Component<TooltipProps, any> {
});
}
// Fix Tooltip won't hide at disabled button
// mouse events don't trigger at disabled button in Chrome
// https://github.com/react-component/tooltip/issues/18
getDisabledCompatibleChildren(element) {
if ((element.type.__ANT_BUTTON || element.type === 'button') && element.props.disabled) {
// reserve display style for <Button style={{ display: 'block '}}></Button>
// Note:
// If people override ant-btn's style.display by css,
// it will be affected cause we reset it to 'inline-block'
const displayStyle = (element.props.style && element.props.style.display)
? element.props.style.display : 'inline-block';
const child = cloneElement(element, {
style: {
...element.props.style,
pointerEvents: 'none',
},
});
return (
<span style={{ display: displayStyle, cursor: 'not-allowed' }}>
{child}
</span>
);
}
return element;
}
isNoTitle() {
const { title, overlay } = this.props;
return !title && !overlay; // overlay for old version compatibility
@ -132,7 +158,9 @@ export default class Tooltip extends React.Component<TooltipProps, any> {
visible = false;
}
const child = React.isValidElement(children) ? children : <span>{children}</span>;
const child = this.getDisabledCompatibleChildren(
React.isValidElement(children) ? children : <span>{children}</span>
);
const childProps = child.props;
const childCls = classNames(childProps.className, {
[openClassName || `${prefixCls}-open`]: true,

View File

@ -18,17 +18,15 @@ You can customize the labels of the transfer buttons, the width and height of th
````jsx
import { Transfer, Button } from 'antd';
const App = React.createClass({
getInitialState() {
return {
class App extends React.Component {
state = {
mockData: [],
targetKeys: [],
};
},
}
componentDidMount() {
this.getMock();
},
getMock() {
}
getMock = () => {
const targetKeys = [];
const mockData = [];
for (let i = 0; i < 20; i++) {
@ -44,11 +42,11 @@ const App = React.createClass({
mockData.push(data);
}
this.setState({ mockData, targetKeys });
},
handleChange(targetKeys) {
}
handleChange = (targetKeys) => {
this.setState({ targetKeys });
},
renderFooter() {
}
renderFooter = () => {
return (
<Button size="small" style={{ float: 'right', margin: 5 }}
onClick={this.getMock}
@ -56,7 +54,7 @@ const App = React.createClass({
reload
</Button>
);
},
}
render() {
return (
<Transfer
@ -73,8 +71,8 @@ const App = React.createClass({
footer={this.renderFooter}
/>
);
},
});
}
}
ReactDOM.render(<App />, mountNode);
````

View File

@ -30,26 +30,27 @@ const targetKeys = mockData
.filter(item => +item.key % 3 > 1)
.map(item => item.key);
const App = React.createClass({
getInitialState() {
return {
class App extends React.Component {
state = {
targetKeys,
selectedKeys: [],
};
},
handleChange(nextTargetKeys, direction, moveKeys) {
}
handleChange = (nextTargetKeys, direction, moveKeys) => {
this.setState({ targetKeys: nextTargetKeys });
console.log('targetKeys: ', targetKeys);
console.log('direction: ', direction);
console.log('moveKeys: ', moveKeys);
},
handleSelectChange(sourceSelectedKeys, targetSelectedKeys) {
}
handleSelectChange = (sourceSelectedKeys, targetSelectedKeys) => {
this.setState({ selectedKeys: [...sourceSelectedKeys, ...targetSelectedKeys] });
console.log('sourceSelectedKeys: ', sourceSelectedKeys);
console.log('targetSelectedKeys: ', targetSelectedKeys);
},
}
render() {
const state = this.state;
return (
@ -63,8 +64,8 @@ const App = React.createClass({
render={item => item.title}
/>
);
},
});
}
}
ReactDOM.render(<App />, mountNode);
````

View File

@ -16,17 +16,15 @@ Custom each Transfer Item, and in this way you can render a complex datasource.
````jsx
import { Transfer } from 'antd';
const App = React.createClass({
getInitialState() {
return {
class App extends React.Component {
state = {
mockData: [],
targetKeys: [],
};
},
}
componentDidMount() {
this.getMock();
},
getMock() {
}
getMock = () => {
const targetKeys = [];
const mockData = [];
for (let i = 0; i < 20; i++) {
@ -42,12 +40,12 @@ const App = React.createClass({
mockData.push(data);
}
this.setState({ mockData, targetKeys });
},
handleChange(targetKeys, direction, moveKeys) {
}
handleChange = (targetKeys, direction, moveKeys) => {
console.log(targetKeys, direction, moveKeys);
this.setState({ targetKeys });
},
renderItem(item) {
}
renderItem = (item) => {
const customLabel = (
<span className="custom-item">
{item.title} - {item.description}
@ -58,7 +56,7 @@ const App = React.createClass({
label: customLabel, // for displayed item
value: item.title, // for title and filter matching
};
},
}
render() {
return (
<Transfer
@ -72,8 +70,8 @@ const App = React.createClass({
render={this.renderItem}
/>
);
},
});
}
}
ReactDOM.render(<App />, mountNode);
````

View File

@ -17,17 +17,15 @@ title:
````jsx
import { Transfer } from 'antd';
const App = React.createClass({
getInitialState() {
return {
class App extends React.Component {
state = {
mockData: [],
targetKeys: [],
};
},
}
componentDidMount() {
this.getMock();
},
getMock() {
}
getMock = () => {
const targetKeys = [];
const mockData = [];
for (let i = 0; i < 2000; i++) {
@ -43,11 +41,11 @@ const App = React.createClass({
mockData.push(data);
}
this.setState({ mockData, targetKeys });
},
handleChange(targetKeys, direction, moveKeys) {
}
handleChange = (targetKeys, direction, moveKeys) => {
console.log(targetKeys, direction, moveKeys);
this.setState({ targetKeys });
},
}
render() {
return (
<Transfer
@ -57,8 +55,8 @@ const App = React.createClass({
render={item => item.title}
/>
);
},
});
}
}
ReactDOM.render(<App />, mountNode);
````

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