Merge remote-tracking branch 'upstream/master' into vertical-steps

This commit is contained in:
zhujun24 2015-08-31 15:16:02 +08:00
commit d720a908a0
46 changed files with 436 additions and 162 deletions

View File

@ -1,3 +1,29 @@
## 0.8.1 (2015-08-31)
### Table
* 新增无数据的展示样式。[4c54644](https://github.com/ant-design/ant-design/commit/4c54644116d46cb2510d2d475234529bad60e5d5)
* 修复本地模式 `dataSource` 无法更新的问题。[6d2dcc4](https://github.com/ant-design/ant-design/commit/6d2dcc45393b6ec0ad1ba73caf8b1ec42353743f)
* 修复远程模式 loading 失效的问题。[9b8abb2](https://github.com/ant-design/ant-design/commit/9b8abb219934c246970a84200818aa8f85974bdf)
### Upload
* 新增 `onRemove(file) {}` 接口,作为移除上传文件的回调。
* 新增 `urlResolver(res) {}` 接口,可以拿到请求回调数据里的远程文件地址,展示在文件列表中方便下载。
* 新增 `limit` 属性,用于限制文件上传列表的数量。
### Notification
* 修复不会自动消失的问题。[23fce55](https://github.com/ant-design/ant-design/commit/23fce559b0b2faf4e0b686a92dbcdd045727a464)
### Steps
* 新增竖版的步骤条。
### Carousel
* 修复 fade 模式下可以拖拽的问题。#212
## 0.8.0 (2015-08-25) ## 0.8.0 (2015-08-25)
这个版本是第一个稳定版,组件经过三期迭代,基本到齐,并有大量改进和变化,不向下兼容。 这个版本是第一个稳定版,组件经过三期迭代,基本到齐,并有大量改进和变化,不向下兼容。

View File

@ -14,6 +14,7 @@ const AntCarousel = React.createClass({
if (props.effect === 'fade') { if (props.effect === 'fade') {
props.fade = true; props.fade = true;
props.draggable = false;
} }
let className = 'ant-carousel'; let className = 'ant-carousel';

View File

@ -27,13 +27,13 @@ function animate(node, show, transitionName, done) {
const animation = { const animation = {
enter(node, done) { enter(node, done) {
animate(node, false, 'slideDown', done); return animate(node, false, 'slideDown', done);
}, },
leave(node, done) { leave(node, done) {
animate(node, true, 'slideUp', done); return animate(node, true, 'slideUp', done);
}, },
appear(node, done) { appear(node, done) {
animate(node, false, 'slideDown', done); return animate(node, false, 'slideDown', done);
}, },
}; };

View File

@ -16,7 +16,7 @@ let defaultCalendarValue = new GregorianCalendar(zhCn);
defaultCalendarValue.setTime(Date.now()); defaultCalendarValue.setTime(Date.now());
function createPicker(Calendar){ function createPicker(Calendar) {
return React.createClass({ return React.createClass({
getInitialState() { getInitialState() {
var value; var value;

View File

@ -37,7 +37,7 @@ React.render(
<div className="ant-input-group"> <div className="ant-input-group">
<input type="text" className="ant-input" id="site4" placeholder="www.mysite" /> <input type="text" className="ant-input" id="site4" placeholder="www.mysite" />
<div className="ant-input-group-wrap"> <div className="ant-input-group-wrap">
<Select value=".com" style={{width:65}}> <Select defaultValue=".com" style={{width:70}}>
<Option value=".com">.com</Option> <Option value=".com">.com</Option>
<Option value=".jp">.jp</Option> <Option value=".jp">.jp</Option>
<Option value=".cn">.cn</Option> <Option value=".cn">.cn</Option>

View File

@ -1,6 +1,5 @@
import React from 'react'; import React from 'react';
import Menu from 'rc-menu'; import Menu from 'rc-menu';
import velocity from 'velocity-animate';
import animation from '../common/openAnimation'; import animation from '../common/openAnimation';
const AntMenu = React.createClass({ const AntMenu = React.createClass({

View File

@ -2,7 +2,7 @@
- order: 1 - order: 1
自定义通知框自动关闭的延时,默认`3s`,取消自动关闭只要将该值设为`0`即可。 自定义通知框自动关闭的延时,默认`4.5s`,取消自动关闭只要将该值设为 `0` 即可。
--- ---

View File

@ -22,7 +22,7 @@ function getNotificationInstance() {
function notice(args) { function notice(args) {
let duration; let duration;
if (args.duration === undefined) { if (args.duration === undefined) {
duration = 500; duration = 4.5;
} else { } else {
duration = args.duration; duration = args.duration;
} }

View File

@ -34,7 +34,7 @@ config 参数如下:
| btn | 自定义关闭按钮 | React.Element | 无 | | btn | 自定义关闭按钮 | React.Element | 无 |
| key | 当前通知唯一标志 | String | 无 | | key | 当前通知唯一标志 | String | 无 |
| onClose | 点击默认关闭按钮时触发的回调函数 | Function | 无 | | onClose | 点击默认关闭按钮时触发的回调函数 | Function | 无 |
| duration | 默认秒后自动关闭,配置为 null 则不自动关闭 | Number | 5 | | duration | 默认 4.5 秒后自动关闭,配置为 null 则不自动关闭 | Number | 4.5 |
还提供了一个全局配置方法,需要在调用前提前配置,一次有效。 还提供了一个全局配置方法,需要在调用前提前配置,一次有效。

View File

@ -54,7 +54,7 @@ var Line = React.createClass({
}else { }else {
fullCls = ' ' + prefixCls + '-line-wrap-full'; fullCls = ' ' + prefixCls + '-line-wrap-full';
} }
var persentStyle = { var percentStyle = {
width: props.percent + '%', width: props.percent + '%',
height: props.strokeWidth height: props.strokeWidth
}; };
@ -64,7 +64,7 @@ var Line = React.createClass({
{progressInfo} {progressInfo}
<div className={prefixCls + '-line-outer'}> <div className={prefixCls + '-line-outer'}>
<div className={prefixCls + '-line-inner'}> <div className={prefixCls + '-line-inner'}>
<div className={prefixCls + '-line-bg'} style={persentStyle}></div> <div className={prefixCls + '-line-bg'} style={percentStyle}></div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -3,7 +3,7 @@ import Radio from './radio';
function getCheckedValue(children) { function getCheckedValue(children) {
var checkedValue = null; var checkedValue = null;
children.forEach(function (radio) { React.Children.forEach(children, function (radio) {
if (radio.props && radio.props.checked) { if (radio.props && radio.props.checked) {
checkedValue = radio.props.value; checkedValue = radio.props.value;
} }
@ -34,7 +34,7 @@ export default React.createClass({
}, },
render: function () { render: function () {
var props = this.props; var props = this.props;
var children = props.children.map((radio) => { var children = React.Children.map(props.children, (radio) => {
if (radio.props) { if (radio.props) {
return <Radio return <Radio
key={radio.props.value} key={radio.props.value}

View File

@ -22,7 +22,7 @@ function handleChange(value) {
React.render( React.render(
<Select <Select
style={{width:400}} style={{width: '100%'}}
tags defaultValue={['name2', 'name3']} onChange={handleChange}> tags defaultValue={['name2', 'name3']} onChange={handleChange}>
{children} {children}
</Select> </Select>

View File

@ -35,6 +35,7 @@ var dataSource = new Table.DataSource({
resolve: function(result) { resolve: function(result) {
return result.data; return result.data;
}, },
data: {},
// 和后台接口返回的分页数据进行适配 // 和后台接口返回的分页数据进行适配
getPagination: function(result) { getPagination: function(result) {
return { return {

View File

@ -36,14 +36,17 @@ var columns = [{
} }
}]; }];
var data = [{ var data = [{
key: '1',
name: '胡彦斌', name: '胡彦斌',
age: 32, age: 32,
address: '西湖区湖底公园1号' address: '西湖区湖底公园1号'
}, { }, {
key: '2',
name: '胡彦祖', name: '胡彦祖',
age: 42, age: 42,
address: '西湖区湖底公园1号' address: '西湖区湖底公园1号'
}, { }, {
key: '3',
name: '李大嘴', name: '李大嘴',
age: 32, age: 32,
address: '西湖区湖底公园1号' address: '西湖区湖底公园1号'

View File

@ -23,14 +23,17 @@ var columns = [{
}]; }];
var data = [{ var data = [{
key: '1',
name: '胡彦斌', name: '胡彦斌',
age: 32, age: 32,
address: '西湖区湖底公园1号' address: '西湖区湖底公园1号'
}, { }, {
key: '2',
name: '胡彦祖', name: '胡彦祖',
age: 42, age: 42,
address: '西湖区湖底公园1号' address: '西湖区湖底公园1号'
}, { }, {
key: '3',
name: '李大嘴', name: '李大嘴',
age: 32, age: 32,
address: '西湖区湖底公园1号' address: '西湖区湖底公园1号'

View File

@ -1,41 +1,51 @@
{ {
"data": [{ "data": [{
"key": "1",
"name": "胡彦斌ajax1", "name": "胡彦斌ajax1",
"age": 32, "age": 32,
"address": "西湖区湖底公园1号" "address": "西湖区湖底公园1号"
}, { }, {
"key": "2",
"name": "胡彦祖ajax2", "name": "胡彦祖ajax2",
"age": 42, "age": 42,
"address": "西湖区湖底公园1号" "address": "西湖区湖底公园1号"
}, { }, {
"key": "3",
"name": "李大嘴ajax3", "name": "李大嘴ajax3",
"age": 32, "age": 32,
"address": "西湖区湖底公园1号" "address": "西湖区湖底公园1号"
}, { }, {
"key": "4",
"name": "李大嘴ajax4", "name": "李大嘴ajax4",
"age": 32, "age": 32,
"address": "西湖区湖底公园1号" "address": "西湖区湖底公园1号"
}, { }, {
"key": "5",
"name": "李大嘴ajax5", "name": "李大嘴ajax5",
"age": 32, "age": 32,
"address": "西湖区湖底公园1号" "address": "西湖区湖底公园1号"
}, { }, {
"key": "6",
"name": "李大嘴ajax6", "name": "李大嘴ajax6",
"age": 32, "age": 32,
"address": "西湖区湖底公园1号" "address": "西湖区湖底公园1号"
}, { }, {
"key": "7",
"name": "李大嘴ajax7", "name": "李大嘴ajax7",
"age": 32, "age": 32,
"address": "西湖区湖底公园1号" "address": "西湖区湖底公园1号"
}, { }, {
"key": "8",
"name": "李大嘴ajax8", "name": "李大嘴ajax8",
"age": 32, "age": 32,
"address": "西湖区湖底公园1号" "address": "西湖区湖底公园1号"
}, { }, {
"key": "9",
"name": "李大嘴ajax9", "name": "李大嘴ajax9",
"age": 32, "age": 32,
"address": "西湖区湖底公园1号" "address": "西湖区湖底公园1号"
}, { }, {
"key": "10",
"name": "李大嘴ajax10", "name": "李大嘴ajax10",
"age": 32, "age": 32,
"address": "西湖区湖底公园1号" "address": "西湖区湖底公园1号"

View File

@ -43,18 +43,22 @@ var columns = [{
}]; }];
var data = [{ var data = [{
key: '1',
name: '胡斌', name: '胡斌',
age: 32, age: 32,
address: '西湖区湖底公园1号' address: '西湖区湖底公园1号'
}, { }, {
key: '2',
name: '胡彦祖', name: '胡彦祖',
age: 42, age: 42,
address: '西湖区湖底公园12号' address: '西湖区湖底公园12号'
}, { }, {
key: '3',
name: '李大嘴', name: '李大嘴',
age: 32, age: 32,
address: '西湖区湖底公园123号' address: '西湖区湖底公园123号'
}, { }, {
key: '4',
name: '李秀莲大嘴哥', name: '李秀莲大嘴哥',
age: 32, age: 32,
address: '西湖区湖底公园123号' address: '西湖区湖底公园123号'

View File

@ -0,0 +1,86 @@
# 外界控制数据
- order: 11
由父元素控制自身数据展示。
---
````jsx
var Table = antd.Table;
var columns = [{
title: '姓名',
dataIndex: 'name',
render: function(text) {
return <a href="javascript:;">{text}</a>;
}
}, {
title: '年龄',
dataIndex: 'age'
}, {
title: '住址',
dataIndex: 'address'
}];
var data1 = [{
key: '1',
name: '胡彦斌',
age: 32,
address: '西湖区湖底公园1号'
}, {
key: '2',
name: '胡彦祖',
age: 42,
address: '西湖区湖底公园1号'
}, {
key: '3',
name: '李大嘴',
age: 32,
address: '西湖区湖底公园1号'
}];
var data2 = [{
key: '11',
name: '胡彦斌2',
age: 32,
address: '西湖区湖底公园2号'
}, {
key: '22',
name: '胡彦祖2',
age: 42,
address: '西湖区湖底公园2号'
}, {
key: '33',
name: '李大嘴2',
age: 32,
address: '西湖区湖底公园2号'
}];
var App = React.createClass({
getInitialState() {
return {
data: []
};
},
handleClick1() {
this.setState({
data: data1
});
},
handleClick2() {
this.setState({
data: data2
});
},
render() {
return <div>
<Table columns={columns} dataSource={this.state.data} />
<button className="ant-btn" onClick={this.handleClick1}>加载本地数据1</button>
&nbsp;
<button className="ant-btn" onClick={this.handleClick2}>加载本地数据2</button>
</div>;
}
})
React.render(<App />
, document.getElementById('components-table-demo-local-data'));
````

View File

@ -20,14 +20,17 @@ var columns = [{
}]; }];
var data = [{ var data = [{
key: '1',
name: '胡彦斌', name: '胡彦斌',
age: 32, age: 32,
address: '西湖区湖底公园1号' address: '西湖区湖底公园1号'
}, { }, {
key: '2',
name: '胡彦祖', name: '胡彦祖',
age: 42, age: 42,
address: '西湖区湖底公园1号' address: '西湖区湖底公园1号'
}, { }, {
key: '3',
name: '李大嘴', name: '李大嘴',
age: 32, age: 32,
address: '西湖区湖底公园1号' address: '西湖区湖底公园1号'

View File

@ -26,6 +26,7 @@ var data = [];
for (let i=0; i<46; i++) { for (let i=0; i<46; i++) {
data.push({ data.push({
key: i,
name: '李大嘴' + i, name: '李大嘴' + i,
age: 32, age: 32,
address: '西湖区湖底公园' + i + '号' address: '西湖区湖底公园' + i + '号'

View File

@ -22,14 +22,17 @@ var columns = [{
dataIndex: 'address' dataIndex: 'address'
}]; }];
var data = [{ var data = [{
key: '1',
name: '胡彦斌', name: '胡彦斌',
age: 32, age: 32,
address: '西湖区湖底公园1号' address: '西湖区湖底公园1号'
}, { }, {
key: '2',
name: '胡彦祖', name: '胡彦祖',
age: 42, age: 42,
address: '西湖区湖底公园1号' address: '西湖区湖底公园1号'
}, { }, {
key: '3',
name: '李大嘴', name: '李大嘴',
age: 32, age: 32,
address: '西湖区湖底公园1号' address: '西湖区湖底公园1号'

View File

@ -19,14 +19,17 @@ var columns = [{
dataIndex: 'address' dataIndex: 'address'
}]; }];
var data = [{ var data = [{
key: '1',
name: '胡彦斌', name: '胡彦斌',
age: 32, age: 32,
address: '西湖区湖底公园1号' address: '西湖区湖底公园1号'
}, { }, {
key: '2',
name: '胡彦祖', name: '胡彦祖',
age: 42, age: 42,
address: '西湖区湖底公园1号' address: '西湖区湖底公园1号'
}, { }, {
key: '3',
name: '李大嘴', name: '李大嘴',
age: 32, age: 32,
address: '西湖区湖底公园1号' address: '西湖区湖底公园1号'

View File

@ -31,7 +31,7 @@ class DataSource {
} }
clone(config = {}) { clone(config = {}) {
return new DataSource(objectAssign(config, this.config)); return new DataSource(objectAssign({}, this.config, config));
} }
} }
@ -42,13 +42,15 @@ var AntTable = React.createClass({
selectedRowKeys: [], selectedRowKeys: [],
// only for remote // only for remote
data: [], data: [],
dataSource: this.props.dataSource,
filters: {}, filters: {},
loading: !this.isLocalDataSource(), loading: false,
sortColumn: '', sortColumn: '',
sortOrder: '', sortOrder: '',
sorter: null, sorter: null,
pagination: this.hasPagination() ? objectAssign({ pagination: this.hasPagination() ? objectAssign({
pageSize: 10 pageSize: 10,
current: 1
}, this.props.pagination) : {} }, this.props.pagination) : {}
}; };
}, },
@ -68,25 +70,23 @@ var AntTable = React.createClass({
}, },
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
let newState = {};
if (('pagination' in nextProps) && nextProps.pagination !== false) { if (('pagination' in nextProps) && nextProps.pagination !== false) {
this.setState({ newState.pagination = objectAssign({}, this.state.pagination, nextProps.pagination);
pagination: objectAssign({}, this.state.pagination, nextProps.pagination)
});
} }
if (!this.isLocalDataSource()) { // dataSource
// dataSource if ('dataSource' in nextProps &&
if (nextProps.dataSource !== this.props.dataSource) { nextProps.dataSource !== this.props.dataSource) {
this.setState({ newState = {
selectedRowKeys: [], selectedRowKeys: [],
loading: true dataSource: nextProps.dataSource,
}, this.fetch); loading: true
} };
} }
if (nextProps.columns !== this.props.columns) { if (nextProps.columns !== this.props.columns) {
this.setState({ newState.filters = {};
filters: {}
});
} }
this.setState(newState, this.fetch);
}, },
hasPagination(pagination) { hasPagination(pagination) {
@ -97,11 +97,11 @@ var AntTable = React.createClass({
}, },
isLocalDataSource() { isLocalDataSource() {
return Array.isArray(this.props.dataSource); return Array.isArray(this.state.dataSource);
}, },
getRemoteDataSource() { getRemoteDataSource() {
return this.props.dataSource; return this.state.dataSource;
}, },
toggleSortOrder(order, column) { toggleSortOrder(order, column) {
@ -295,11 +295,11 @@ var AntTable = React.createClass({
</span> </span>
</div>; </div>;
} }
column.title = [ column.title = <div>
column.title, {column.title}
sortButton, {sortButton}
filterDropdown {filterDropdown}
]; </div>;
return column; return column;
}); });
}, },
@ -313,15 +313,15 @@ var AntTable = React.createClass({
if (this.props.size === 'small') { if (this.props.size === 'small') {
classString += ' mini'; classString += ' mini';
} }
let total; let total = this.state.pagination.total;
if (this.isLocalDataSource()) { if (!total && this.isLocalDataSource()) {
total = this.getLocalData().length; total = this.getLocalData().length;
} }
return <Pagination className={classString} return (total > 0) ? <Pagination className={classString}
onChange={this.handlePageChange} onChange={this.handlePageChange}
total={total} total={total}
pageSize={10} pageSize={10}
{...this.state.pagination} />; {...this.state.pagination} /> : null;
}, },
prepareParamsArguments(state) { prepareParamsArguments(state) {
@ -424,7 +424,7 @@ var AntTable = React.createClass({
getLocalData() { getLocalData() {
let state = this.state; let state = this.state;
let data = this.props.dataSource; let data = this.state.dataSource;
// //
if (state.sortOrder && state.sorter) { if (state.sortOrder && state.sorter) {
data = data.sort(state.sorter); data = data.sort(state.sorter);
@ -457,7 +457,7 @@ var AntTable = React.createClass({
let data = this.getCurrentPageData(); let data = this.getCurrentPageData();
let columns = this.renderRowSelection(); let columns = this.renderRowSelection();
let classString = ''; let classString = '';
if (this.state.loading && this.isLocalDataSource()) { if (this.state.loading && !this.isLocalDataSource()) {
classString += ' ant-table-loading'; classString += ' ant-table-loading';
} }
if (this.props.size === 'small') { if (this.props.size === 'small') {
@ -467,13 +467,24 @@ var AntTable = React.createClass({
classString += ' ant-table-bordered'; classString += ' ant-table-bordered';
} }
columns = this.renderColumnsDropdown(columns); columns = this.renderColumnsDropdown(columns);
columns = columns.map((column, i) => {
column.key = column.dataIndex || i;
return column;
});
let emptyText;
if (!data || data.length === 0) {
emptyText = <div className="ant-table-empty">
<i className="anticon anticon-frown"></i>暂无数据
</div>;
}
return <div className="clearfix"> return <div className="clearfix">
<Table <Table
{...this.props} {...this.props}
data={data || []} data={data}
columns={columns} columns={columns}
className={classString} className={classString}
/> />
{emptyText}
{this.renderPagination()} {this.renderPagination()}
</div>; </div>;
} }

View File

@ -24,10 +24,12 @@ Table 有两种模式,本地数据和远程数据模式。
```jsx ```jsx
var dataSource = [{ var dataSource = [{
key: '1',
name: '胡彦斌', name: '胡彦斌',
age: 32, age: 32,
address: '西湖区湖底公园1号' address: '西湖区湖底公园1号'
}, { }, {
key: '2',
name: '胡彦祖', name: '胡彦祖',
age: 42, age: 42,
address: '西湖区湖底公园1号' address: '西湖区湖底公园1号'
@ -64,6 +66,7 @@ var dataSource = new Table.DataSource({
| size | 正常或迷你类型 | string | `normal` or `small` | normal | | size | 正常或迷你类型 | string | `normal` or `small` | normal |
| dataSource | 数据源,可以为数组(本地模式)或一个数据源描述对象(远程模式) | Array or Object | | | | dataSource | 数据源,可以为数组(本地模式)或一个数据源描述对象(远程模式) | Array or Object | | |
| columns | 表格列的配置描述,具体项见下表 | Array | | 无 | | columns | 表格列的配置描述,具体项见下表 | Array | | 无 |
| rowKey | 表格列 key 的取值 | Function(recode,index):string | | record.key |
### Column ### Column

View File

@ -1,6 +1,5 @@
import React from 'react'; import React from 'react';
import Tree from 'rc-tree'; import Tree from 'rc-tree';
import velocity from 'velocity-animate';
import animation from '../common/openAnimation'; import animation from '../common/openAnimation';
const AntTree = React.createClass({ const AntTree = React.createClass({

View File

@ -1,6 +1,6 @@
# 点击上传 # 点击上传
- order: 1 - order: 0
经典款式,用户点击按钮弹出文件选择框。 经典款式,用户点击按钮弹出文件选择框。
@ -15,12 +15,9 @@ var props = {
data: {}, data: {},
accept: '', accept: '',
uploadTip: '', uploadTip: '',
start: function(file){ onStart(file){
console.log(file.name) console.log(file.uid);
}, }
error: function() {},
success: function() {},
progress: function() {}
}; };
React.render( React.render(

View File

@ -14,11 +14,7 @@ var props = {
action: '/upload.do', action: '/upload.do',
data: {}, data: {},
accept: '', accept: '',
uploadTip: '', uploadTip: ''
error: function() {},
success: function() {},
progress: function() {},
start: function() {}
}; };
React.render( React.render(

View File

@ -14,15 +14,7 @@ var props = {
action: '/upload.do', action: '/upload.do',
data: {}, data: {},
accept: 'i', accept: 'i',
uploadTip: '', uploadTip: ''
error: function(err) {
console.log(err)
},
success: function() {},
progress: function() {},
start: function(file){
console.log(file)
}
}; };
React.render( React.render(
@ -31,7 +23,7 @@ React.render(
<i className="anticon anticon-inbox"></i> <i className="anticon anticon-inbox"></i>
</p> </p>
<p className="ant-upload-text">点击或将文件拖拽到此区域上传</p> <p className="ant-upload-text">点击或将文件拖拽到此区域上传</p>
<p className="ant-upload-hint">支持单个或批量上传,严上传公司内部资料及其他违禁文件</p> <p className="ant-upload-hint">支持单个或批量上传,严上传公司内部资料及其他违禁文件</p>
</Dragger>, </Dragger>,
document.getElementById('components-upload-demo-drag') document.getElementById('components-upload-demo-drag')
); );

View File

@ -0,0 +1,33 @@
# 文件列表限制
- order: 3
`limit` 属性控制文件列表数的上限。如设为 1 时,表示只能上传一个文件,新文件会顶掉旧文件。
---
````jsx
var Upload = antd.Upload;
var props = {
description: '支持扩展名为: .rar .zip ...',
action: '/upload.do',
data: {},
accept: '',
uploadTip: '',
limit: 1,
onStart(file){
console.log(file.uid);
}
};
React.render(
<Upload {...props}>
<button className="ant-btn ant-btn-ghost">
<i className="anticon anticon-upload"></i> 点击上传,只支持一个文件
</button>
</Upload>,
document.getElementById('components-upload-demo-limit')
);
````

View File

@ -7,36 +7,71 @@ import getFileItem from './getFileItem';
const prefixCls = 'ant-upload'; const prefixCls = 'ant-upload';
let fileIndex = 0; let fileIndex = 0;
function noop() {
}
const AntUpload = React.createClass({ const AntUpload = React.createClass({
getInitialState() { getInitialState() {
return { return {
downloadList: [] downloadList: []
}; };
}, },
handleStart(file) { onStart(file) {
let nextDownloadList = this.state.downloadList; let nextDownloadList = this.state.downloadList;
nextDownloadList.push({ nextDownloadList.push({
index: fileIndex++, index: fileIndex++,
uid: file.uid || '', uid: file.uid || '',
filename: file.name, filename: file.name,
file: file,
status: 'downloading' status: 'downloading'
}); });
if (nextDownloadList.length === this.props.limit + 1) {
nextDownloadList = nextDownloadList.slice(1);
}
this.setState({ this.setState({
downloadList: nextDownloadList downloadList: nextDownloadList
}); });
this.props.onStart(file);
}, },
handleSuccess(ret, file) { removeFile(file){
Message.success(file.name + '上传完成'); var downloadList = this.state.downloadList.concat();
let targetItem = getFileItem(file, this.state.downloadList); let targetItem = getFileItem(file, downloadList);
targetItem.status = 'done'; var index = downloadList.indexOf(targetItem);
if (index !== -1) {
downloadList.splice(index, 1);
}
this.setState({ this.setState({
downloadList: this.state.downloadList downloadList: downloadList
}); });
}, },
handleProgress() { onSuccess(ret, file) {
var res = this.props.onSuccess(ret, file);
if (res !== false) {
var downloadList = this.state.downloadList.concat();
Message.success(file.name + '上传完成');
let targetItem = getFileItem(file, downloadList);
targetItem.status = 'done';
//
if (typeof this.props.urlResolver === 'function') {
targetItem.url = this.props.urlResolver(ret);
}
this.setState({
downloadList: downloadList
});
} else {
this.removeFile(file);
}
}, },
handleError() { onProgress(e, file) {
Message.error('上传失败'); this.props.onProgress(e, file);
},
onError(err, responce, file) {
Message.error(file.name + ' 上传失败');
this.removeFile(file);
this.props.onError(err, responce, file);
},
onRemove(file){
this.props.onRemove(file);
}, },
getDefaultProps() { getDefaultProps() {
return { return {
@ -47,32 +82,27 @@ const AntUpload = React.createClass({
data: {}, data: {},
accept: '', accept: '',
uploadTip: '', uploadTip: '',
start: function() {}, onStart: noop,
error: function() {}, onError: noop,
success: function() {}, onSuccess: noop,
progress: function() {} onProgress: noop,
onRemove: noop,
limit: Number.MAX_VALUE,
urlResolver: function(ret) {
try {
return JSON.parse(ret).url;
} catch(e) {}
}
}; };
}, },
render() { render() {
let type = this.props.type || 'select'; let type = this.props.type || 'select';
let props = assign({}, this.props); let props = assign({}, this.props, {
onStart: this.onStart,
props.onStart = (file) => { onError: this.onError,
this.handleStart(file); onProgress: this.onProgress,
props.start.call(this, file); onSuccess: this.onSuccess,
}; });
props.onSuccess = (ret, file) => {
this.handleSuccess(ret, file);
props.success.call(this, ret, file);
};
props.onProgress = (step) => {
this.handleProgress(step);
props.progress.call(this, step);
};
props.onError = (err, responce, file) => {
this.handleError(err);
props.error.call(this, err, responce, file);
};
if (type === 'drag') { if (type === 'drag') {
return ( return (
<div className={prefixCls + ' ' + prefixCls + '-drag'}> <div className={prefixCls + ' ' + prefixCls + '-drag'}>
@ -91,7 +121,9 @@ const AntUpload = React.createClass({
{this.props.children} {this.props.children}
</Upload> </Upload>
</div> </div>
<UploadList items={this.state.downloadList} /> <UploadList items={this.state.downloadList}
onRemove={this.onRemove}
limit={props.limit} />
</div> </div>
); );
} }
@ -100,7 +132,7 @@ const AntUpload = React.createClass({
AntUpload.Dragger = React.createClass({ AntUpload.Dragger = React.createClass({
render() { render() {
return <AntUpload {...this.props} type="drag" style={{height: this.props.height}} />; return <AntUpload {...this.props} type="drag" style={{height: this.props.height}}/>;
} }
}); });

View File

@ -28,6 +28,8 @@
| onError | 可选参数, error callback |Function | 无 | | onError | 可选参数, error callback |Function | 无 |
| onSuccess | 可选参数, success callback | Function | 无 | | onSuccess | 可选参数, success callback | Function | 无 |
| onProgress | 可选参数, progress callback, 现代浏览器有效 | Function | 无 | | onProgress | 可选参数, progress callback, 现代浏览器有效 | Function | 无 |
| urlResolver| 通过解析请求返回数据,获得文件上传的远程地址 | Function | `function() { return JSON.parse(ret).url }` |
| limit | 文件上传数量的限制 | Number | Number.MAX_VALUE |
### onError ### onError

View File

@ -30,15 +30,19 @@ export default React.createClass({
this.setState({ this.setState({
items: items items: items
}); });
this.props.onRemove(file.file);
}, },
render() { render() {
let items = this.state.items; let items = this.state.items;
let downloadItem = (file) => { let downloadItem = (file) => {
let statusIcon = file.status === 'done' ? <i className={'anticon anticon-check ' + prefixCls + '-success-icon'}></i> : <i className="anticon anticon-loading"></i>; let statusIcon = file.status === 'done' ? <i className={'anticon anticon-check ' + prefixCls + '-success-icon'}></i> :
<i className="anticon anticon-loading"></i>;
let filename = file.url ? <a className={prefixCls + '-item-name'} href={file.url} _target="_blank">{file.filename}</a> :
<b className={prefixCls + '-item-name'}>{file.filename}</b>;
return ( return (
<div className={prefixCls + '-list-item'} key={file.index}> <div className={prefixCls + '-list-item'} key={file.index}>
{statusIcon} {statusIcon}
<b className={prefixCls + '-item-name'}>{file.filename}</b> {filename}
<i className="anticon anticon-cross" ref="theCloseBtn" <i className="anticon anticon-cross" ref="theCloseBtn"
onClick={this.handleClose.bind(this, file)}></i> onClick={this.handleClose.bind(this, file)}></i>
</div> </div>

View File

@ -78,17 +78,15 @@ var App = React.createClass({
}; };
}, },
handleChange(value) { handleChange(value) {
message.info('您选择的日期是: ' + value.toString());
this.setState({ this.setState({
date: value date: value
}); });
}, },
notice() {
message.info(this.state.date.toString());
},
render() { render() {
return <div> return <div style={{width: 400, margin: '100px auto'}}>
<Datepicker onSelect={this.handleChange} /> <Datepicker onSelect={this.handleChange} />
<button className="ant-btn ant-btn-primary" onClick={this.notice}>显示日期</button> <div style={{marginTop: 20}}>当前日期:{this.state.date.toString()}</div>
</div>; </div>;
} }
}); });

View File

@ -74,7 +74,10 @@ exports.middlewares = [
busboy.on('finish', function() { busboy.on('finish', function() {
console.log('Done parsing form!'); console.log('Done parsing form!');
//res.writeHead(303, { Connection: 'close', Location: '/' }); //res.writeHead(303, { Connection: 'close', Location: '/' });
res.end('success'); res.end(JSON.stringify({
'status': 'success',
'url': '/example.file'
}));
}); });
req.pipe(busboy); req.pipe(busboy);
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "antd", "name": "antd",
"version": "0.8.1-beta1", "version": "0.8.1-beta2",
"stableVersion": "0.8.0", "stableVersion": "0.8.0",
"title": "Ant Design", "title": "Ant Design",
"description": "一个 UI 设计语言", "description": "一个 UI 设计语言",

View File

@ -35,7 +35,7 @@ $(function () {
}, },
render() { render() {
return <Select combobox style={{width: 260}} return <Select combobox style={{width: '100%'}}
onSelect={this.handleSelect} onSelect={this.handleSelect}
optionLabelProp="text" optionLabelProp="text"
dropdownClassName="autoComplete" dropdownClassName="autoComplete"

View File

@ -106,6 +106,7 @@
</li> </li>
</ul> </ul>
</nav> </nav>
<div class="nav-phone-icon"></div>
</header> </header>
<div class="main-wrapper"> <div class="main-wrapper">
{% block aside %}{% endblock %} {% block content %}{% endblock %} {% block aside %}{% endblock %} {% block content %}{% endblock %}

View File

@ -95,9 +95,9 @@ mask:true,exposure:"bottom"});
2. 如球类物体掉地上的后,反弹几次后停止。 2. 如球类物体掉地上的后,反弹几次后停止。
- 弹性动画最好结合 alpha。 弹性动画最好结合 alpha。
> 慎用Bounce或Elastic这两种适用在特殊元素下一般back即可满足页面上元素的弹动; > 慎用 Bounce Elastic这两种适用在特殊元素下一般 back 即可满足页面上元素的弹动;
<div id="J-Back"></div> <div id="J-Back"></div>
@ -110,7 +110,7 @@ mask:false,exposure:"top"});
}) })
</script> </script>
上图所示缓动函数:绿 `easeOutBounce` `easeOutElastic`( css 需自配)`ease-out-back` `ease-in-back` 上图所示缓动函数:绿 `easeOutBounce` `easeOutElastic`css 需自配)`ease-out-back` `ease-in-back`
## 缓动函数 ## 缓动函数
@ -119,15 +119,15 @@ Ant Design 提供了一套缓动函数规范动画行为供组件使用。
|名称 |参数 |说明 | |名称 |参数 |说明 |
|-------------------|------------------------------------------|---------------------------| |-------------------|------------------------------------------|---------------------------|
|@ease-out | `cubic-bezier(0.215,0.61,0.355,1);` |默认后缓动 | |@ease-out | `cubic-bezier(0.215,0.61,0.355,1);` |默认后缓动 |
|@ease-in | `cubic-bezier(0.55,0.055,0.675,0.19);`|默认前缓动 | |@ease-in | `cubic-bezier(0.55,0.055,0.675,0.19);`|默认前缓动 |
|@ease-in-out | `cubic-bezier(0.645,0.045,0.355,1);` |默认前后缓动 | |@ease-in-out | `cubic-bezier(0.645,0.045,0.355,1);` |默认前后缓动 |
|@ease-out-back | `cubic-bezier(0.18,0.89,0.32,1.28);` |结束回动 | |@ease-out-back | `cubic-bezier(0.18,0.89,0.32,1.28);` |结束回动 |
|@ease-in-back | `cubic-bezier(0.6,-0.3,0.74,0.05);` |开始回动 | |@ease-in-back | `cubic-bezier(0.6,-0.3,0.74,0.05);` |开始回动 |
|@ease-in-out-back | `cubic-bezier(0.68,-0.55,0.27,1.55);` |前后回动 | |@ease-in-out-back | `cubic-bezier(0.68,-0.55,0.27,1.55);` |前后回动 |
|@ease-out-circ | `cubic-bezier(0.08,0.82,0.17,1);` |圆形后缓动 | |@ease-out-circ | `cubic-bezier(0.08,0.82,0.17,1);` |圆形后缓动 |
|@ease-in-circ | `cubic-bezier(0.6,0.04,0.98,0.34);` |圆形前缓动 | |@ease-in-circ | `cubic-bezier(0.6,0.04,0.98,0.34);` |圆形前缓动 |
|@ease-in-out-circ | `cubic-bezier(0.78,0.14,0.15,0.86);` |圆形前后缓动 | |@ease-in-out-circ | `cubic-bezier(0.78,0.14,0.15,0.86);` |圆形前后缓动 |
|@ease-out-quint | `cubic-bezier(0.23, 1, 0.32, 1);`| quint后缓动| |@ease-out-quint | `cubic-bezier(0.23, 1, 0.32, 1);`| quint 后缓动|
|@ease-in-quint | `cubic-bezier(0.755, 0.05, 0.855, 0.06);`|quint前缓动| |@ease-in-quint | `cubic-bezier(0.755, 0.05, 0.855, 0.06);`|quint 前缓动|
|@ease-in-out-quint | `cubic-bezier(0.86, 0, 0.07, 1);`| quint前后缓动| |@ease-in-out-quint | `cubic-bezier(0.86, 0, 0.07, 1);`| quint 前后缓动|

View File

@ -15,12 +15,14 @@
<div class="col col-12 paragraph-12px"> <div class="col col-12 paragraph-12px">
<h3>12px 段落</h3> <h3>12px 段落</h3>
<p>汉学家称这个空白字为「盘古之白」,因为它劈开了全角字和半角字之间的混沌。</p> <p>汉学家称这个空白字为「盘古之白」,因为它劈开了全角字和半角字之间的混沌。</p>
<p>另有有研究显示,打字的时候不喜欢在中文和英文之间加空格的人,感情路都走得很辛苦,有七成的比例会在 34 岁的时候跟自己不爱的人结婚,而其余三成的人最后只能把遗产留给自己的猫。毕竟爱情跟书写都需要适时地留白。</p> <p>另有研究显示,打字的时候不喜欢在中文和英文之间加空格的人,感情路都走得很辛苦,有七成的比例会在 34 岁的时候跟自己不爱的人结婚,而其余三成的人最后只能把遗产留给自己的猫。毕竟爱情跟书写都需要适时地留白。</p>
<p>文案来自 <a href="https://github.com/vinta/paranoid-auto-spacing#%E7%82%BA%E4%BB%80%E9%BA%BC%E4%BD%A0%E5%80%91%E5%B0%B1%E6%98%AF%E4%B8%8D%E8%83%BD%E5%8A%A0%E5%80%8B%E7%A9%BA%E6%A0%BC%E5%91%A2">此处</a></p>
</div> </div>
<div class="col col-12 paragraph-14px"> <div class="col col-12 paragraph-14px">
<h3>14px 段落</h3> <h3>14px 段落</h3>
<p>汉学家称这个空白字为「盘古之白」,因为它劈开了全角字和半角字之间的混沌。</p> <p>汉学家称这个空白字为「盘古之白」,因为它劈开了全角字和半角字之间的混沌。</p>
<p>另有有研究显示,打字的时候不喜欢在中文和英文之间加空格的人,感情路都走得很辛苦,有七成的比例会在 34 岁的时候跟自己不爱的人结婚,而其余三成的人最后只能把遗产留给自己的猫。毕竟爱情跟书写都需要适时地留白。</p> <p>另有研究显示,打字的时候不喜欢在中文和英文之间加空格的人,感情路都走得很辛苦,有七成的比例会在 34 岁的时候跟自己不爱的人结婚,而其余三成的人最后只能把遗产留给自己的猫。毕竟爱情跟书写都需要适时地留白。</p>
<p>文案来自 <a href="https://github.com/vinta/paranoid-auto-spacing#%E7%82%BA%E4%BB%80%E9%BA%BC%E4%BD%A0%E5%80%91%E5%B0%B1%E6%98%AF%E4%B8%8D%E8%83%BD%E5%8A%A0%E5%80%8B%E7%A9%BA%E6%A0%BC%E5%91%A2">此处</a></p>
</div> </div>
</div> </div>
@ -92,7 +94,7 @@
## 文案长度 ## 文案长度
语言通常是越简单越明确,而提示性文字更需要简明扼要,让用户一目了然,减少操作失误。提示性句子长度业务而定,建议一般不超过 1618 个字。 语言通常是越简单越明确,而提示性文字更需要简明扼要,让用户一目了然,减少操作失误。提示性句子长度业务而定,建议一般不超过 1618 个字。
<img align="right" style="margin:30px 100px" src="https://t.alipayobjects.com/images/T17cthXgpbXXXXXXXX.png" width="300"> <img align="right" style="margin:30px 100px" src="https://t.alipayobjects.com/images/T17cthXgpbXXXXXXXX.png" width="300">

View File

@ -37,6 +37,10 @@ $(function() {
// 移动 API 文档到演示下方 // 移动 API 文档到演示下方
$('.markdown #api').nextAll().andSelf().appendTo('.api-container'); $('.markdown #api').nextAll().andSelf().appendTo('.api-container');
$('.nav-phone-icon').click(function() {
$(this).prev().toggle();
});
$.easing['jswing'] = $.easing['swing']; $.easing['jswing'] = $.easing['swing'];
$.extend($.easing,{ $.extend($.easing,{
easeInCirc: function (x, t, b, c, d) { easeInCirc: function (x, t, b, c, d) {

View File

@ -105,7 +105,7 @@ a.logo {
.search { .search {
float: left; float: left;
height: 22px; height: 22px;
padding: 0px 30px; padding: 0px 0 0 30px;
margin: 32px auto 0; margin: 32px auto 0;
border-left: 1px solid #EBEDEE; border-left: 1px solid #EBEDEE;
position: relative; position: relative;
@ -113,6 +113,7 @@ a.logo {
#autoComplete { #autoComplete {
margin-top: -2px; margin-top: -2px;
width: 230px;
} }
#autoComplete .ant-select { #autoComplete .ant-select {
@ -1883,10 +1884,31 @@ a.entry-link:hover .anticon-smile {
.logo { .logo {
margin: 10px; margin: 10px;
width: 110px;
height: auto; height: auto;
} }
.nav {
position: absolute;
z-index: 1000;
top: 50px;
right: 0;
background: #fff;
overflow: hidden;
height: auto;
line-height: 50px;
margin-right: 0;
border: 1px solid #e9e9e9;
width: 50%;
}
.nav .bar {
display: none!important;
}
.nav ul li {
width: 100%;
}
.nav-phone-icon { .nav-phone-icon {
display: block; display: block;
width: 49px; width: 49px;
@ -1915,11 +1937,25 @@ a.entry-link:hover .anticon-smile {
height: calc(100% - 86px); height: calc(100% - 86px);
} }
footer ul { .aside-container {
display: none; float: none;
width: auto;
} }
footer h3 { .main-container {
display: block; margin-left: 0;
}
.markdown {
width: 100%;
}
footer {
text-align: center;
}
footer ul li {
float: none;
width: auto;
} }
} }

View File

@ -105,7 +105,7 @@ input[type="checkbox"] {
position: absolute; position: absolute;
font-size: @font-size-base; font-size: @font-size-base;
line-height: @line-height-base; line-height: @line-height-base;
bottom: - @line-height-computed; bottom: -@line-height-computed;
} }

View File

@ -1,3 +1,4 @@
@select-prefix-cls: ant-select; @select-prefix-cls: ant-select;
@import "../mixins/iconfont"; @import "../mixins/iconfont";
@ -17,9 +18,9 @@
font-family: 'anticon'; font-family: 'anticon';
font-weight: bold; font-weight: bold;
position: absolute; position: absolute;
top: 6px; top: 7px;
right: 0; right: 0;
padding-right: 16px; padding-right: 15px;
color: @primary-color; color: @primary-color;
} }
} }

View File

@ -176,6 +176,21 @@
} }
} }
} }
&-empty {
height: 100px;
line-height: 100px;
text-align: center;
font-size: 12px;
color: #999;
border-bottom: 1px solid #E9E9E9;
margin-bottom: 16px;
.anticon {
margin-right: 4px;
position: relative;
top: -1px;
}
}
} }
.@{table-prefix-cls}-pagination { .@{table-prefix-cls}-pagination {

View File

@ -90,11 +90,13 @@
} }
.@{upload-prefix-cls}-item-name { .@{upload-prefix-cls}-item-name {
font-size: 12px; font-size: 12px;
color: #666;
margin-left: 4px; margin-left: 4px;
margin-right: 8px; margin-right: 8px;
font-weight: normal; font-weight: normal;
} }
b.@{upload-prefix-cls}-item-name {
color: #666;
}
.@{upload-prefix-cls}-success-icon { .@{upload-prefix-cls}-success-icon {
color: @success-color; color: @success-color;
font-weight: bold; font-weight: bold;

View File

@ -1,11 +1,11 @@
.zoom-motion(@className, @keyframeName) { .zoom-motion(@className, @keyframeName) {
.make-motion(@className, @keyframeName); .make-motion(@className, @keyframeName);
.@{className}-enter, .@{className}-appear { .@{className}-enter, .@{className}-appear {
transform: scale(0, 0); // need this by yiminghe transform: scale(0); // need this by yiminghe
animation-timing-function: @ease-out-quint; animation-timing-function: @ease-out-circ;
} }
.@{className}-leave { .@{className}-leave {
animation-timing-function: @ease-in-quint; animation-timing-function: @ease-in-out-circ;
} }
} }
@ -18,20 +18,20 @@
@keyframes zoomIn { @keyframes zoomIn {
0% { 0% {
opacity: 0; opacity: 0;
transform: scale(0, 0); transform: scale(0);
} }
100% { 100% {
transform: scale(1, 1); transform: scale(1);
} }
} }
@keyframes zoomOut { @keyframes zoomOut {
0% { 0% {
transform: scale(1, 1); transform: scale(1);
} }
100% { 100% {
opacity: 0; opacity: 0;
transform: scale(0, 0); transform: scale(0);
} }
} }
@ -39,23 +39,23 @@
0% { 0% {
opacity: 0; opacity: 0;
transform-origin: 50% 0%; transform-origin: 50% 0%;
transform: scale(0, 0); transform: scale(.8);
} }
100% { 100% {
transform-origin: 50% 0%; transform-origin: 50% 0%;
transform: scale(1, 1); transform: scale(1);
} }
} }
@keyframes zoomUpOut { @keyframes zoomUpOut {
0% { 0% {
transform-origin: 50% 0%; transform-origin: 50% 0%;
transform: scale(1, 1); transform: scale(1);
} }
100% { 100% {
opacity: 0; opacity: 0;
transform-origin: 50% 0%; transform-origin: 50% 0%;
transform: scale(0, 0); transform: scale(.8);
} }
} }
@ -63,23 +63,23 @@
0% { 0% {
opacity: 0; opacity: 0;
transform-origin: 0% 50%; transform-origin: 0% 50%;
transform: scale(0, 0); transform: scale(.8);
} }
100% { 100% {
transform-origin: 0% 50%; transform-origin: 0% 50%;
transform: scale(1, 1); transform: scale(1);
} }
} }
@keyframes zoomLeftOut { @keyframes zoomLeftOut {
0% { 0% {
transform-origin: 0% 50%; transform-origin: 0% 50%;
transform: scale(1, 1); transform: scale(1);
} }
100% { 100% {
opacity: 0; opacity: 0;
transform-origin: 0% 50%; transform-origin: 0% 50%;
transform: scale(0, 0); transform: scale(.8);
} }
} }
@ -87,23 +87,23 @@
0% { 0% {
opacity: 0; opacity: 0;
transform-origin: 100% 50%; transform-origin: 100% 50%;
transform: scale(0, 0); transform: scale(.8);
} }
100% { 100% {
transform-origin: 100% 50%; transform-origin: 100% 50%;
transform: scale(1, 1); transform: scale(1);
} }
} }
@keyframes zoomRightOut { @keyframes zoomRightOut {
0% { 0% {
transform-origin: 100% 50%; transform-origin: 100% 50%;
transform: scale(1, 1); transform: scale(1);
} }
100% { 100% {
opacity: 0; opacity: 0;
transform-origin: 100% 50%; transform-origin: 100% 50%;
transform: scale(0, 0); transform: scale(.8);
} }
} }
@ -111,22 +111,22 @@
0% { 0% {
opacity: 0; opacity: 0;
transform-origin: 50% 100%; transform-origin: 50% 100%;
transform: scale(0, 0); transform: scale(.8);
} }
100% { 100% {
transform-origin: 50% 100%; transform-origin: 50% 100%;
transform: scale(1, 1); transform: scale(1);
} }
} }
@keyframes zoomDownOut { @keyframes zoomDownOut {
0% { 0% {
transform-origin: 50% 100%; transform-origin: 50% 100%;
transform: scale(1, 1); transform: scale(1);
} }
100% { 100% {
opacity: 0; opacity: 0;
transform-origin: 50% 100%; transform-origin: 50% 100%;
transform: scale(0, 0); transform: scale(.8);
} }
} }