* implement custom row classes

* add story for customizing row classes

* add test for rowClasses

* patch docs for rowClasses
This commit is contained in:
Allen 2017-10-30 14:24:39 +08:00 committed by GitHub
parent 19dc4d3984
commit 6110663075
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 207 additions and 9 deletions

View File

@ -16,6 +16,7 @@
* [cellEdit](#cellEdit)
* [selectRow](#selectRow)
* [rowStyle](#rowStyle)
* [rowClasses](#rowClasses)
* [defaultSorted](#defaultSorted)
### <a name='keyField'>keyField(**required**) - [String]</a>
@ -62,6 +63,23 @@ const rowStyle = (row, rowIndex) => {
<BootstrapTable data={ ... } columns={ ... } rowStyle={ rowStyle } />
```
### <a name='rowClasses'>rowClasses = [String | Function]</a>
Custom the style of table rows:
```js
<BootstrapTable data={ ... } columns={ ... } rowClasses="custom-row-class" />
```
This prop also accept a callback function for flexible to custom row style:
```js
const rowClasses = (row, rowIndex) => {
return 'custom-row-class';
};
<BootstrapTable data={ ... } columns={ ... } rowClasses={ rowClasses } />
```
### <a name='defaultSorted'>defaultSorted - [Array]</a>
`defaultSorted` accept an object array which allow you to define the default sort columns when first render.

View File

@ -0,0 +1,81 @@
import React from 'react';
import BootstrapTable from 'react-bootstrap-table2';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const rowClasses1 = 'custom-row-class';
const sourceCode1 = `\
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const rowClasses = 'custom-row-class';
<BootstrapTable keyField='id' data={ products } columns={ columns } rowClasses={ rowClasses } />
`;
const rowClasses2 = (row, rowIndex) => {
let classes = null;
if (rowIndex > 2) {
classes = 'index-bigger-than-two';
}
return classes;
};
const sourceCode2 = `\
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const rowClasses = (row, rowIndex) => {
let classes = null;
if (rowIndex > 2) {
classes = 'index-bigger-than-two';
}
return classes;
};
<BootstrapTable keyField='id' data={ products } columns={ columns } rowClasses={ rowClasses } />
`;
export default () => (
<div>
<BootstrapTable keyField="id" data={ products } columns={ columns } rowClasses={ rowClasses1 } />
<Code>{ sourceCode1 }</Code>
<BootstrapTable keyField="id" data={ products } columns={ columns } rowClasses={ rowClasses2 } />
<Code>{ sourceCode2 }</Code>
</div>
);

View File

@ -34,6 +34,7 @@ import HeaderColumnAttrsTable from 'examples/header-columns/column-attrs-table';
// work on rows
import RowStyleTable from 'examples/rows/row-style';
import RowClassTable from 'examples/rows/row-class';
// table sort
import EnableSortTable from 'examples/sort/enable-sort-table';
@ -107,7 +108,8 @@ storiesOf('Work on Header Columns', module)
.add('Customize Column HTML attribute', () => <HeaderColumnAttrsTable />);
storiesOf('Work on Rows', module)
.add('Row Style', () => <RowStyleTable />);
.add('Customize Row Style', () => <RowStyleTable />)
.add('Customize Row Class', () => <RowClassTable />);
storiesOf('Sort Table', module)
.add('Enable Sort', () => <EnableSortTable />)

View File

@ -0,0 +1,7 @@
.custom-row-class {
background-color: #c8e6c9;
}
.index-bigger-than-two {
background-color: #00BFFF;
}

View File

@ -6,4 +6,5 @@
@import "welcome/index";
@import "columns/index";
@import "cell-edit/index";
@import "row-selection/index";
@import "row-selection/index";
@import "rows/index";

View File

@ -3,6 +3,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import cs from 'classnames';
import _ from './utils';
import Row from './row';
@ -20,11 +21,11 @@ const Body = (props) => {
cellEdit,
selectRow,
selectedRowKeys,
rowStyle
rowStyle,
rowClasses
} = props;
const {
classes: selectedClasses,
bgColor,
nonSelectable
} = selectRow;
@ -45,16 +46,21 @@ const Body = (props) => {
: null;
let style = _.isFunction(rowStyle) ? rowStyle(row, index) : rowStyle;
let classes;
let classes = (_.isFunction(rowClasses) ? rowClasses(row, index) : rowClasses);
if (selected) {
const selectedStyle = _.isFunction(selectRow.style)
? selectRow.style(row, index)
: selectRow.style;
const selectedClasses = _.isFunction(selectRow.classes)
? selectRow.classes(row, index)
: selectRow.classes;
style = {
...style,
...selectedStyle
};
classes = _.isFunction(selectedClasses) ? selectedClasses(row, index) : selectedClasses;
classes = cs(classes, selectedClasses);
if (bgColor) {
style = style || {};

View File

@ -36,7 +36,8 @@ class BootstrapTable extends PropsBaseResolver(Component) {
condensed,
noDataIndication,
caption,
rowStyle
rowStyle,
rowClasses
} = this.props;
const tableClass = cs('table', {
@ -85,6 +86,7 @@ class BootstrapTable extends PropsBaseResolver(Component) {
selectRow={ cellSelectionInfo }
selectedRowKeys={ store.getSelectedRowKeys() }
rowStyle={ rowStyle }
rowClasses={ rowClasses }
/>
</table>
</div>
@ -143,6 +145,7 @@ BootstrapTable.propTypes = {
onRowSelect: PropTypes.func,
onAllRowsSelect: PropTypes.func,
rowStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
rowClasses: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
defaultSorted: PropTypes.arrayOf(PropTypes.shape({
dataField: PropTypes.string.isRequired,
order: PropTypes.oneOf([Const.SORT_DESC, Const.SORT_ASC]).isRequired

View File

@ -155,11 +155,11 @@ describe('Body', () => {
/>);
});
it('should calling rowStyleCallBack correctly', () => {
it('should calling rowStyle callBack correctly', () => {
expect(rowStyleCallBack.callCount).toBe(data.length);
});
it('should calling rowStyleCallBack with correct argument', () => {
it('should calling rowStyle callBack with correct argument', () => {
expect(rowStyleCallBack.firstCall.calledWith(data[0], 0)).toBeTruthy();
expect(rowStyleCallBack.secondCall.calledWith(data[1], 1)).toBeTruthy();
});
@ -259,6 +259,86 @@ describe('Body', () => {
});
});
describe('when rowClasses prop is defined', () => {
const rowClasses = 'test-classe';
describe('and it is a string', () => {
beforeEach(() => {
wrapper = shallow(
<Body
{ ...mockBodyResolvedProps }
keyField="id"
columns={ columns }
data={ data }
rowClasses={ rowClasses }
/>);
});
it('should rendering Row component with correct className', () => {
const rows = wrapper.find(Row);
rows.forEach((row) => {
expect(row.props().className).toEqual(rowClasses);
});
});
});
describe('and it is a callback function', () => {
const rowClassesCallBack = sinon.stub().returns(rowClasses);
beforeEach(() => {
wrapper = shallow(
<Body
{ ...mockBodyResolvedProps }
keyField="id"
columns={ columns }
data={ data }
rowClasses={ rowClassesCallBack }
/>);
});
it('should calling rowClasses callback correctly', () => {
expect(rowClassesCallBack.callCount).toBe(data.length);
});
it('should calling rowClasses callback with correct argument', () => {
expect(rowClassesCallBack.firstCall.calledWith(data[0], 0)).toBeTruthy();
expect(rowClassesCallBack.secondCall.calledWith(data[1], 1)).toBeTruthy();
});
it('should rendering Row component with correct className', () => {
const rows = wrapper.find(Row);
rows.forEach((row) => {
expect(row.props().className).toEqual(rowClasses);
});
});
});
describe('when selectRow.classes is defined', () => {
const selectedRowKey = data[0][keyField];
const selectedRowKeys = [selectedRowKey];
const selectedClasses = 'selected-classes';
const selectRow = { mode: 'radio', classes: selectedClasses };
beforeEach(() => {
wrapper = shallow(
<Body
{ ...mockBodyResolvedProps }
keyField="id"
columns={ columns }
data={ data }
rowClasses={ rowClasses }
selectRow={ selectRow }
selectedRowKeys={ selectedRowKeys }
/>);
});
it('should rendering selected Row component with mixing selectRow.classes correctly', () => {
const selectedRow = wrapper.find(Row).get(0);
expect(selectedRow.props.className).toBe(`${rowClasses} ${selectedClasses}`);
});
});
});
describe('when cellEdit.nonEditableRows props is defined', () => {
const nonEditableRows = [data[1].id];
const cellEdit = {