From 6110663075fa262ff2bc11de5ee877c46829eed5 Mon Sep 17 00:00:00 2001 From: Allen Date: Mon, 30 Oct 2017 14:24:39 +0800 Subject: [PATCH] fix #128 * implement custom row classes * add story for customizing row classes * add test for rowClasses * patch docs for rowClasses --- docs/README.md | 18 ++++ .../examples/rows/row-class.js | 81 ++++++++++++++++++ .../stories/index.js | 4 +- .../stories/stylesheet/rows/_index.scss | 7 ++ .../stories/stylesheet/storybook.scss | 3 +- packages/react-bootstrap-table2/src/body.js | 14 +++- .../src/bootstrap-table.js | 5 +- .../react-bootstrap-table2/test/body.test.js | 84 ++++++++++++++++++- 8 files changed, 207 insertions(+), 9 deletions(-) create mode 100644 packages/react-bootstrap-table2-example/examples/rows/row-class.js create mode 100644 packages/react-bootstrap-table2-example/stories/stylesheet/rows/_index.scss diff --git a/docs/README.md b/docs/README.md index 1d852ca..aab6265 100644 --- a/docs/README.md +++ b/docs/README.md @@ -16,6 +16,7 @@ * [cellEdit](#cellEdit) * [selectRow](#selectRow) * [rowStyle](#rowStyle) +* [rowClasses](#rowClasses) * [defaultSorted](#defaultSorted) ### keyField(**required**) - [String] @@ -62,6 +63,23 @@ const rowStyle = (row, rowIndex) => { ``` +### rowClasses = [String | Function] +Custom the style of table rows: + +```js + +``` + +This prop also accept a callback function for flexible to custom row style: + +```js +const rowClasses = (row, rowIndex) => { + return 'custom-row-class'; +}; + + +``` + ### defaultSorted - [Array] `defaultSorted` accept an object array which allow you to define the default sort columns when first render. diff --git a/packages/react-bootstrap-table2-example/examples/rows/row-class.js b/packages/react-bootstrap-table2-example/examples/rows/row-class.js new file mode 100644 index 0000000..b17f6b1 --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/rows/row-class.js @@ -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'; + + +`; + +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; +}; + + +`; + +export default () => ( +
+ + { sourceCode1 } + + { sourceCode2 } +
+); diff --git a/packages/react-bootstrap-table2-example/stories/index.js b/packages/react-bootstrap-table2-example/stories/index.js index bd1522f..c267778 100644 --- a/packages/react-bootstrap-table2-example/stories/index.js +++ b/packages/react-bootstrap-table2-example/stories/index.js @@ -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', () => ); storiesOf('Work on Rows', module) - .add('Row Style', () => ); + .add('Customize Row Style', () => ) + .add('Customize Row Class', () => ); storiesOf('Sort Table', module) .add('Enable Sort', () => ) diff --git a/packages/react-bootstrap-table2-example/stories/stylesheet/rows/_index.scss b/packages/react-bootstrap-table2-example/stories/stylesheet/rows/_index.scss new file mode 100644 index 0000000..16da83d --- /dev/null +++ b/packages/react-bootstrap-table2-example/stories/stylesheet/rows/_index.scss @@ -0,0 +1,7 @@ +.custom-row-class { + background-color: #c8e6c9; +} + +.index-bigger-than-two { + background-color: #00BFFF; +} \ No newline at end of file diff --git a/packages/react-bootstrap-table2-example/stories/stylesheet/storybook.scss b/packages/react-bootstrap-table2-example/stories/stylesheet/storybook.scss index 47a18b1..3bbec85 100644 --- a/packages/react-bootstrap-table2-example/stories/stylesheet/storybook.scss +++ b/packages/react-bootstrap-table2-example/stories/stylesheet/storybook.scss @@ -6,4 +6,5 @@ @import "welcome/index"; @import "columns/index"; @import "cell-edit/index"; -@import "row-selection/index"; \ No newline at end of file +@import "row-selection/index"; +@import "rows/index"; \ No newline at end of file diff --git a/packages/react-bootstrap-table2/src/body.js b/packages/react-bootstrap-table2/src/body.js index f8c07f9..85f4e35 100644 --- a/packages/react-bootstrap-table2/src/body.js +++ b/packages/react-bootstrap-table2/src/body.js @@ -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 || {}; diff --git a/packages/react-bootstrap-table2/src/bootstrap-table.js b/packages/react-bootstrap-table2/src/bootstrap-table.js index 32103b2..b82d819 100644 --- a/packages/react-bootstrap-table2/src/bootstrap-table.js +++ b/packages/react-bootstrap-table2/src/bootstrap-table.js @@ -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 } /> @@ -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 diff --git a/packages/react-bootstrap-table2/test/body.test.js b/packages/react-bootstrap-table2/test/body.test.js index 1f160ad..51176d6 100644 --- a/packages/react-bootstrap-table2/test/body.test.js +++ b/packages/react-bootstrap-table2/test/body.test.js @@ -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( + ); + }); + + 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( + ); + }); + + 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( + ); + }); + + 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 = {