Merge branch 'master' of github.com:ant-design/ant-design

This commit is contained in:
afc163 2016-11-08 18:04:08 +08:00
commit 64899c5da2
5 changed files with 98 additions and 74 deletions

View File

@ -1,12 +1,12 @@
import React from 'react';
import { PropTypes } from 'react';
import classNames from 'classnames';
import createDOMForm from 'rc-form/lib/createDOMForm';
import PureRenderMixin from 'rc-util/lib/PureRenderMixin';
import omit from 'omit.js';
import warning from 'warning';
import assign from 'object-assign';
import warning from '../_util/warning';
import FormItem from './FormItem';
import createDOMForm from 'rc-form/lib/createDOMForm';
import { FIELD_META_PROP } from './constants';
export interface FormCreateOption {
@ -121,14 +121,14 @@ export default class Form extends React.Component<FormProps, any> {
};
},
componentWillMount() {
this.getFieldProps = this.deprecatedGetFieldProps;
this.__getFieldProps = this.props.form.getFieldProps;
},
deprecatedGetFieldProps(name, option) {
warning(
false,
'`getFieldProps` is not recommended, please use `getFieldDecorator` instead'
);
return this.getFieldProps(name, option);
return this.__getFieldProps(name, option);
},
render() {
this.props.form.getFieldProps = this.deprecatedGetFieldProps;

View File

@ -16,47 +16,47 @@ The most basic usage of `Transfer` involves providing the source data and target
````jsx
import { Transfer } from 'antd';
const mockData = [];
for (let i = 0; i < 20; i++) {
mockData.push({
key: i.toString(),
title: `content${i + 1}`,
description: `description of content${i + 1}`,
disabled: Math.random() * 3 < 1,
});
}
const targetKeys = mockData
.filter(() => Math.random() * 2 > 1)
.map(item => item.key);
const App = React.createClass({
getInitialState() {
return {
mockData: [],
targetKeys: [],
targetKeys,
selectedKeys: [],
};
},
componentDidMount() {
this.getMock();
},
getMock() {
const targetKeys = [];
const mockData = [];
for (let i = 0; i < 20; i++) {
const data = {
key: i.toString(),
title: `content${i + 1}`,
description: `description of content${i + 1}`,
chosen: Math.random() * 2 > 1,
disabled: Math.random() * 3 < 1,
};
if (data.chosen) {
targetKeys.push(data.key);
}
mockData.push(data);
}
this.setState({ mockData, targetKeys });
},
handleChange(targetKeys, direction, moveKeys) {
console.log(targetKeys, direction, moveKeys);
this.setState({ targetKeys });
handleChange(nextTargetKeys, direction, moveKeys) {
this.setState({ targetKeys: nextTargetKeys });
console.log('targetKeys: ', targetKeys);
console.log('direction: ', direction);
console.log('moveKeys: ', moveKeys);
},
handleSelectChange(sourceSelectedKeys, targetSelectedKeys) {
this.setState({ selectedKeys: [...sourceSelectedKeys, ...targetSelectedKeys] });
console.log('sourceSelectedKeys: ', sourceSelectedKeys);
console.log('targetSelectedKeys: ', targetSelectedKeys);
},
render() {
const state = this.state;
return (
<Transfer
dataSource={this.state.mockData}
targetKeys={this.state.targetKeys}
dataSource={mockData}
targetKeys={state.targetKeys}
selectedKeys={state.selectedKeys}
onChange={this.handleChange}
onSelectChange={this.handleSelectChange}
render={item => item.title}

View File

@ -19,17 +19,19 @@ To transfer the elements between two columns in an intuitive and efficient way.
|-----------|------------------------------------------|------------|--------|
| dataSource | Used for setting the source data. The elements that are part of this array will be present the left column. Except the elements whose keys are included in `targetKeys` prop. | Array | [] |
| render | The function to generate the item shown on a column. Based on an record (element of the dataSource array), this function should return a React element which is generated from that record. | Function(record) | |
| targetKeys | A set of keys of elements that are listed on the right column. | Array | [] |
| onChange | A callback function that is executed when the transfer between columns is complete. | Function(targetKeys, direction, moveKeys) | |
| onSelectChange | A callback function which is executed when selected items are changed. | Function(sourceSelectedKeys, targetSelectedKeys) | |
| targetKeys | A set of keys of elements that are listed on the right column. | string[] | [] |
| selectedKeys | A set of keys of selected items. | string[] | [] |
| onChange | A callback function that is executed when the transfer between columns is complete. | (targetKeys, direction, moveKeys): void | |
| onSelectChange | A callback function which is executed when selected items are changed. | (sourceSelectedKeys, targetSelectedKeys): void | |
| listStyle | A custom CSS style used for rendering the transfer columns. | Object | |
| className | A custom CSS class. | String | |
| titles | A set of titles that are sorted from left to right. | Array | ['Source, 'Target] |
| operations | A set of operations that are sorted from top to bottom. | Array | [] |
| showSearch | If included, a search box is shown on each column. | Boolean | false |
| filterOption | A function to determine whether an item should show in search result list | (inputValue, option): boolean | |
| searchPlaceholder | The hint text of the search box. | String | 'Search here' |
| notFoundContent | Text to display when a column is empty. | React.node | 'The list is empty' |
| footer | A function used for rendering the footer. | Function(props) | |
| notFoundContent | Text to display when a column is empty. | React.ReactNode | 'The list is empty' |
| footer | A function used for rendering the footer. | (props): React.ReactNode | |
| lazy | property of [react-lazy-load](https://github.com/loktar00/react-lazy-load) for lazy rendering items | Object | `{ height: 32, offset: 32 }` |
## Warning

View File

@ -19,18 +19,19 @@ export interface TransferItem {
export interface TransferProps {
dataSource: TransferItem[];
targetKeys: string[];
render?: (record: TransferItem) => any;
onChange?: (targetKeys: TransferItem[], direction: string, moveKeys: any) => void;
selectedKeys?: string[];
render?: (record: TransferItem) => React.ReactNode;
onChange?: (targetKeys: string[], direction: string, moveKeys: any) => void;
onSelectChange?: (sourceSelectedKeys: string[], targetSelectedKeys: string[]) => void;
listStyle?: React.CSSProperties;
className?: string;
prefixCls?: string;
className?: string;
titles?: string[];
operations?: string[];
showSearch?: boolean;
searchPlaceholder?: string;
notFoundContent?: React.ReactNode;
footer?: (props: any) => any;
footer?: (props: any) => React.ReactNode;
style?: React.CSSProperties;
filterOption: (inputValue: any, item: any) => boolean;
body?: (props: any) => any;
@ -46,6 +47,7 @@ export interface TransferContext {
const defaultTitles = ['源列表', '目的列表'];
export default class Transfer extends React.Component<TransferProps, any> {
// For high-level customized Transfer @dqaria
static List = List;
static Operation = Operation;
static Search = Search;
@ -84,18 +86,20 @@ export default class Transfer extends React.Component<TransferProps, any> {
context: TransferContext;
splitedDataSource: any;
constructor(props) {
constructor(props: TransferProps) {
super(props);
const { selectedKeys = [], targetKeys = [] } = props;
this.state = {
leftFilter: '',
rightFilter: '',
leftCheckedKeys: [],
rightCheckedKeys: [],
sourceSelectedKeys: selectedKeys.filter(key => targetKeys.indexOf(key) === -1),
targetSelectedKeys: selectedKeys.filter(key => targetKeys.indexOf(key) > -1),
};
}
componentWillReceiveProps(nextProps) {
const { leftCheckedKeys, rightCheckedKeys } = this.state;
componentWillReceiveProps(nextProps: TransferProps) {
const { sourceSelectedKeys, targetSelectedKeys } = this.state;
if (nextProps.targetKeys !== this.props.targetKeys ||
nextProps.dataSource !== this.props.dataSource) {
// clear cached splited dataSource
@ -108,12 +112,19 @@ export default class Transfer extends React.Component<TransferProps, any> {
// clear key nolonger existed
// clear checkedKeys according to targetKeys
this.setState({
leftCheckedKeys: leftCheckedKeys.filter(existInDateSourcekey)
sourceSelectedKeys: sourceSelectedKeys.filter(existInDateSourcekey)
.filter(data => targetKeys.filter(key => key === data).length === 0),
rightCheckedKeys: rightCheckedKeys.filter(existInDateSourcekey)
targetSelectedKeys: targetSelectedKeys.filter(existInDateSourcekey)
.filter(data => targetKeys.filter(key => key === data).length > 0),
});
}
if (nextProps.selectedKeys) {
const targetKeys = nextProps.targetKeys;
this.setState({
sourceSelectedKeys: nextProps.selectedKeys.filter(key => targetKeys.indexOf(key) === -1),
targetSelectedKeys: nextProps.selectedKeys.filter(key => targetKeys.indexOf(key) > -1),
});
}
}
splitDataSource(props: TransferProps) {
if (this.splitedDataSource) {
@ -146,8 +157,8 @@ export default class Transfer extends React.Component<TransferProps, any> {
moveTo = (direction) => {
const { targetKeys = [], onChange } = this.props;
const { leftCheckedKeys, rightCheckedKeys } = this.state;
const moveKeys = direction === 'right' ? leftCheckedKeys : rightCheckedKeys;
const { sourceSelectedKeys, targetSelectedKeys } = this.state;
const moveKeys = direction === 'right' ? sourceSelectedKeys : targetSelectedKeys;
// move items to target box
const newTargetKeys = direction === 'right'
? moveKeys.concat(targetKeys)
@ -156,7 +167,7 @@ export default class Transfer extends React.Component<TransferProps, any> {
// empty checked keys
const oppositeDirection = direction === 'right' ? 'left' : 'right';
this.setState({
[`${oppositeDirection}CheckedKeys`]: [],
[this.getSelectedKeysName(oppositeDirection)]: [],
});
this.handleSelectChange(oppositeDirection, []);
@ -169,25 +180,28 @@ export default class Transfer extends React.Component<TransferProps, any> {
moveToRight = () => this.moveTo('right')
handleSelectChange(direction: string, holder: string[]) {
const { leftCheckedKeys, rightCheckedKeys } = this.state;
const { sourceSelectedKeys, targetSelectedKeys } = this.state;
const onSelectChange = this.props.onSelectChange;
if (!onSelectChange) {
return;
}
if (direction === 'left') {
onSelectChange(holder, rightCheckedKeys);
onSelectChange(holder, targetSelectedKeys);
} else {
onSelectChange(leftCheckedKeys, holder);
onSelectChange(sourceSelectedKeys, holder);
}
}
handleSelectAll = (direction, filteredDataSource, checkAll) => {
const holder = checkAll ? [] : filteredDataSource.map(item => item.key);
this.setState({
[`${direction}CheckedKeys`]: holder,
});
this.handleSelectChange(direction, holder);
if (!this.props.selectedKeys) {
this.setState({
[this.getSelectedKeysName(direction)]: holder,
});
}
}
handleLeftSelectAll = (filteredDataSource, checkAll) => (
@ -217,8 +231,8 @@ export default class Transfer extends React.Component<TransferProps, any> {
handleRightClear = () => this.handleClear('right')
handleSelect = (direction, selectedItem, checked) => {
const { leftCheckedKeys, rightCheckedKeys } = this.state;
const holder = direction === 'left' ? [...leftCheckedKeys] : [...rightCheckedKeys];
const { sourceSelectedKeys, targetSelectedKeys } = this.state;
const holder = direction === 'left' ? [...sourceSelectedKeys] : [...targetSelectedKeys];
let index;
holder.forEach((key, i) => {
if (key === selectedItem.key) {
@ -231,10 +245,13 @@ export default class Transfer extends React.Component<TransferProps, any> {
if (checked) {
holder.push(selectedItem.key);
}
this.setState({
[`${direction}CheckedKeys`]: holder,
});
this.handleSelectChange(direction, holder);
if (!this.props.selectedKeys) {
this.setState({
[this.getSelectedKeysName(direction)]: holder,
});
}
}
handleLeftSelect = (selectedItem, checked) => this.handleSelect('left', selectedItem, checked);
@ -253,17 +270,21 @@ export default class Transfer extends React.Component<TransferProps, any> {
return defaultTitles;
}
getSelectedKeysName(direction) {
return direction === 'left' ? 'sourceSelectedKeys' : 'targetSelectedKeys';
}
render() {
const {
prefixCls = 'ant-transfer', operations = [], showSearch, notFoundContent,
searchPlaceholder, body, footer, listStyle, className = '',
filterOption, render, lazy,
} = this.props;
const { leftFilter, rightFilter, leftCheckedKeys, rightCheckedKeys } = this.state;
const { leftFilter, rightFilter, sourceSelectedKeys, targetSelectedKeys } = this.state;
const { leftDataSource, rightDataSource } = this.splitDataSource(this.props);
const leftActive = rightCheckedKeys.length > 0;
const rightActive = leftCheckedKeys.length > 0;
const leftActive = targetSelectedKeys.length > 0;
const rightActive = sourceSelectedKeys.length > 0;
const cls = classNames({
[className]: !!className,
@ -279,7 +300,7 @@ export default class Transfer extends React.Component<TransferProps, any> {
filter={leftFilter}
filterOption={filterOption}
style={listStyle}
checkedKeys={leftCheckedKeys}
checkedKeys={sourceSelectedKeys}
handleFilter={this.handleLeftFilter}
handleClear={this.handleLeftClear}
handleSelect={this.handleLeftSelect}
@ -308,7 +329,7 @@ export default class Transfer extends React.Component<TransferProps, any> {
filter={rightFilter}
filterOption={filterOption}
style={listStyle}
checkedKeys={rightCheckedKeys}
checkedKeys={targetSelectedKeys}
handleFilter={this.handleRightFilter}
handleClear={this.handleRightClear}
handleSelect={this.handleRightSelect}

View File

@ -20,18 +20,19 @@ title: Transfer
|-----------|------------------------------------------|------------|--------|
| dataSource | 数据源,其中的数据将会被渲染到左边一栏中,`targetKeys` 中指定的除外。 | Array | [] |
| render | 每行数据渲染函数,该函数的入参为 `dataSource` 中的项,返回值为 React element | Function(record) | |
| targetKeys | 显示在右侧框数据的key集合 | Array | [] |
| onChange | 选项在两栏之间转移时的回调函数 | Function(targetKeys, direction, moveKeys) | |
| onSelectChange | 选中项发生改变时的回调函数 | Function(sourceSelectedKeys, targetSelectedKeys) | |
| targetKeys | 显示在右侧框数据的key集合 | string[] | [] |
| selectedKeys | 设置哪些项应该被选中 | string[] | [] |
| onChange | 选项在两栏之间转移时的回调函数 | (targetKeys, direction, moveKeys): void | |
| onSelectChange | 选中项发生改变时的回调函数 | (sourceSelectedKeys, targetSelectedKeys): void | |
| listStyle | 两个穿梭框的自定义样式 | Object | |
| className | 自定义类 | String | |
| titles | 标题集合,顺序从左至右 | Array | ['源列表', '目的列表'] |
| operations | 操作文案集合,顺序从上至下 | Array | [] |
| showSearch | 是否显示搜索框 | Boolean | false |
| filterOption | 接收 `inputValue` `option` 两个参数,当 `option` 符合筛选条件时,应返回 `true`,反之则返回 `false`。| Function(inputValue, option) | |
| searchPlaceholder | 搜索框的默认值 | String | '请输入搜索内容' |
| notFoundContent | 当列表为空时显示的内容 | React.node | '列表为空' |
| footer | 底部渲染函数 | Function(props) | |
| filterOption | 接收 `inputValue` `option` 两个参数,当 `option` 符合筛选条件时,应返回 `true`,反之则返回 `false`。| (inputValue, option): boolean | |
| searchPlaceholder | 搜索框的默认值 | string | '请输入搜索内容' |
| notFoundContent | 当列表为空时显示的内容 | React.ReactNode | '列表为空' |
| footer | 底部渲染函数 | (props): React.ReactNode | |
| lazy | Transfer 使用了 [react-lazy-load](https://github.com/loktar00/react-lazy-load) 优化性能,这里可以设置相关参数 | Object | `{ height: 32, offset: 32 }` |
## 注意