This commit is contained in:
Boyuzhou 2017-01-11 17:01:50 +08:00
parent c23e4597ca
commit c41fd2efe6
20 changed files with 790 additions and 1111 deletions

View File

@ -3,8 +3,51 @@
@import "../node_modules/bee-layout/src/Layout.scss";
@import "../node_modules/bee-button/src/Button.scss";
@import "../node_modules/bee-transition/src/Transition.scss";
@import "../src/animation.scss";
@import "../src/bordered.scss";
@import "../src/index.scss";
@import "../node_modules/bee-dropdown/src/Dropdown.scss";
@import "../node_modules/bee-menus/src/Menus.scss";
@import "../node_modules/bee-popconfirm/src/Popconfirm.scss";
@import "../node_modules/bee-form-control/src/FormControl.scss";
.editable-cell {
position: relative;
}
.editable-cell-input-wrapper,
.editable-cell-text-wrapper {
padding-right: 24px;
}
.editable-cell-text-wrapper {
padding: 5px 24px 5px 5px;
}
.editable-cell-icon,
.editable-cell-icon-check {
position: absolute;
right: 0;
width: 20px;
cursor: pointer;
}
.editable-cell-icon {
line-height: 18px;
display: none;
}
.editable-cell-icon-check {
line-height: 28px;
}
.editable-cell:hover .editable-cell-icon {
display: inline-block;
}
.editable-cell-icon:hover,
.editable-cell-icon-check:hover {
color:#2db7f5;
}
.editable-add-btn {
margin-bottom: 8px;
}

View File

