* implement custom row style

* add story for custom row style

* add tests for rowStyle

* patch docs for rowStyle
This commit is contained in:
Allen 2017-10-29 18:17:20 +08:00 committed by GitHub
parent e1e8c00271
commit 19dc4d3984
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 275 additions and 10 deletions

View File

@ -15,6 +15,7 @@
* [condensed](#condensed)
* [cellEdit](#cellEdit)
* [selectRow](#selectRow)
* [rowStyle](#rowStyle)
* [defaultSorted](#defaultSorted)
### <a name='keyField'>keyField(**required**) - [String]</a>
@ -44,6 +45,23 @@ Makes table cells editable, please see [cellEdit definition](./cell-edit.md) for
### <a name='selectRow'>selectRow - [Object]</a>
Makes table rows selectable, please see [selectRow definition](./row-selection.md) for more detail.
### <a name='rowStyle'>rowStyle = [Object | Function]</a>
Custom the style of table rows:
```js
<BootstrapTable data={ ... } columns={ ... } rowStyle={ { backgroundColor: 'red' } } />
```
This prop also accept a callback function for flexible to custom row style:
```js
const rowStyle = (row, rowIndex) => {
return { ... };
};
<BootstrapTable data={ ... } columns={ ... } rowStyle={ rowStyle } />
```
### <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,93 @@
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 rowStyle1 = { backgroundColor: '#c8e6c9' };
const sourceCode1 = `\
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const rowStyle = { backgroundColor: '#c8e6c9' };
<BootstrapTable keyField='id' data={ products } columns={ columns } rowStyle={ rowStyle } />
`;
const rowStyle2 = (row, rowIndex) => {
const style = {};
if (row.id > 3) {
style.backgroundColor = '#c8e6c9';
} else {
style.backgroundColor = '#00BFFF';
}
if (rowIndex > 2) {
style.fontWeight = 'bold';
style.color = 'white';
}
return style;
};
const sourceCode2 = `\
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const rowStyle2 = (row, rowIndex) => {
const style = {};
if (row.id > 3) {
style.backgroundColor = '#c8e6c9';
} else {
style.backgroundColor = '#00BFFF';
}
if (rowIndex > 2) {
style.fontWeight = 'bold';
style.color = 'white';
}
return style;
};
<BootstrapTable keyField='id' data={ products } columns={ columns } rowStyle={ rowStyle2 } />
`;
export default () => (
<div>
<BootstrapTable keyField="id" data={ products } columns={ columns } rowStyle={ rowStyle1 } />
<Code>{ sourceCode1 }</Code>
<BootstrapTable keyField="id" data={ products } columns={ columns } rowStyle={ rowStyle2 } />
<Code>{ sourceCode2 }</Code>
</div>
);

View File

@ -32,6 +32,9 @@ import HeaderColumnClassTable from 'examples/header-columns/column-class-table';
import HeaderColumnStyleTable from 'examples/header-columns/column-style-table';
import HeaderColumnAttrsTable from 'examples/header-columns/column-attrs-table';
// work on rows
import RowStyleTable from 'examples/rows/row-style';
// table sort
import EnableSortTable from 'examples/sort/enable-sort-table';
import DefaultSortTable from 'examples/sort/default-sort-table';
@ -103,6 +106,9 @@ storiesOf('Work on Header Columns', module)
.add('Customize Column Style', () => <HeaderColumnStyleTable />)
.add('Customize Column HTML attribute', () => <HeaderColumnAttrsTable />);
storiesOf('Work on Rows', module)
.add('Row Style', () => <RowStyleTable />);
storiesOf('Sort Table', module)
.add('Enable Sort', () => <EnableSortTable />)
.add('Default Sort Table', () => <DefaultSortTable />)

View File

@ -19,11 +19,11 @@ const Body = (props) => {
visibleColumnSize,
cellEdit,
selectRow,
selectedRowKeys
selectedRowKeys,
rowStyle
} = props;
const {
style: selectedStyle,
classes: selectedClasses,
bgColor,
nonSelectable
@ -44,10 +44,16 @@ const Body = (props) => {
? selectedRowKeys.includes(key)
: null;
let style;
let style = _.isFunction(rowStyle) ? rowStyle(row, index) : rowStyle;
let classes;
if (selected) {
style = _.isFunction(selectedStyle) ? selectedStyle(row, index) : selectedStyle;
const selectedStyle = _.isFunction(selectRow.style)
? selectRow.style(row, index)
: selectRow.style;
style = {
...style,
...selectedStyle
};
classes = _.isFunction(selectedClasses) ? selectedClasses(row, index) : selectedClasses;
if (bgColor) {

View File

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

View File

@ -26,6 +26,8 @@ describe('Body', () => {
name: 'B'
}];
const keyField = 'id';
describe('simplest body', () => {
beforeEach(() => {
wrapper = shallow(<Body { ...mockBodyResolvedProps } keyField="id" columns={ columns } data={ data } />);
@ -117,9 +119,148 @@ describe('Body', () => {
});
});
describe('when rowStyle prop is defined', () => {
const rowStyle = { backgroundColor: 'red', color: 'white' };
describe('and it is a style object', () => {
beforeEach(() => {
wrapper = shallow(
<Body
{ ...mockBodyResolvedProps }
keyField="id"
columns={ columns }
data={ data }
rowStyle={ rowStyle }
/>);
});
it('should rendering Row component with correct style', () => {
const rows = wrapper.find(Row);
rows.forEach((row) => {
expect(row.props().style).toEqual(rowStyle);
});
});
});
describe('and it is a callback functoin', () => {
const rowStyleCallBack = sinon.stub().returns(rowStyle);
beforeEach(() => {
wrapper = shallow(
<Body
{ ...mockBodyResolvedProps }
keyField="id"
columns={ columns }
data={ data }
rowStyle={ rowStyleCallBack }
/>);
});
it('should calling rowStyleCallBack correctly', () => {
expect(rowStyleCallBack.callCount).toBe(data.length);
});
it('should calling rowStyleCallBack with correct argument', () => {
expect(rowStyleCallBack.firstCall.calledWith(data[0], 0)).toBeTruthy();
expect(rowStyleCallBack.secondCall.calledWith(data[1], 1)).toBeTruthy();
});
it('should rendering Row component with correct style', () => {
const rows = wrapper.find(Row);
rows.forEach((row) => {
expect(row.props().style).toEqual(rowStyle);
});
});
});
describe('when selectRow.style is defined', () => {
const selectedRowKey = data[0][keyField];
const selectedRowKeys = [selectedRowKey];
const selectedStyle = { backgroundColor: 'green', fontWeight: 'bold' };
const selectRow = { mode: 'radio', style: selectedStyle };
beforeEach(() => {
wrapper = shallow(
<Body
{ ...mockBodyResolvedProps }
keyField="id"
columns={ columns }
data={ data }
rowStyle={ rowStyle }
selectRow={ selectRow }
selectedRowKeys={ selectedRowKeys }
/>);
});
it('should rendering selected Row component with mixing selectRow.style correctly', () => {
const selectedRow = wrapper.find(Row).get(0);
expect(JSON.stringify(selectedRow.props.style)).toBe(JSON.stringify({
...rowStyle,
...selectedStyle
}));
});
describe('and selectRow.bgColor is also defined', () => {
beforeEach(() => {
selectRow.bgColor = 'gray';
wrapper = shallow(
<Body
{ ...mockBodyResolvedProps }
keyField="id"
columns={ columns }
data={ data }
rowStyle={ rowStyle }
selectRow={ selectRow }
selectedRowKeys={ selectedRowKeys }
/>);
});
it('should rendering selected Row component with mixing selectRow.style correctly', () => {
const selectedRow = wrapper.find(Row).get(0);
expect(JSON.stringify(selectedRow.props.style)).toBe(JSON.stringify({
...rowStyle,
...selectedStyle,
backgroundColor: selectRow.bgColor
}));
});
it('should render selected Row component with correct style.backgroundColor', () => {
const selectedRow = wrapper.find(Row).get(0);
expect(selectedRow.props.style.backgroundColor).toEqual(selectRow.bgColor);
});
});
});
describe('when selectRow.bgColor is defined', () => {
const selectedRowKey = data[0][keyField];
const selectedRowKeys = [selectedRowKey];
const selectRow = { mode: 'radio', bgColor: 'gray' };
beforeEach(() => {
selectRow.bgColor = 'gray';
wrapper = shallow(
<Body
{ ...mockBodyResolvedProps }
keyField="id"
columns={ columns }
data={ data }
rowStyle={ rowStyle }
selectRow={ selectRow }
selectedRowKeys={ selectedRowKeys }
/>);
});
it('should rendering selected Row component with correct style', () => {
const selectedRow = wrapper.find(Row).get(0);
expect(JSON.stringify(selectedRow.props.style)).toBe(JSON.stringify({
...rowStyle,
backgroundColor: selectRow.bgColor
}));
});
});
});
describe('when cellEdit.nonEditableRows props is defined', () => {
const nonEditableRows = [data[1].id];
const keyField = 'id';
const cellEdit = {
mode: Const.CLICK_TO_CELL_EDIT,
nonEditableRows
@ -150,7 +291,6 @@ describe('Body', () => {
});
describe('when selectRow.mode is checkbox or radio (row was selectable)', () => {
const keyField = 'id';
const selectRow = { mode: 'checkbox' };
const selectedRowKey = data[0][keyField];
const selectedRowKeys = [selectedRowKey];
@ -194,7 +334,7 @@ describe('Body', () => {
});
it('should render Row component with correct style prop', () => {
expect(wrapper.find(Row).get(0).props.style).toBe(style);
expect(JSON.stringify(wrapper.find(Row).get(0).props.style)).toBe(JSON.stringify(style));
});
});
@ -222,7 +362,7 @@ describe('Body', () => {
});
it('should render Row component with correct style prop', () => {
expect(wrapper.find(Row).get(0).props.style).toBe(style);
expect(JSON.stringify(wrapper.find(Row).get(0).props.style)).toBe(JSON.stringify(style));
});
});
@ -377,7 +517,6 @@ describe('Body', () => {
describe('when selectRow.mode is ROW_SELECT_DISABLED (row was un-selectable)', () => {
beforeEach(() => {
const keyField = 'id';
wrapper = shallow(
<Body
{ ...mockBodyResolvedProps }