mirror of
https://github.com/gosticks/react-bootstrap-table2.git
synced 2025-10-16 11:55:39 +00:00
fix #104
* implement row seleciton style and class * add testing for row selection style and class * refine select row test * add stories for row selection style and class * add docs for row selection style and class * patch for wrong docs
This commit is contained in:
parent
cb6410bbe4
commit
10f06dca10
@ -478,7 +478,7 @@ Or take a callback function
|
||||
}
|
||||
```
|
||||
|
||||
## <a name='editCellClasses'>column.editCellClasses - [Object | Function]</a>
|
||||
## <a name='editCellClasses'>column.editCellClasses - [String | Function]</a>
|
||||
You can use `column.editCellClasses` to add custom class on `<td>` when cell editing. It's same as [`column.editCellStyle`](#editCellStyle) which also accept a callback function to able to custom your class more flexible. Following is the arguments of this callback function: `cell`, `row`, `rowIndex`, `colIndex`.
|
||||
|
||||
```js
|
||||
|
||||
@ -9,6 +9,8 @@ The following are available properties in `selectRow`:
|
||||
|
||||
#### Required
|
||||
* [mode (**required**)](#mode)
|
||||
* [style](#style)
|
||||
* [classes)](#classes)
|
||||
|
||||
#### Optional
|
||||
|
||||
@ -46,3 +48,41 @@ const selectRow = {
|
||||
selectRow={ selectRowProp }
|
||||
/>
|
||||
```
|
||||
|
||||
## <a name='style'>selectRow.style - [Object | Function]</a>
|
||||
`selectRow.style` allow you to have custom style on selected rows:
|
||||
|
||||
```js
|
||||
const selectRow = {
|
||||
mode: 'checkbox',
|
||||
style: { background: 'red' }
|
||||
};
|
||||
```
|
||||
|
||||
If you wanna more flexible customization, `selectRow.style` also accept a function:
|
||||
|
||||
```js
|
||||
const selectRow = {
|
||||
mode: 'checkbox',
|
||||
style: (row, rowIndex) => { return ...; }
|
||||
};
|
||||
```
|
||||
|
||||
## <a name='classes'>selectRow.classes - [String | Function]</a>
|
||||
`selectRow.classes` allow you to add css class on selected rows:
|
||||
|
||||
```js
|
||||
const selectRow = {
|
||||
mode: 'checkbox',
|
||||
classes: 'custom-class'
|
||||
};
|
||||
```
|
||||
|
||||
If you wanna more flexible customization, `selectRow.classes` also accept a function:
|
||||
|
||||
```js
|
||||
const selectRow = {
|
||||
mode: 'checkbox',
|
||||
classes: (row, rowIndex) => { return ...; }
|
||||
};
|
||||
```
|
||||
|
||||
90
packages/react-bootstrap-table2-example/examples/row-selection/selection-class.js
vendored
Normal file
90
packages/react-bootstrap-table2-example/examples/row-selection/selection-class.js
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
/* eslint no-unused-vars: 0 */
|
||||
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 selectRow1 = {
|
||||
mode: 'checkbox',
|
||||
classes: 'selection-row'
|
||||
};
|
||||
|
||||
const selectRow2 = {
|
||||
mode: 'checkbox',
|
||||
classes: (row, rowIndex) =>
|
||||
(rowIndex > 1 ? 'row-index-bigger-than-2101' : 'row-index-small-than-2101')
|
||||
};
|
||||
|
||||
const sourceCode1 = `\
|
||||
const columns = [{
|
||||
dataField: 'id',
|
||||
text: 'Product ID'
|
||||
}, {
|
||||
dataField: 'name',
|
||||
text: 'Product Name'
|
||||
}, {
|
||||
dataField: 'price',
|
||||
text: 'Product Price'
|
||||
}];
|
||||
|
||||
const selectRow = {
|
||||
mode: 'checkbox',
|
||||
classes: 'selection-row'
|
||||
};
|
||||
|
||||
<BootstrapTable
|
||||
keyField='id'
|
||||
data={ products }
|
||||
columns={ columns }
|
||||
selectRow={ selectRow }
|
||||
/>
|
||||
`;
|
||||
|
||||
const sourceCode2 = `\
|
||||
const columns = [{
|
||||
dataField: 'id',
|
||||
text: 'Product ID'
|
||||
}, {
|
||||
dataField: 'name',
|
||||
text: 'Product Name'
|
||||
}, {
|
||||
dataField: 'price',
|
||||
text: 'Product Price'
|
||||
}];
|
||||
|
||||
const selectRow = {
|
||||
mode: 'checkbox',
|
||||
classes: (row, rowIndex) =>
|
||||
(rowIndex > 1 ? 'row-index-bigger-than-2101' : 'row-index-small-than-2101')
|
||||
};
|
||||
|
||||
<BootstrapTable
|
||||
keyField='id'
|
||||
data={ products }
|
||||
columns={ columns }
|
||||
selectRow={ selectRow }
|
||||
/>
|
||||
`;
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<BootstrapTable keyField="id" data={ products } columns={ columns } selectRow={ selectRow1 } />
|
||||
<Code>{ sourceCode1 }</Code>
|
||||
<BootstrapTable keyField="id" data={ products } columns={ columns } selectRow={ selectRow2 } />
|
||||
<Code>{ sourceCode2 }</Code>
|
||||
</div>
|
||||
);
|
||||
94
packages/react-bootstrap-table2-example/examples/row-selection/selection-style.js
vendored
Normal file
94
packages/react-bootstrap-table2-example/examples/row-selection/selection-style.js
vendored
Normal file
@ -0,0 +1,94 @@
|
||||
/* eslint no-unused-vars: 0 */
|
||||
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 selectRow1 = {
|
||||
mode: 'checkbox',
|
||||
style: { backgroundColor: '#c8e6c9' }
|
||||
};
|
||||
|
||||
const selectRow2 = {
|
||||
mode: 'checkbox',
|
||||
style: (row, rowIndex) => {
|
||||
const backgroundColor = rowIndex > 1 ? '#00BFFF' : '#00FFFF';
|
||||
return { backgroundColor };
|
||||
}
|
||||
};
|
||||
|
||||
const sourceCode1 = `\
|
||||
const columns = [{
|
||||
dataField: 'id',
|
||||
text: 'Product ID'
|
||||
}, {
|
||||
dataField: 'name',
|
||||
text: 'Product Name'
|
||||
}, {
|
||||
dataField: 'price',
|
||||
text: 'Product Price'
|
||||
}];
|
||||
|
||||
const selectRow = {
|
||||
mode: 'checkbox',
|
||||
style: { backgroundColor: '#c8e6c9' }
|
||||
};
|
||||
|
||||
<BootstrapTable
|
||||
keyField='id'
|
||||
data={ products }
|
||||
columns={ columns }
|
||||
selectRow={ selectRow }
|
||||
/>
|
||||
`;
|
||||
|
||||
const sourceCode2 = `\
|
||||
const columns = [{
|
||||
dataField: 'id',
|
||||
text: 'Product ID'
|
||||
}, {
|
||||
dataField: 'name',
|
||||
text: 'Product Name'
|
||||
}, {
|
||||
dataField: 'price',
|
||||
text: 'Product Price'
|
||||
}];
|
||||
|
||||
const selectRow = {
|
||||
mode: 'checkbox',
|
||||
style: (row, rowIndex) => {
|
||||
const backgroundColor = rowIndex > 1 ? '#00BFFF' : '#00FFFF';
|
||||
return { backgroundColor };
|
||||
}
|
||||
};
|
||||
|
||||
<BootstrapTable
|
||||
keyField='id'
|
||||
data={ products }
|
||||
columns={ columns }
|
||||
selectRow={ selectRow }
|
||||
/>
|
||||
`;
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<BootstrapTable keyField="id" data={ products } columns={ columns } selectRow={ selectRow1 } />
|
||||
<Code>{ sourceCode1 }</Code>
|
||||
<BootstrapTable keyField="id" data={ products } columns={ columns } selectRow={ selectRow2 } />
|
||||
<Code>{ sourceCode2 }</Code>
|
||||
</div>
|
||||
);
|
||||
@ -53,6 +53,8 @@ import CellEditWithRedux from 'examples/cell-edit/cell-edit-with-redux-table';
|
||||
// work on row selection
|
||||
import SingleSelectionTable from 'examples/row-selection/single-selection';
|
||||
import MultipleSelectionTable from 'examples/row-selection/multiple-selection';
|
||||
import SelectionStyleTable from 'examples/row-selection/selection-style';
|
||||
import SelectionClassTable from 'examples/row-selection/selection-class';
|
||||
|
||||
// css style
|
||||
import 'bootstrap/dist/css/bootstrap.min.css';
|
||||
@ -113,6 +115,8 @@ storiesOf('Cell Editing', module)
|
||||
.add('Async Cell Editing(Redux)', () => <CellEditWithRedux />);
|
||||
|
||||
storiesOf('Row Selection', module)
|
||||
.add('Single selection', () => <SingleSelectionTable />)
|
||||
.add('Multiple selection', () => <MultipleSelectionTable />);
|
||||
.add('Single Selection', () => <SingleSelectionTable />)
|
||||
.add('Multiple Selection', () => <MultipleSelectionTable />)
|
||||
.add('Selection Style', () => <SelectionStyleTable />)
|
||||
.add('Selection Class', () => <SelectionClassTable />);
|
||||
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
.selection-row {
|
||||
background-color: #c8e6c9;
|
||||
}
|
||||
|
||||
.row-index-bigger-than-2101 {
|
||||
background-color: #00BFFF;
|
||||
}
|
||||
|
||||
.row-index-small-than-2101 {
|
||||
background-color: #00FFFF;
|
||||
}
|
||||
@ -5,4 +5,5 @@
|
||||
|
||||
@import "welcome/index";
|
||||
@import "columns/index";
|
||||
@import "cell-edit/index";
|
||||
@import "cell-edit/index";
|
||||
@import "row-selection/index";
|
||||
14
packages/react-bootstrap-table2/src/body.js
vendored
14
packages/react-bootstrap-table2/src/body.js
vendored
@ -22,6 +22,11 @@ const Body = (props) => {
|
||||
selectedRowKeys
|
||||
} = props;
|
||||
|
||||
const {
|
||||
style: selectedStyle,
|
||||
classes: selectedClasses
|
||||
} = selectRow;
|
||||
|
||||
let content;
|
||||
|
||||
if (isEmpty) {
|
||||
@ -37,6 +42,13 @@ const Body = (props) => {
|
||||
? selectedRowKeys.includes(key)
|
||||
: null;
|
||||
|
||||
let style = {};
|
||||
let classes = '';
|
||||
if (selected) {
|
||||
style = _.isFunction(selectedStyle) ? selectedStyle(row, index) : selectedStyle;
|
||||
classes = _.isFunction(selectedClasses) ? selectedClasses(row, index) : selectedClasses;
|
||||
}
|
||||
|
||||
return (
|
||||
<Row
|
||||
key={ key }
|
||||
@ -48,6 +60,8 @@ const Body = (props) => {
|
||||
editable={ editable }
|
||||
selected={ selected }
|
||||
selectRow={ selectRow }
|
||||
style={ style }
|
||||
className={ classes }
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
@ -127,7 +127,9 @@ BootstrapTable.propTypes = {
|
||||
editing: PropTypes.bool
|
||||
}),
|
||||
selectRow: PropTypes.shape({
|
||||
mode: PropTypes.oneOf([Const.ROW_SELECT_SINGLE, Const.ROW_SELECT_MULTIPLE]).isRequired
|
||||
mode: PropTypes.oneOf([Const.ROW_SELECT_SINGLE, Const.ROW_SELECT_MULTIPLE]).isRequired,
|
||||
style: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
|
||||
classes: PropTypes.oneOfType([PropTypes.string, PropTypes.func])
|
||||
}),
|
||||
onRowSelect: PropTypes.func,
|
||||
onAllRowsSelect: PropTypes.func
|
||||
|
||||
28
packages/react-bootstrap-table2/src/row.js
vendored
28
packages/react-bootstrap-table2/src/row.js
vendored
@ -9,13 +9,13 @@ import EditingCell from './cell-edit/editing-cell';
|
||||
import Const from './const';
|
||||
|
||||
const Row = (props) => {
|
||||
const { ROW_SELECT_DISABLED } = Const;
|
||||
|
||||
const {
|
||||
row,
|
||||
columns,
|
||||
keyField,
|
||||
rowIndex,
|
||||
className,
|
||||
style,
|
||||
cellEdit,
|
||||
selected,
|
||||
selectRow,
|
||||
@ -31,9 +31,9 @@ const Row = (props) => {
|
||||
} = cellEdit;
|
||||
|
||||
return (
|
||||
<tr>
|
||||
<tr style={ style } className={ className }>
|
||||
{
|
||||
selectRow.mode === ROW_SELECT_DISABLED
|
||||
selectRow.mode === Const.ROW_SELECT_DISABLED
|
||||
? null
|
||||
: (
|
||||
<SelectionCell
|
||||
@ -53,21 +53,21 @@ const Row = (props) => {
|
||||
editable = column.editable(content, row, rowIndex, index);
|
||||
}
|
||||
if (rowIndex === editingRowIdx && index === editingColIdx) {
|
||||
let style = column.editCellStyle || {};
|
||||
let classes = column.editCellClasses;
|
||||
let editCellstyle = column.editCellStyle || {};
|
||||
let editCellclasses = column.editCellClasses;
|
||||
if (_.isFunction(column.editCellStyle)) {
|
||||
style = column.editCellStyle(content, row, rowIndex, index);
|
||||
editCellstyle = column.editCellStyle(content, row, rowIndex, index);
|
||||
}
|
||||
if (_.isFunction(column.editCellClasses)) {
|
||||
classes = column.editCellClasses(content, row, rowIndex, index);
|
||||
editCellclasses = column.editCellClasses(content, row, rowIndex, index);
|
||||
}
|
||||
return (
|
||||
<EditingCell
|
||||
key={ content }
|
||||
row={ row }
|
||||
column={ column }
|
||||
className={ classes }
|
||||
style={ style }
|
||||
className={ editCellclasses }
|
||||
style={ editCellstyle }
|
||||
{ ...rest }
|
||||
/>
|
||||
);
|
||||
@ -93,11 +93,15 @@ const Row = (props) => {
|
||||
Row.propTypes = {
|
||||
row: PropTypes.object.isRequired,
|
||||
rowIndex: PropTypes.number.isRequired,
|
||||
columns: PropTypes.array.isRequired
|
||||
columns: PropTypes.array.isRequired,
|
||||
style: PropTypes.object,
|
||||
className: PropTypes.string
|
||||
};
|
||||
|
||||
Row.defaultProps = {
|
||||
editable: true
|
||||
editable: true,
|
||||
style: {},
|
||||
className: null
|
||||
};
|
||||
|
||||
export default Row;
|
||||
|
||||
@ -152,35 +152,128 @@ 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];
|
||||
|
||||
it('props selected should be true if all rows were selected', () => {
|
||||
beforeEach(() => {
|
||||
wrapper = shallow(
|
||||
<Body
|
||||
{ ...mockBodyResolvedProps }
|
||||
data={ data }
|
||||
columns={ columns }
|
||||
keyField={ keyField }
|
||||
selectedRowKeys={ [1, 2] }
|
||||
selectedRowKeys={ selectedRowKeys }
|
||||
selectRow={ selectRow }
|
||||
/>
|
||||
);
|
||||
|
||||
expect(wrapper.find(Row).get(0).props.selected).toBe(true);
|
||||
});
|
||||
|
||||
it('props selected should be false if all rows were not selected', () => {
|
||||
wrapper = shallow(
|
||||
<Body
|
||||
{ ...mockBodyResolvedProps }
|
||||
data={ data }
|
||||
columns={ columns }
|
||||
keyField={ keyField }
|
||||
selectedRowKeys={ [] }
|
||||
selectRow={ selectRow }
|
||||
/>
|
||||
);
|
||||
it('should render Row component with correct selected prop', () => {
|
||||
const rows = wrapper.find(Row);
|
||||
for (let i = 0; i < rows.length; i += 1) {
|
||||
const row = rows.get(i);
|
||||
expect(row.props.selected).toBe(selectedRowKeys.indexOf(row.props.row[keyField]) > -1);
|
||||
}
|
||||
});
|
||||
|
||||
expect(wrapper.find(Row).get(0).props.selected).toBe(false);
|
||||
describe('if selectRow.style is defined as an object', () => {
|
||||
const style = { backgroundColor: 'red' };
|
||||
|
||||
beforeEach(() => {
|
||||
selectRow.style = style;
|
||||
wrapper = shallow(
|
||||
<Body
|
||||
{ ...mockBodyResolvedProps }
|
||||
data={ data }
|
||||
columns={ columns }
|
||||
keyField={ keyField }
|
||||
selectedRowKeys={ selectedRowKeys }
|
||||
selectRow={ selectRow }
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
it('should render Row component with correct style prop', () => {
|
||||
expect(wrapper.find(Row).get(0).props.style).toBe(style);
|
||||
});
|
||||
});
|
||||
|
||||
describe('if selectRow.style is defined as a function', () => {
|
||||
const style = { backgroundColor: 'red' };
|
||||
const styleCallBack = sinon.stub().returns(style);
|
||||
|
||||
beforeEach(() => {
|
||||
selectRow.style = styleCallBack;
|
||||
wrapper = shallow(
|
||||
<Body
|
||||
{ ...mockBodyResolvedProps }
|
||||
data={ data }
|
||||
columns={ columns }
|
||||
keyField={ keyField }
|
||||
selectedRowKeys={ selectedRowKeys }
|
||||
selectRow={ selectRow }
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
it('should calling style callback correctly', () => {
|
||||
expect(styleCallBack.callCount).toBe(1);
|
||||
expect(styleCallBack.calledWith(data[0]), 1);
|
||||
});
|
||||
|
||||
it('should render Row component with correct style prop', () => {
|
||||
expect(wrapper.find(Row).get(0).props.style).toBe(style);
|
||||
});
|
||||
});
|
||||
|
||||
describe('if selectRow.classes is defined as a string', () => {
|
||||
const className = 'custom-class';
|
||||
|
||||
beforeEach(() => {
|
||||
selectRow.classes = className;
|
||||
wrapper = shallow(
|
||||
<Body
|
||||
{ ...mockBodyResolvedProps }
|
||||
data={ data }
|
||||
columns={ columns }
|
||||
keyField={ keyField }
|
||||
selectedRowKeys={ selectedRowKeys }
|
||||
selectRow={ selectRow }
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
it('should render Row component with correct className prop', () => {
|
||||
expect(wrapper.find(Row).get(0).props.className).toEqual(className);
|
||||
});
|
||||
});
|
||||
|
||||
describe('if selectRow.classes is defined as a function', () => {
|
||||
const className = 'custom-class';
|
||||
const classesCallBack = sinon.stub().returns(className);
|
||||
|
||||
beforeEach(() => {
|
||||
selectRow.classes = classesCallBack;
|
||||
wrapper = shallow(
|
||||
<Body
|
||||
{ ...mockBodyResolvedProps }
|
||||
data={ data }
|
||||
columns={ columns }
|
||||
keyField={ keyField }
|
||||
selectedRowKeys={ selectedRowKeys }
|
||||
selectRow={ selectRow }
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
it('should calling style callback correctly', () => {
|
||||
expect(classesCallBack.callCount).toBe(1);
|
||||
expect(classesCallBack.calledWith(data[0]), 1);
|
||||
});
|
||||
|
||||
it('should render Row component with correct style prop', () => {
|
||||
expect(wrapper.find(Row).get(0).props.className).toEqual(className);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -42,6 +42,44 @@ describe('Row', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('when style prop is defined', () => {
|
||||
const customStyle = { backgroundColor: 'red' };
|
||||
beforeEach(() => {
|
||||
wrapper = shallow(
|
||||
<Row
|
||||
{ ...mockBodyResolvedProps }
|
||||
rowIndex={ 1 }
|
||||
columns={ defaultColumns }
|
||||
row={ row }
|
||||
style={ customStyle }
|
||||
/>);
|
||||
});
|
||||
|
||||
it('should render component with style successfully', () => {
|
||||
expect(wrapper.length).toBe(1);
|
||||
expect(wrapper.prop('style')).toEqual(customStyle);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when className prop is defined', () => {
|
||||
const className = 'test-class';
|
||||
beforeEach(() => {
|
||||
wrapper = shallow(
|
||||
<Row
|
||||
{ ...mockBodyResolvedProps }
|
||||
rowIndex={ 1 }
|
||||
columns={ defaultColumns }
|
||||
row={ row }
|
||||
className={ className }
|
||||
/>);
|
||||
});
|
||||
|
||||
it('should render component with style successfully', () => {
|
||||
expect(wrapper.length).toBe(1);
|
||||
expect(wrapper.hasClass(className)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when cellEdit prop is defined', () => {
|
||||
let columns;
|
||||
let cellEdit;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user