@ -1,67 +1,36 @@
/**
*
* @title 这是标题
* @description 这是描述
* @title 简单表格
* @description
*
*/
class Demo1 extends React.Component {
constructor(props) {
super(props);
this.columns = [
{ title: 'title1', dataIndex: 'a', key: 'a', width: 100 },
{ id: '123', title: 'title2', dataIndex: 'b', key: 'b', width: 100 },
{ title: 'title3', dataIndex: 'c', key: 'c', width: 200 },
{
title: 'Operations', dataIndex: '', key: 'd', render: (text, record) =>
<a onClick={e => this.onDelete(record.key, e)} href="#">Delete</a>,
},
];
this.state = {
data: [
{ a: '123', key: '1' },
{ a: 'cdd', b: 'edd', key: '2' },
{ a: '1333', c: 'eee', key: '3' },
],
};
}
onDelete(key, e) {
console.log('Delete', key);
e.preventDefault();
const data = this.state.data.filter(item => item.key !== key);
this.setState({ data });
}
const columns = [
{ title: '用户名', dataIndex: 'a', key: 'a', width: 100 },
{ id: '123', title: '性别', dataIndex: 'b', key: 'b', width: 100 },
{ title: '年龄', dataIndex: 'c', key: 'c', width: 200 },
{
title: '操作', dataIndex: '', key: 'd', render() {
return <a href="#">一些操作</a>;
},
},
];
onAdd() {
const data = [...this.state.data];
data.push({
a: 'new data',
b: 'new data',
c: 'new data',
key: Date.now(),
});
this.setState({ data });
}
const data = [
{ a: '令狐冲', b: '男', c: 41, key: '1' },
{ a: '杨过', b: '男', c: 67, key: '2' },
{ a: '郭靖', b: '男', c: 25, key: '3' },
];
getBodyWrapper(body) {
return (
<Animate transitionName="move" component="tbody" className={body.props.className}>
{body.props.children}
</Animate>
);
}
render() {
return (
<div style={{ margin: 20 }}>
<h2>Table row with animation</h2>
<button onClick={() => this.onAdd()}>添加</button>
<Table
columns={this.columns}
data={this.state.data}
getBodyWrapper={this.getBodyWrapper}
/>
</div>
);
}
class Demo1 extends Component {
render () {
return (
<Table
columns={columns}
data={data}
title={currentData => <div>标题: {currentData.length} 个元素</div>}
footer={currentData => <div>表尾: {currentData.length} 个元素</div>}
/>
)
}
}

View File

@ -5,86 +5,166 @@
*
*/
const columns1 = [{
title: 'Name',
dataIndex: 'name',
key: 'name',
width: 400,
}, {
title: 'Age',
dataIndex: 'age',
key: 'age',
width: 100,
}, {
title: 'Address',
dataIndex: 'address',
key: 'address',
width: 200,
}, {
title: 'Operations',
dataIndex: 'operation',
key: 'x',
width: 150,
}];
const data1 = [{
key: 1,
name: 'a',
age: 32,
address: 'I am a',
children: [{
key: 11,
name: 'aa',
age: 33,
address: 'I am aa',
}, {
key: 12,
name: 'ab',
age: 33,
address: 'I am ab',
children: [{
key: 121,
name: 'aba',
age: 33,
address: 'I am aba',
}],
}, {
key: 13,
name: 'ac',
age: 33,
address: 'I am ac',
children: [{
key: 131,
name: 'aca',
age: 33,
address: 'I am aca',
children: [{
key: 1311,
name: 'acaa',
age: 33,
address: 'I am acaa',
}, {
key: 1312,
name: 'acab',
age: 33,
address: 'I am acab',
}],
}],
}],
}, {
key: 2,
name: 'b',
age: 32,
address: 'I am b',
}];
function onExpand(expanded, record) {
console.log('onExpand', expanded, record);
}
class Demo2 extends Component {
render () {
return (
<Table defaultExpandAllRows columns={columns1} data={data1} indentSize={30} onExpand={onExpand} />
)
class EditableCell extends React.Component {
state = {
value: this.props.value,
editable: false,
}
handleChange = (e) => {
const value = e.target.value;
this.setState({ value });
}
check = () => {
this.setState({ editable: false });
if (this.props.onChange) {
this.props.onChange(this.state.value);
}
}
edit = () => {
this.setState({ editable: true });
}
handleKeydown = (event) => {
console.log(event);
if(event.keyCode == 13){
this.check();
}
}
render() {
const { value, editable } = this.state;
return (<div className="editable-cell">
{
editable ?
<div className="editable-cell-input-wrapper">
<Input
value={value}
onChange={this.handleChange}
onKeyDown = {this.handleKeydown}
/>
<Icon
type="uf-correct"
className="editable-cell-icon-check"
onClick={this.check}
/>
</div>
:
<div className="editable-cell-text-wrapper">
{value || ' '}
<Icon
type="uf-pencil"
className="editable-cell-icon"
onClick={this.edit}
/>
</div>
}
</div>);
}
}
class Demo2 extends React.Component {
constructor(props) {
super(props);
this.columns = [{
title: '姓名',
dataIndex: 'name',
key:'name',
width: '30%',
render: (text, record, index) => (
<EditableCell
value={text}
onChange={this.onCellChange(index, 'name')}
/>
),
}, {
title: '年龄',
dataIndex: 'age',
key:'age',
}, {
title: '你懂的',
dataIndex: 'address',
key:'address',
}, {
title: '操作',
dataIndex: 'operation',
key: 'operation',
render: (text, record, index) => {
return (
this.state.dataSource.length > 1 ?
(
<Popconfirm content="确认删除?" id='aa' onClose={this.onDelete(index)}>
<Icon type="uf-del"></Icon>
</Popconfirm>
) : null
);
},
}];
this.state = {
dataSource: [{
key: '0',
name: '沉鱼',
age: '18',
address: '96, 77, 89',
}, {
key: '1',
name: '落雁',
age: '16',
address: '90, 70, 80',
}, {
key: '2',
name: '闭月',
age: '17',
address: '80, 60, 80',
}, {
key: '3',
name: '羞花',
age: '20',
address: '120, 60, 90',
}],
count: 4,
};
}
onCellChange = (index, key) => {
return (value) => {
const dataSource = [...this.state.dataSource];
dataSource[index][key] = value;
this.setState({ dataSource });
};
}
onDelete = (index) => {
return () => {
const dataSource = [...this.state.dataSource];
dataSource.splice(index, 1);
this.setState({ dataSource });
};
}
handleAdd = () => {
const { count, dataSource } = this.state;
const newData = {
key: count,
name: `凤姐 ${count}`,
age: 32,
address: `100 100 100`,
};
this.setState({
dataSource: [...dataSource, newData],
count: count + 1,
});
}
getBodyWrapper = (body) => {
return (
<Animate transitionName="move" component="tbody" className={body.props.className}>
{body.props.children}
</Animate>
);
}
render() {
const { dataSource } = this.state;
const columns = this.columns;
return (<div>
<Button className="editable-add-btn" type="ghost" onClick={this.handleAdd}>添加</Button>
<Table bordered data={dataSource} columns={columns} getBodyWrapper={this.getBodyWrapper} />
</div>);
}
}

View File

@ -1,49 +0,0 @@
/**
*
* @title 这是标题
* @description 这是描述
*
*/
const columns2 = [
{ title: 'title1', dataIndex: 'a',
className: 'a',
key: 'a', width: 100 },
{ id: '123', title: 'title2', dataIndex: 'b',
className: 'b',
key: 'b', width: 100 },
{ title: 'title3', dataIndex: 'c',
className: 'c',
key: 'c', width: 200 },
{
title: 'Operations', dataIndex: '',
className: 'd',
key: 'd', render() {
return <a href="#">Operations</a>;
},
},
];
const data2 = [
{ a: '123', key: '1' },
{ a: 'cdd', b: 'edd', key: '2' },
{ a: '1333', c: 'eee', d: 2, key: '3' },
];
class Demo3 extends Component {
render () {
return (
<div>
<h2>rowClassName and className</h2>
<Table
columns={columns2}
rowClassName={(record, i) => `row-${i}`}
expandedRowRender={record => <p>extra: {record.a}</p>}
expandedRowClassName={(record, i) => `ex-row-${i}`}
data={data2}
className="table"
/>
</div>
)
}
}

View File

@ -1,112 +0,0 @@
/**
*
* @title 这是标题
* @description 这是描述
*
*/
const columns3 = [
{ title: '手机号', dataIndex: 'a', colSpan: 2, width: 100, key: 'a', render(o, row, index) {
const obj = {
children: o,
props: {},
};
// 设置第一行为链接
if (index === 0) {
obj.children = <a href="#">{o}</a>;
}
// 第5行合并两列
if (index === 4) {
obj.props.colSpan = 2;
}
if (index === 5) {
obj.props.colSpan = 6;
}
return obj;
} },
{ title: '电话', dataIndex: 'b', colSpan: 0, width: 100, key: 'b', render(o, row, index) {
const obj = {
children: o,
props: {},
};
// 列合并掉的表格设置colSpan=0不会去渲染
if (index === 4 || index === 5) {
obj.props.colSpan = 0;
}
return obj;
} },
{ title: 'Name', dataIndex: 'c', width: 100, key: 'c', render(o, row, index) {
const obj = {
children: o,
props: {},
};
if (index === 5) {
obj.props.colSpan = 0;
}
return obj;
} },
{ title: 'Address', dataIndex: 'd', width: 200, key: 'd', render(o, row, index) {
const obj = {
children: o,
props: {},
};
if (index === 0) {
obj.props.rowSpan = 2;
}
if (index === 1 || index === 5) {
obj.props.rowSpan = 0;
}
return obj;
} },
{ title: 'Gender', dataIndex: 'e', width: 200, key: 'e', render(o, row, index) {
const obj = {
children: o,
props: {},
};
if (index === 5) {
obj.props.colSpan = 0;
}
return obj;
} },
{
title: 'Operations', dataIndex: '', key: 'f',
render(o, row, index) {
if (index === 5) {
return {
props: {
colSpan: 0,
},
};
}
return <a href="#">Operations</a>;
},
},
];
const data3 = [
{ a: '13812340987', b: '0571-12345678', c: '张三', d: '文一西路', e: 'Male', key: '1' },
{ a: '13812340986', b: '0571-98787658', c: '张夫人', d: '文一西路', e: 'Female', key: '2' },
{ a: '13812988888', b: '0571-099877', c: '李四', d: '文二西路', e: 'Male', key: '3' },
{ a: '1381200008888', b: '0571-099877', c: '王五', d: '文二西路', e: 'Male', key: '4' },
{ a: '0571-88888110', c: '李警官', d: '武林门', e: 'Male', key: '5' },
{ a: '资料统计完毕于xxxx年xxx月xxx日', key: '6' },
];
class Demo4 extends Component {
render () {
return (
<div>
<h2>colSpan & rowSpan</h2>
<Table
columns={columns3}
data={data3}
className="table"
/>
</div>
)
}
}

View File

@ -1,102 +0,0 @@
/**
*
* @title 这是标题
* @description 这是描述
*
*/
const data = [];
for (let i = 0; i < 10; i++) {
data.push({
key: i,
a: `a${i}`,
b: `b${i}`,
c: `c${i}`,
});
}
const Demo5 = React.createClass({
getInitialState() {
this.filters = [];
return {
visible: false,
};
},
handleVisibleChange(visible) {
this.setState({ visible });
},
handleSelect(selected) {
this.filters.push(selected);
},
handleDeselect(key) {
const index = this.filters.indexOf(key);
if (index !== -1) {
this.filters.splice(index, 1);
}
},
confirmFilter() {
console.log(this.filters.join(','));
this.setState({
visible: false,
});
},
render() {
const menu = (
<Menu
style={{ width: 200 }}
multiple
onSelect={this.handleSelect}
onDeselect={this.handleDeselect}
>
<Item key="1">one</Item>
<Item key="2">two</Item>
<Item key="3">three</Item>
<Divider />
<Item disabled>
<button
style={{
cursor: 'pointer',
color: '#000',
pointerEvents: 'visible',
}}
onClick={this.confirmFilter}
>确定</button>
</Item>
</Menu>
);
const columns = [
{
title: (
<div>
title1
<DropDown
trigger={['click']}
onVisibleChange={this.handleVisibleChange}
visible={this.state.visible}
overlay={menu}
>
<a href="#">filter</a>
</DropDown>
</div>
), key: 'a', dataIndex: 'a', width: 100,
},
{ title: 'title2', key: 'b', dataIndex: 'b', width: 100 },
{ title: 'title3', key: 'c', dataIndex: 'c', width: 200 },
];
return (
<Table
columns={columns}
data={data}
rowKey={record => record.key}
/>
);
},
});

View File

@ -8,11 +8,13 @@ import Table from '../src';
import Animate from 'bee-animate';
import Menu, { Item, Divider } from 'bee-menus';
import DropDown from 'bee-dropdown';
import Icon from "bee-icon";
import Input from 'bee-form-control';
import Popconfirm from 'bee-popconfirm';
const CARET = <i className="uf uf-arrow-down"></i>;
const CARET = <i className="uf uf-chevronarrowdown"></i>;
const CARETUP = <i className="uf uf-chevronarrowup"></i>;
const CARETUP = <i className="uf uf-arrow-up"></i>;
{demolist}
@ -42,14 +44,9 @@ class Demo extends Component {
);
const header = (
<Row>
<Col md={11}>
<Col md={12}>
{ example }
</Col>
<Col md={1}>
<Button shape="icon" onClick={ this.handleClick }>
{ caret }
</Button>
</Col>
</Row>
);
return (

File diff suppressed because one or more lines are too long

View File

@ -41,18 +41,19 @@
"warning": "^3.0.0"
},
"devDependencies": {
"bee-animate": "0.0.3",
"bee-animate": "latest",
"bee-button": "latest",
"bee-dropdown": "^0.1.4",
"bee-form-control": "^0.1.7",
"bee-icon": "0.0.5",
"bee-layout": "latest",
"bee-menus": "0.0.5",
"bee-panel": "latest",
"bee-popconfirm": "^0.2.1",
"chai": "^3.5.0",
"console-polyfill": "~0.2.1",
"enzyme": "^2.4.1",
"es5-shim": "~4.1.10",
"react": "~0.14.0",
"react": "15.3.2",
"react-addons-test-utils": "15.3.2",
"react-dom": "~0.14.0"
"react-dom": "15.3.2"
}
}

View File

@ -2,6 +2,8 @@ import React from 'react';
import Column from './Column';
import ColumnGroup from './ColumnGroup';
//行控制管理
export default class ColumnManager {
_cached = {}

View File

@ -1,33 +1,39 @@
import React, { PropTypes } from 'react';
import React, { PropTypes, Component } from 'react';
import shallowequal from 'shallowequal';
const ExpandIcon = React.createClass({
propTypes: {
const propTypes = {
record: PropTypes.object,
prefixCls: PropTypes.string,
clsPrefix: PropTypes.string,
expandable: PropTypes.any,
expanded: PropTypes.bool,
needIndentSpaced: PropTypes.bool,
onExpand: PropTypes.func,
},
};
class ExpandIcon extends Component{
constructor(props){
super(props);
}
shouldComponentUpdate(nextProps) {
return !shallowequal(nextProps, this.props);
},
}
render() {
const { expandable, prefixCls, onExpand, needIndentSpaced, expanded, record } = this.props;
const { expandable, clsPrefix, onExpand, needIndentSpaced, expanded, record } = this.props;
if (expandable) {
const expandClassName = expanded ? 'expanded' : 'collapsed';
return (
<span
className={`${prefixCls}-expand-icon ${prefixCls}-${expandClassName}`}
className={`${clsPrefix}-expand-icon ${clsPrefix}-${expandClassName}`}
onClick={(e) => onExpand(!expanded, record, e)}
/>
);
} else if (needIndentSpaced) {
return <span className={`${prefixCls}-expand-icon ${prefixCls}-spaced`} />;
return <span className={`${clsPrefix}-expand-icon ${clsPrefix}-spaced`} />;
}
return null;
},
});
}
};
ExpandIcon.propTypes = propTypes;
export default ExpandIcon;

View File

@ -1,4 +1,4 @@
import React, { PropTypes } from 'react';
import React, { PropTypes, Component } from 'react';
import TableRow from './TableRow';
import TableHeader from './TableHeader';
import { measureScrollbar, debounce, warningOnce } from './utils';
@ -7,8 +7,7 @@ import addEventListener from 'rc-util/lib/Dom/addEventListener';
import ColumnManager from './ColumnManager';
import createStore from './createStore';
const Table = React.createClass({
propTypes: {
const propTypes = {
data: PropTypes.array,
expandIconAsCell: PropTypes.bool,
defaultExpandAllRows: PropTypes.bool,
@ -16,9 +15,10 @@ const Table = React.createClass({
defaultExpandedRowKeys: PropTypes.array,
useFixedHeader: PropTypes.bool,
columns: PropTypes.array,
prefixCls: PropTypes.string,
clsPrefix: PropTypes.string,
bodyStyle: PropTypes.object,
style: PropTypes.object,
//特殊的渲染规则的key值
rowKey: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
rowClassName: PropTypes.func,
expandedRowClassName: PropTypes.func,
@ -29,6 +29,7 @@ const Table = React.createClass({
onRowClick: PropTypes.func,
onRowDoubleClick: PropTypes.func,
expandIconColumnIndex: PropTypes.number,
//是否显示表头
showHeader: PropTypes.bool,
title: PropTypes.func,
footer: PropTypes.func,
@ -37,61 +38,87 @@ const Table = React.createClass({
rowRef: PropTypes.func,
getBodyWrapper: PropTypes.func,
children: PropTypes.node,
},
};
getDefaultProps() {
return {
data: [],
useFixedHeader: false,
expandIconAsCell: false,
defaultExpandAllRows: false,
defaultExpandedRowKeys: [],
rowKey: 'key',
rowClassName: () => '',
expandedRowClassName: () => '',
onExpand() {},
onExpandedRowsChange() {},
onRowClick() {},
onRowDoubleClick() {},
prefixCls: 'u-table',
bodyStyle: {},
style: {},
childrenColumnName: 'children',
indentSize: 15,
expandIconColumnIndex: 0,
showHeader: true,
scroll: {},
rowRef: () => null,
getBodyWrapper: body => body,
emptyText: () => 'No Data',
};
},
const defaultProps = {
data: [],
useFixedHeader: false,
expandIconAsCell: false,
defaultExpandAllRows: false,
defaultExpandedRowKeys: [],
rowKey: 'key',
rowClassName: () => '',
expandedRowClassName: () => '',
onExpand() {},
onExpandedRowsChange() {},
onRowClick() {},
onRowDoubleClick() {},
clsPrefix: 'u-table',
bodyStyle: {},
style: {},
childrenColumnName: 'children',
indentSize: 15,
expandIconColumnIndex: 0,
showHeader: true,
scroll: {},
rowRef: () => null,
getBodyWrapper: body => body,
emptyText: () => 'No Data',
};
getInitialState() {
const props = this.props;
let expandedRowKeys = [];
let rows = [...props.data];
this.columnManager = new ColumnManager(props.columns, props.children);
this.store = createStore({ currentHoverKey: null });
class Table extends Component{
constructor(props){
super(props);
let expandedRowKeys = [];
let rows = [...props.data];
this.columnManager = new ColumnManager(props.columns, props.children);
this.store = createStore({ currentHoverKey: null });
if (props.defaultExpandAllRows) {
for (let i = 0; i < rows.length; i++) {
const row = rows[i];
expandedRowKeys.push(this.getRowKey(row, i));
rows = rows.concat(row[props.childrenColumnName] || []);
if (props.defaultExpandAllRows) {
for (let i = 0; i < rows.length; i++) {
const row = rows[i];
expandedRowKeys.push(this.getRowKey(row, i));
rows = rows.concat(row[props.childrenColumnName] || []);
}
} else {
expandedRowKeys = props.expandedRowKeys || props.defaultExpandedRowKeys;
}
} else {
expandedRowKeys = props.expandedRowKeys || props.defaultExpandedRowKeys;
}
return {
expandedRowKeys,
data: props.data,
currentHoverKey: null,
scrollPosition: 'left',
fixedColumnsHeadRowsHeight: [],
fixedColumnsBodyRowsHeight: [],
};
},
this.state = {
expandedRowKeys,
data: props.data,
currentHoverKey: null,
scrollPosition: 'left',
fixedColumnsHeadRowsHeight: [],
fixedColumnsBodyRowsHeight: [],
}
this.onExpandedRowsChange = this.onExpandedRowsChange.bind(this);
this.onExpanded = this.onExpanded.bind(this);
this.onRowDestroy = this.onRowDestroy.bind(this);
this.getRowKey = this.getRowKey.bind(this);
this.getExpandedRows = this.getExpandedRows.bind(this);
this.getHeader = this.getHeader.bind(this);
this.getHeaderRows = this.getHeaderRows.bind(this);
this.getExpandedRow = this.getExpandedRow.bind(this);
this.getRowsByData = this.getRowsByData.bind(this);
this.getRows = this.getRows.bind(this);
this.getColGroup = this.getColGroup.bind(this);
this.getLeftFixedTable = this.getLeftFixedTable.bind(this);
this.getRightFixedTable = this.getRightFixedTable.bind(this);
this.getTable = this.getTable.bind(this);
this.getTitle = this.getTitle.bind(this);
this.getFooter = this.getFooter.bind(this);
this.getEmptyText = this.getEmptyText.bind(this);
this.getHeaderRowStyle = this.getHeaderRowStyle.bind(this);
this.syncFixedTableRowHeight = this.syncFixedTableRowHeight.bind(this);
this.resetScrollY = this.resetScrollY.bind(this);
this.findExpandedRow = this.findExpandedRow.bind(this);
this.isRowExpanded = this.isRowExpanded.bind(this);
this.detectScrollTarget = this.detectScrollTarget.bind(this);
this.handleBodyScroll = this.handleBodyScroll.bind(this);
this.handleRowHover = this.handleRowHover.bind(this);
}
componentDidMount() {
this.resetScrollY();
@ -101,7 +128,7 @@ const Table = React.createClass({
window, 'resize', debounce(this.syncFixedTableRowHeight, 150)
);
}
},
}
componentWillReceiveProps(nextProps) {
if ('data' in nextProps) {
@ -122,24 +149,24 @@ const Table = React.createClass({
} else if (nextProps.children !== this.props.children) {
this.columnManager.reset(null, nextProps.children);
}
},
}
componentDidUpdate() {
this.syncFixedTableRowHeight();
},
}
componentWillUnmount() {
if (this.resizeEvent) {
this.resizeEvent.remove();
}
},
}
onExpandedRowsChange(expandedRowKeys) {
if (!this.props.expandedRowKeys) {
this.setState({ expandedRowKeys });
}
this.props.onExpandedRowsChange(expandedRowKeys);
},
}
onExpanded(expanded, record, e, index) {
if (e) {
@ -155,7 +182,7 @@ const Table = React.createClass({
this.onExpandedRowsChange(expandedRows);
}
this.props.onExpand(expanded, record);
},
}
onRowDestroy(record, rowIndex) {
const expandedRows = this.getExpandedRows().concat();
@ -170,7 +197,7 @@ const Table = React.createClass({
expandedRows.splice(index, 1);
}
this.onExpandedRowsChange(expandedRows);
},
}
getRowKey(record, index) {
const rowKey = this.props.rowKey;
@ -182,20 +209,20 @@ const Table = React.createClass({
'or set `rowKey` to an unique primary key.'
);
return key;
},
}
getExpandedRows() {
return this.props.expandedRowKeys || this.state.expandedRowKeys;
},
}
getHeader(columns, fixed) {
const { showHeader, expandIconAsCell, prefixCls } = this.props;
const { showHeader, expandIconAsCell, clsPrefix } = this.props;
const rows = this.getHeaderRows(columns);
if (expandIconAsCell && fixed !== 'right') {
rows[0].unshift({
key: 'rc-table-expandIconAsCell',
className: `${prefixCls}-expand-icon-th`,
className: `${clsPrefix}-expand-icon-th`,
title: '',
rowSpan: rows.length,
});
@ -205,12 +232,12 @@ const Table = React.createClass({
return showHeader ? (
<TableHeader
prefixCls={prefixCls}
clsPrefix={clsPrefix}
rows={rows}
rowStyle={trStyle}
/>
) : null;
},
}
getHeaderRows(columns, currentRow = 0, rows) {
rows = rows || [];
@ -241,10 +268,10 @@ const Table = React.createClass({
}
});
return rows.filter(row => row.length > 0);
},
}
getExpandedRow(key, content, visible, className, fixed) {
const { prefixCls, expandIconAsCell } = this.props;
const { clsPrefix, expandIconAsCell } = this.props;
let colCount;
if (fixed === 'left') {
colCount = this.columnManager.leftLeafColumns().length;
@ -274,13 +301,13 @@ const Table = React.createClass({
visible={visible}
className={className}
key={`${key}-extra-row`}
prefixCls={`${prefixCls}-expanded-row`}
clsPrefix={`${clsPrefix}-expanded-row`}
indent={1}
expandable={false}
store={this.store}
/>
);
},
}
getRowsByData(data, visible, indent, columns, fixed) {
const props = this.props;
@ -343,7 +370,7 @@ const Table = React.createClass({
onExpand={this.onExpanded}
expandable={childrenColumn || expandedRowRender}
expanded={isRowExpanded}
prefixCls={`${props.prefixCls}-row`}
clsPrefix={`${props.clsPrefix}-row`}
childrenColumnName={childrenColumnName}
columns={leafColumns}
expandIconColumnIndex={expandIconColumnIndex}
@ -372,18 +399,18 @@ const Table = React.createClass({
}
}
return rst;
},
}
getRows(columns, fixed) {
return this.getRowsByData(this.state.data, true, 0, columns, fixed);
},
}
getColGroup(columns, fixed) {
let cols = [];
if (this.props.expandIconAsCell && fixed !== 'right') {
cols.push(
<col
className={`${this.props.prefixCls}-expand-icon-col`}
className={`${this.props.clsPrefix}-expand-icon-col`}
key="rc-table-expand-icon-col"
/>
);
@ -400,32 +427,32 @@ const Table = React.createClass({
return <col key={c.key} style={{ width: c.width, minWidth: c.width }} />;
}));
return <colgroup>{cols}</colgroup>;
},
}
getLeftFixedTable() {
return this.getTable({
columns: this.columnManager.leftColumns(),
fixed: 'left',
});
},
}
getRightFixedTable() {
return this.getTable({
columns: this.columnManager.rightColumns(),
fixed: 'right',
});
},
}
getTable(options = {}) {
const { columns, fixed } = options;
const { prefixCls, scroll = {}, getBodyWrapper } = this.props;
const { clsPrefix, scroll = {}, getBodyWrapper } = this.props;
let { useFixedHeader } = this.props;
const bodyStyle = { ...this.props.bodyStyle };
const headStyle = {};
let tableClassName = '';
if (scroll.x || fixed) {
tableClassName = `${prefixCls}-fixed`;
tableClassName = `${clsPrefix}-fixed`;
bodyStyle.overflowX = bodyStyle.overflowX || 'auto';
}
@ -459,7 +486,7 @@ const Table = React.createClass({
}
}
const tableBody = hasBody ? getBodyWrapper(
<tbody className={`${prefixCls}-tbody`}>
<tbody className={`${clsPrefix}-tbody`}>
{this.getRows(columns, fixed)}
</tbody>
) : null;
@ -477,7 +504,7 @@ const Table = React.createClass({
if (useFixedHeader) {
headTable = (
<div
className={`${prefixCls}-header`}
className={`${clsPrefix}-header`}
ref={fixed ? null : 'headTable'}
style={headStyle}
onMouseOver={this.detectScrollTarget}
@ -491,7 +518,7 @@ const Table = React.createClass({
let BodyTable = (
<div
className={`${prefixCls}-body`}
className={`${clsPrefix}-body`}
style={bodyStyle}
ref="bodyTable"
onMouseOver={this.detectScrollTarget}
@ -513,11 +540,11 @@ const Table = React.createClass({
delete bodyStyle.overflowY;
BodyTable = (
<div
className={`${prefixCls}-body-outer`}
className={`${clsPrefix}-body-outer`}
style={{ ...bodyStyle }}
>
<div
className={`${prefixCls}-body-inner`}
className={`${clsPrefix}-body-inner`}
ref={refName}
onMouseOver={this.detectScrollTarget}
onTouchStart={this.detectScrollTarget}
@ -530,34 +557,34 @@ const Table = React.createClass({
}
return <span>{headTable}{BodyTable}</span>;
},
}
getTitle() {
const { title, prefixCls } = this.props;
const { title, clsPrefix } = this.props;
return title ? (
<div className={`${prefixCls}-title`}>
<div className={`${clsPrefix}-title`}>
{title(this.state.data)}
</div>
) : null;
},
}
getFooter() {
const { footer, prefixCls } = this.props;
const { footer, clsPrefix } = this.props;
return footer ? (
<div className={`${prefixCls}-footer`}>
<div className={`${clsPrefix}-footer`}>
{footer(this.state.data)}
</div>
) : null;
},
}
getEmptyText() {
const { emptyText, prefixCls, data } = this.props;
const { emptyText, clsPrefix, data } = this.props;
return !data.length ? (
<div className={`${prefixCls}-placeholder`}>
<div className={`${clsPrefix}-placeholder`}>
{emptyText()}
</div>
) : null;
},
}
getHeaderRowStyle(columns, rows) {
const { fixedColumnsHeadRowsHeight } = this.state;
@ -569,14 +596,14 @@ const Table = React.createClass({
return { height: headerHeight / rows.length };
}
return null;
},
}
syncFixedTableRowHeight() {
const { prefixCls } = this.props;
const { clsPrefix } = this.props;
const headRows = this.refs.headTable ?
this.refs.headTable.querySelectorAll('thead') :
this.refs.bodyTable.querySelectorAll('thead');
const bodyRows = this.refs.bodyTable.querySelectorAll(`.${prefixCls}-row`) || [];
const bodyRows = this.refs.bodyTable.querySelectorAll(`.${clsPrefix}-row`) || [];
const fixedColumnsHeadRowsHeight = [].map.call(
headRows, row => row.getBoundingClientRect().height || 'auto'
);
@ -591,7 +618,7 @@ const Table = React.createClass({
fixedColumnsHeadRowsHeight,
fixedColumnsBodyRowsHeight,
});
},
}
resetScrollY() {
if (this.refs.headTable) {
@ -600,22 +627,22 @@ const Table = React.createClass({
if (this.refs.bodyTable) {
this.refs.bodyTable.scrollLeft = 0;
}
},
}
findExpandedRow(record, index) {
const rows = this.getExpandedRows().filter(i => i === this.getRowKey(record, index));
return rows[0];
},
}
isRowExpanded(record, index) {
return typeof this.findExpandedRow(record, index) !== 'undefined';
},
}
detectScrollTarget(e) {
if (this.scrollTarget !== e.currentTarget) {
this.scrollTarget = e.currentTarget;
}
},
}
handleBodyScroll(e) {
// Prevent scrollTop setter trigger onScroll event
@ -654,26 +681,26 @@ const Table = React.createClass({
}
// Remember last scrollLeft for scroll direction detecting.
this.lastScrollLeft = e.target.scrollLeft;
},
}
handleRowHover(isHover, key) {
this.store.setState({
currentHoverKey: isHover ? key : null,
});
},
}
render() {
const props = this.props;
const prefixCls = props.prefixCls;
const clsPrefix = props.clsPrefix;
let className = props.prefixCls;
let className = props.clsPrefix;
if (props.className) {
className += ` ${props.className}`;
}
if (props.useFixedHeader || (props.scroll && props.scroll.y)) {
className += ` ${prefixCls}-fixed-header`;
className += ` ${clsPrefix}-fixed-header`;
}
className += ` ${prefixCls}-scroll-position-${this.state.scrollPosition}`;
className += ` ${clsPrefix}-scroll-position-${this.state.scrollPosition}`;
const isTableScroll = this.columnManager.isAnyColumnsFixed() ||
props.scroll.x ||
@ -682,24 +709,27 @@ const Table = React.createClass({
return (
<div className={className} style={props.style}>
{this.getTitle()}
<div className={`${prefixCls}-content`}>
<div className={`${clsPrefix}-content`}>
{this.columnManager.isAnyColumnsLeftFixed() &&
<div className={`${prefixCls}-fixed-left`}>
<div className={`${clsPrefix}-fixed-left`}>
{this.getLeftFixedTable()}
</div>}
<div className={isTableScroll ? `${prefixCls}-scroll` : ''}>
<div className={isTableScroll ? `${clsPrefix}-scroll` : ''}>
{this.getTable({ columns: this.columnManager.groupedColumns() })}
{this.getEmptyText()}
{this.getFooter()}
</div>
{this.columnManager.isAnyColumnsRightFixed() &&
<div className={`${prefixCls}-fixed-right`}>
<div className={`${clsPrefix}-fixed-right`}>
{this.getRightFixedTable()}
</div>}
</div>
</div>
);
},
});
}
};
Table.propTypes = propTypes;
Table.defaultProps = defaultProps;
export default Table;

View File

@ -1,28 +1,34 @@
import React, { PropTypes } from 'react';
import React, { PropTypes, Component } from 'react';
import objectPath from 'object-path';
const TableCell = React.createClass({
propTypes: {
const propTypes = {
record: PropTypes.object,
prefixCls: PropTypes.string,
clsPrefix: PropTypes.string,
index: PropTypes.number,
indent: PropTypes.number,
indentSize: PropTypes.number,
column: PropTypes.object,
expandIcon: PropTypes.node,
},
expandIcon: PropTypes.node
};
class TableCell extends Component{
constructor(props){
super(props);
this.isInvalidRenderCellText = this.isInvalidRenderCellText.bind(this);
this.handleClick = this.handleClick.bind(this);
}
isInvalidRenderCellText(text) {
return text && !React.isValidElement(text) &&
Object.prototype.toString.call(text) === '[object Object]';
},
}
handleClick(e) {
const { record, column: { onCellClick } } = this.props;
if (onCellClick) {
onCellClick(record, e);
}
},
}
render() {
const { record, indentSize, prefixCls, indent,
const { record, indentSize, clsPrefix, indent,
index, expandIcon, column } = this.props;
const { dataIndex, render, className = '' } = column;
@ -41,7 +47,7 @@ const TableCell = React.createClass({
}
}
// Fix https://github.com/ant-design/ant-design/issues/1202
if (this.isInvalidRenderCellText(text)) {
text = null;
}
@ -49,7 +55,7 @@ const TableCell = React.createClass({
const indentText = expandIcon ? (
<span
style={{ paddingLeft: `${indentSize * indent}px` }}
className={`${prefixCls}-indent indent-level-${indent}`}
className={`${clsPrefix}-indent indent-level-${indent}`}
/>
) : null;
@ -68,7 +74,9 @@ const TableCell = React.createClass({
{text}
</td>
);
},
});
}
};
TableCell.propTypes = propTypes;
export default TableCell;

View File

@ -1,19 +1,23 @@
import React, { PropTypes } from 'react';
import React, { PropTypes, Component } from 'react';
import shallowequal from 'shallowequal';
export default React.createClass({
propTypes: {
prefixCls: PropTypes.string,
const propTypes = {
clsPrefix: PropTypes.string,
rowStyle: PropTypes.object,
rows: PropTypes.array,
},
}
class TableHeader extends Component{
constructor(props){
super(props);
}
shouldComponentUpdate(nextProps) {
return !shallowequal(nextProps, this.props);
},
}
render() {
const { prefixCls, rowStyle, rows } = this.props;
const { clsPrefix, rowStyle, rows } = this.props;
return (
<thead className={`${prefixCls}-thead`}>
<thead className={`${clsPrefix}-thead`}>
{
rows.map((row, index) => (
<tr key={index} style={rowStyle}>
@ -23,5 +27,9 @@ export default React.createClass({
}
</thead>
);
},
});
}
};
TableHeader.propTypes = propTypes;
export default TableHeader;

View File

@ -1,14 +1,13 @@
import React, { PropTypes } from 'react';
import React, { PropTypes, Component } from 'react';
import TableCell from './TableCell';
import ExpandIcon from './ExpandIcon';
const TableRow = React.createClass({
propTypes: {
const propTypes = {
onDestroy: PropTypes.func,
onRowClick: PropTypes.func,
onRowDoubleClick: PropTypes.func,
record: PropTypes.object,
prefixCls: PropTypes.string,
clsPrefix: PropTypes.string,
expandIconColumnIndex: PropTypes.number,
onHover: PropTypes.func,
columns: PropTypes.array,
@ -29,24 +28,30 @@ const TableRow = React.createClass({
expandIconAsCell: PropTypes.bool,
expandRowByClick: PropTypes.bool,
store: PropTypes.object.isRequired,
},
};
getDefaultProps() {
return {
onRowClick() {},
onRowDoubleClick() {},
onDestroy() {},
expandIconColumnIndex: 0,
expandRowByClick: false,
onHover() {},
};
},
const defaultProps = {
onRowClick() {},
onRowDoubleClick() {},
onDestroy() {},
expandIconColumnIndex: 0,
expandRowByClick: false,
onHover() {},
};
class TableRow extends Component{
constructor(props){
super(props);
this.state = {
hovered: false,
};
this.onRowClick = this.onRowClick.bind(this);
this.onRowDoubleClick = this.onRowDoubleClick.bind(this);
this.onMouseEnter = this.onMouseEnter.bind(this);
this.onMouseLeave = this.onMouseLeave.bind(this);
}
getInitialState() {
return {
hovered: false,
};
},
componentDidMount() {
const { store, hoverKey } = this.props;
@ -57,7 +62,7 @@ const TableRow = React.createClass({
this.setState({ hovered: false });
}
});
},
}
componentWillUnmount() {
const { record, onDestroy, index } = this.props;
@ -65,7 +70,7 @@ const TableRow = React.createClass({
if (this.unsubscribe) {
this.unsubscribe();
}
},
}
onRowClick(event) {
const {
@ -81,26 +86,26 @@ const TableRow = React.createClass({
onExpand(!expanded, record, index);
}
onRowClick(record, index, event);
},
}
onRowDoubleClick(event) {
const { record, index, onRowDoubleClick } = this.props;
onRowDoubleClick(record, index, event);
},
}
onMouseEnter() {
const { onHover, hoverKey } = this.props;
onHover(true, hoverKey);
},
}
onMouseLeave() {
const { onHover, hoverKey } = this.props;
onHover(false, hoverKey);
},
}
render() {
const {
prefixCls, columns, record, height, visible, index,
clsPrefix, columns, record, height, visible, index,
expandIconColumnIndex, expandIconAsCell, expanded, expandRowByClick,
expandable, onExpand, needIndentSpaced, indent, indentSize,
} = this.props;
@ -108,7 +113,7 @@ const TableRow = React.createClass({
let { className } = this.props;
if (this.state.hovered) {
className += ` ${prefixCls}-hover`;
className += ` ${clsPrefix}-hover`;
}
const cells = [];
@ -116,7 +121,7 @@ const TableRow = React.createClass({
const expandIcon = (
<ExpandIcon
expandable={expandable}
prefixCls={prefixCls}
clsPrefix={clsPrefix}
onExpand={onExpand}
needIndentSpaced={needIndentSpaced}
expanded={expanded}
@ -128,7 +133,7 @@ const TableRow = React.createClass({
if (expandIconAsCell && i === 0) {
cells.push(
<td
className={`${prefixCls}-expand-icon-cell`}
className={`${clsPrefix}-expand-icon-cell`}
key="rc-table-expand-icon-cell"
>
{expandIcon}
@ -139,7 +144,7 @@ const TableRow = React.createClass({
? false : (i === expandIconColumnIndex);
cells.push(
<TableCell
prefixCls={prefixCls}
clsPrefix={clsPrefix}
record={record}
indentSize={indentSize}
indent={indent}
@ -161,13 +166,16 @@ const TableRow = React.createClass({
onDoubleClick={this.onRowDoubleClick}
onMouseEnter={this.onMouseEnter}
onMouseLeave={this.onMouseLeave}
className={`${prefixCls} ${className} ${prefixCls}-level-${indent}`}
className={`${clsPrefix} ${className} ${clsPrefix}-level-${indent}`}
style={style}
>
{cells}
</tr>
);
},
});
}
};
TableRow.propTypes = propTypes;
TableRow.defaultProps = defaultProps;
export default TableRow;

View File

@ -1,59 +0,0 @@
.move-enter, .move-appear {
opacity: 0;
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
animation-duration: 2.5s;
animation-fill-mode: both;
animation-play-state: paused;
}
.move-leave {
animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
animation-duration: .5s;
animation-fill-mode: both;
animation-play-state: paused;
}
.move-enter.move-enter-active, .move-appear.move-enter-active {
animation-name: moveLeftIn;
animation-play-state: running;
}
.move-leave.move-leave-active {
animation-name: moveRightOut;
animation-play-state: running;
}
@keyframes moveLeftIn {
0% {
transform-origin: 0 0;
transform: translateX(30px);
opacity: 0;
background: #fff6de;
}
20% {
transform-origin: 0 0;
transform: translateX(0);
opacity: 1;
}
80%{
background: #fff6de;
}
100%{
background: transparent;
opacity: 1;
}
}
@keyframes moveRightOut {
0% {
transform-origin: 0 0;
transform: translateX(0);
opacity: 1;
}
100% {
transform-origin: 0 0;
transform: translateX(-30px);
opacity: 0;
}
}

View File

@ -1,11 +0,0 @@
$table-border-color: #e9e9e9;
.u-table.bordered {
table {
border-collapse: collapse;
}
th, td {
border: 1px solid $table-border-color;
}
}

View File

@ -2,10 +2,16 @@
$text-color : #666;
$font-size-base : 12px;
$line-height: 1.5;
$table-border-color: #e9e9e9;
$table-border-color: $border-color-base;
$table-head-background-color: #f7f7f7;
$vertical-padding: 16px;
$horizontal-padding: 8px;
$table-border-color: #e9e9e9;
$table-hover-color: unquote("rgb(#{$palette-blue-50})") !default;
$table-move-in-color: $bg-color-base;
.u-table {
font-size: $font-size-base;
@ -15,6 +21,38 @@ $horizontal-padding: 8px;
line-height: $line-height;
overflow: hidden;
table {
width: 100%;
border-collapse: collapse;
text-align: left;
}
th {
background: $table-head-background-color;
font-weight: bold;
transition: background .3s ease;
}
td {
border-bottom: 1px solid $table-border-color;
}
tr {
transition: all .3s ease;
&:hover {
background: $table-hover-color;
}
}
tr.tr-row-hover {
background: $table-hover-color;
}
th, td {
padding: $vertical-padding $horizontal-padding;
}
&-scroll {
overflow: auto;
}
@ -64,39 +102,6 @@ $horizontal-padding: 8px;
position: relative;
}
table {
width: 100%;
border-collapse: separate;
text-align: left;
}
th {
background: $table-head-background-color;
font-weight: bold;
transition: background .3s ease;
}
td {
border-bottom: 1px solid $table-border-color;
}
tr {
transition: all .3s ease;
&:hover {
background: #eaf8fe;
}
}
tr.tr-row-hover {
background: #eaf8fe;
}
th, td {
padding: $vertical-padding $horizontal-padding;
}
}
.u-table {
&-expand-icon-col {
width: 10px;
}
@ -209,3 +214,75 @@ $horizontal-padding: 8px;
box-shadow: none;
}
}
.u-table.bordered {
table {
border-collapse: collapse;
}
th, td {
border: 1px solid $table-border-color;
}
}
.move-enter, .move-appear {
opacity: 0;
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
animation-duration: 2.5s;
animation-fill-mode: both;
animation-play-state: paused;
}
.move-leave {
animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
animation-duration: .5s;
animation-fill-mode: both;
animation-play-state: paused;
}
.move-enter.move-enter-active, .move-appear.move-enter-active {
animation-name: moveLeftIn;
animation-play-state: running;
}
.move-leave.move-leave-active {
animation-name: moveRightOut;
animation-play-state: running;
}
@keyframes moveLeftIn {
0% {
transform-origin: 0 0;
transform: translateX(30px);
opacity: 0;
background: $table-move-in-color;
}
20% {
transform-origin: 0 0;
transform: translateX(0);
opacity: 1;
}
80%{
background: $table-move-in-color;
}
100%{
background: transparent;
opacity: 1;
}
}
@keyframes moveRightOut {
0% {
transform-origin: 0 0;
transform: translateX(0);
opacity: 1;
}
100% {
transform-origin: 0 0;
transform: translateX(-30px);
opacity: 0;
}
}