Compare commits

..

8 Commits

Author SHA1 Message Date
AllenFang
6cac7f6dc8 Publish
- react-bootstrap-table2-example@1.0.19
 - react-bootstrap-table2-filter@1.1.5
 - react-bootstrap-table2-toolkit@1.3.1
 - react-bootstrap-table-next@3.0.0
2019-02-24 17:01:52 +08:00
Allen
da5b93c3cf Merge pull request #818 from react-bootstrap-table/develop
20190224 release
2019-02-24 16:59:43 +08:00
AllenFang
3ffccce1fe fix #817 2019-02-24 16:20:44 +08:00
AllenFang
09f21e8130 allow to custom className on clear search and export csv button 2019-02-24 16:11:38 +08:00
AllenFang
bf0c5c43a2 fix #735 2019-02-24 15:50:13 +08:00
AllenFang
c01f45a719 fix #789 2019-02-24 14:56:27 +08:00
AllenFang
d26c13b9be fix #815 2019-02-24 14:11:05 +08:00
AllenFang
8e940112f5 fix #811 2019-02-23 16:13:40 +08:00
15 changed files with 205 additions and 56 deletions

View File

@@ -0,0 +1,90 @@
/* eslint react/prop-types: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import ToolkitProvider, { Search, CSVExport } from 'react-bootstrap-table2-toolkit';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const { SearchBar, ClearSearchButton } = Search;
const { ExportCSVButton } = CSVExport;
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import ToolkitProvider, { Search, CSVExport } from 'react-bootstrap-table2-toolkit';
const { SearchBar, ClearSearchButton } = Search;
const { ExportCSVButton } = CSVExport;
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
<ToolkitProvider
keyField="id"
data={ products }
columns={ columns }
search
>
{
props => (
<div>
<h3>Input something at below input field:</h3>
<SearchBar { ...props.searchProps } />
<ClearSearchButton { ...props.searchProps } />
<hr />
<BootstrapTable
{ ...props.baseProps }
/>
<ExportCSVButton { ...props.csvProps }>Export CSV!!</ExportCSVButton>
</div>
)
}
</ToolkitProvider>
`;
export default () => (
<div>
<ToolkitProvider
keyField="id"
data={ products }
columns={ columns }
search
>
{
props => (
<div>
<h3>Input something at below input field:</h3>
<SearchBar { ...props.searchProps } />
<ClearSearchButton { ...props.searchProps } />
<hr />
<BootstrapTable
{ ...props.baseProps }
/>
<ExportCSVButton { ...props.csvProps }>Export CSV!!</ExportCSVButton>
</div>
)
}
</ToolkitProvider>
<Code>{ sourceCode }</Code>
</div>
);

View File

@@ -18,6 +18,11 @@ class QualityRanger extends React.Component {
static defaultProps = { static defaultProps = {
value: 0 value: 0
} }
componentDidMount() {
this.range.focus();
}
getValue() { getValue() {
return parseInt(this.range.value, 10); return parseInt(this.range.value, 10);
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "react-bootstrap-table2-example", "name": "react-bootstrap-table2-example",
"version": "1.0.18", "version": "1.0.19",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"private": true, "private": true,

View File

@@ -21,6 +21,7 @@ import Bootstrap4DefaultSortTable from 'examples/bootstrap4/sort';
import Bootstrap4RowSelectionTable from 'examples/bootstrap4/row-selection'; import Bootstrap4RowSelectionTable from 'examples/bootstrap4/row-selection';
import Bootstrap4PaginationTable from 'examples/bootstrap4/pagination'; import Bootstrap4PaginationTable from 'examples/bootstrap4/pagination';
import Bootstrap4ColumnToggleTable from 'examples/bootstrap4/column-toggle'; import Bootstrap4ColumnToggleTable from 'examples/bootstrap4/column-toggle';
import ToolkitsTable from 'examples/bootstrap4/toolkits';
// work on columns // work on columns
import NestedDataTable from 'examples/columns/nested-data-table'; import NestedDataTable from 'examples/columns/nested-data-table';
@@ -249,7 +250,8 @@ storiesOf('Bootstrap 4', module)
.add('Sort table with bootstrap 4', () => <Bootstrap4DefaultSortTable />) .add('Sort table with bootstrap 4', () => <Bootstrap4DefaultSortTable />)
.add('Row selection table with bootstrap 4', () => <Bootstrap4RowSelectionTable />) .add('Row selection table with bootstrap 4', () => <Bootstrap4RowSelectionTable />)
.add('Pagination table with bootstrap 4', () => <Bootstrap4PaginationTable />) .add('Pagination table with bootstrap 4', () => <Bootstrap4PaginationTable />)
.add('Column Toggle with bootstrap 4', () => <Bootstrap4ColumnToggleTable />); .add('Column Toggle with bootstrap 4', () => <Bootstrap4ColumnToggleTable />)
.add('toolkits Table bootstrap 4', () => <ToolkitsTable />);
storiesOf('Work on Columns', module) storiesOf('Work on Columns', module)
.addDecorator(bootstrapStyle()) .addDecorator(bootstrapStyle())

View File

@@ -1,6 +1,6 @@
{ {
"name": "react-bootstrap-table2-filter", "name": "react-bootstrap-table2-filter",
"version": "1.1.4", "version": "1.1.5",
"description": "it's a column filter addon for react-bootstrap-table2", "description": "it's a column filter addon for react-bootstrap-table2",
"main": "./lib/index.js", "main": "./lib/index.js",
"repository": { "repository": {

View File

@@ -40,7 +40,7 @@ export default (
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
let nextData = nextProps.data; let nextData = nextProps.data;
if (!isRemoteFiltering() && !_.isEqual(nextProps.data, this.props.data)) { if (!isRemoteFiltering() && !_.isEqual(nextProps.data, this.state.data)) {
nextData = this.doFilter(nextProps); nextData = this.doFilter(nextProps);
} }
this.setState({ this.setState({

View File

@@ -1,6 +1,6 @@
{ {
"name": "react-bootstrap-table2-toolkit", "name": "react-bootstrap-table2-toolkit",
"version": "1.3.0", "version": "1.3.1",
"description": "The toolkit for react-bootstrap-table2", "description": "The toolkit for react-bootstrap-table2",
"main": "./lib/index.js", "main": "./lib/index.js",
"repository": { "repository": {

View File

@@ -5,12 +5,14 @@ const ExportCSVButton = (props) => {
const { const {
onExport, onExport,
children, children,
className,
...rest ...rest
} = props; } = props;
return ( return (
<button <button
type="button" type="button"
className={ `react-bs-table-csv-btn btn btn-default ${className}` }
onClick={ () => onExport() } onClick={ () => onExport() }
{ ...rest } { ...rest }
> >
@@ -26,7 +28,7 @@ ExportCSVButton.propTypes = {
style: PropTypes.object style: PropTypes.object
}; };
ExportCSVButton.defaultProps = { ExportCSVButton.defaultProps = {
className: 'react-bs-table-csv-btn btn btn-default', className: '',
style: {} style: {}
}; };

View File

@@ -3,18 +3,21 @@ import PropTypes from 'prop-types';
const ClearButton = ({ const ClearButton = ({
onClear, onClear,
text text,
className
}) => ( }) => (
<button className="btn btn-default" onClick={ onClear }>{ text }</button> <button className={ `btn btn-default ${className}` } onClick={ onClear }>{ text }</button>
); );
ClearButton.propTypes = { ClearButton.propTypes = {
onClear: PropTypes.func.isRequired, onClear: PropTypes.func.isRequired,
className: PropTypes.string,
text: PropTypes.string text: PropTypes.string
}; };
ClearButton.defaultProps = { ClearButton.defaultProps = {
text: 'Clear' text: 'Clear',
className: ''
}; };
export default ClearButton; export default ClearButton;

View File

@@ -1,6 +1,6 @@
{ {
"name": "react-bootstrap-table-next", "name": "react-bootstrap-table-next",
"version": "2.2.0", "version": "3.0.0",
"description": "Next generation of react-bootstrap-table", "description": "Next generation of react-bootstrap-table",
"main": "./lib/index.js", "main": "./lib/index.js",
"repository": { "repository": {

View File

@@ -23,7 +23,10 @@ class Cell extends eventDelegater(Component) {
if (shouldUpdate) return true; if (shouldUpdate) return true;
// if (nextProps.formatter)
shouldUpdate = shouldUpdate =
nextProps.column.formatter ? !_.isEqual(this.props.row, nextProps.row) : false ||
this.props.column.hidden !== nextProps.column.hidden || this.props.column.hidden !== nextProps.column.hidden ||
this.props.rowIndex !== nextProps.rowIndex || this.props.rowIndex !== nextProps.rowIndex ||
this.props.columnIndex !== nextProps.columnIndex || this.props.columnIndex !== nextProps.columnIndex ||

View File

@@ -294,6 +294,7 @@ const withContext = Base =>
return rootProps => ( return rootProps => (
<this.CellEditContext.Provider <this.CellEditContext.Provider
{ ...baseProps } { ...baseProps }
ref={ n => this.cellEditContext = n }
selectRow={ this.props.selectRow } selectRow={ this.props.selectRow }
cellEdit={ this.props.cellEdit } cellEdit={ this.props.cellEdit }
data={ rootProps.getData() } data={ rootProps.getData() }

View File

@@ -14,26 +14,27 @@ class SelectionProvider extends React.Component {
keyField: PropTypes.string.isRequired keyField: PropTypes.string.isRequired
} }
state = { selected: this.props.selectRow.selected || [] }; constructor(props) {
super(props);
this.selected = props.selectRow.selected || [];
}
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
if (nextProps.selectRow) { if (nextProps.selectRow) {
this.setState(() => ({ this.selected = nextProps.selectRow.selected || this.selected;
selected: nextProps.selectRow.selected || this.state.selected
}));
} }
} }
// exposed API // exposed API
getSelected() { getSelected() {
return this.state.selected; return this.selected;
} }
handleRowSelect = (rowKey, checked, rowIndex, e) => { handleRowSelect = (rowKey, checked, rowIndex, e) => {
const { data, keyField, selectRow: { mode, onSelect } } = this.props; const { data, keyField, selectRow: { mode, onSelect } } = this.props;
const { ROW_SELECT_SINGLE } = Const; const { ROW_SELECT_SINGLE } = Const;
let currSelected = [...this.state.selected]; let currSelected = [...this.selected];
let result = true; let result = true;
if (onSelect) { if (onSelect) {
@@ -41,7 +42,6 @@ class SelectionProvider extends React.Component {
result = onSelect(row, checked, rowIndex, e); result = onSelect(row, checked, rowIndex, e);
} }
this.setState(() => {
if (result === true || result === undefined) { if (result === true || result === undefined) {
if (mode === ROW_SELECT_SINGLE) { // when select mode is radio if (mode === ROW_SELECT_SINGLE) { // when select mode is radio
currSelected = [rowKey]; currSelected = [rowKey];
@@ -51,8 +51,8 @@ class SelectionProvider extends React.Component {
currSelected = currSelected.filter(value => value !== rowKey); currSelected = currSelected.filter(value => value !== rowKey);
} }
} }
return { selected: currSelected }; this.selected = currSelected;
}); this.forceUpdate();
} }
handleAllRowsSelect = (e, isUnSelect) => { handleAllRowsSelect = (e, isUnSelect) => {
@@ -64,7 +64,7 @@ class SelectionProvider extends React.Component {
nonSelectable nonSelectable
} }
} = this.props; } = this.props;
const { selected } = this.state; const { selected } = this;
let currSelected; let currSelected;
@@ -81,7 +81,7 @@ class SelectionProvider extends React.Component {
dataOperator.getSelectedRows( dataOperator.getSelectedRows(
data, data,
keyField, keyField,
isUnSelect ? this.state.selected : currSelected isUnSelect ? selected : currSelected
), ),
e e
); );
@@ -89,7 +89,8 @@ class SelectionProvider extends React.Component {
currSelected = result; currSelected = result;
} }
} }
this.setState(() => ({ selected: currSelected })); this.selected = currSelected;
this.forceUpdate();
} }
render() { render() {
@@ -99,7 +100,7 @@ class SelectionProvider extends React.Component {
} = getSelectionSummary( } = getSelectionSummary(
this.props.data, this.props.data,
this.props.keyField, this.props.keyField,
this.state.selected this.selected
); );
let checkedStatus; let checkedStatus;
@@ -113,7 +114,7 @@ class SelectionProvider extends React.Component {
<SelectionContext.Provider <SelectionContext.Provider
value={ { value={ {
...this.props.selectRow, ...this.props.selectRow,
selected: this.state.selected, selected: this.selected,
onRowSelect: this.handleRowSelect, onRowSelect: this.handleRowSelect,
onAllRowsSelect: this.handleAllRowsSelect, onAllRowsSelect: this.handleAllRowsSelect,
allRowsSelected, allRowsSelected,

View File

@@ -218,6 +218,47 @@ describe('Cell', () => {
}); });
}); });
describe('when props.row is change', () => {
describe('and column.formatter is enable', () => {
const column = { dataField: 'name', text: 'Product Name', formatter: () => 123 };
beforeEach(() => {
props = {
row,
columnIndex: 1,
rowIndex: 1,
tabIndex: 5,
column
};
wrapper = shallow(
<Cell { ...props } />);
});
it('should return true', () => {
nextProps = { ...props, row: { ...row, alert: 'test' } };
expect(wrapper.instance().shouldComponentUpdate(nextProps)).toBe(true);
});
});
describe('but column.formatter is disable', () => {
const column = { dataField: 'name', text: 'Product Name' };
beforeEach(() => {
props = {
row,
columnIndex: 1,
rowIndex: 1,
tabIndex: 5,
column
};
wrapper = shallow(
<Cell { ...props } />);
});
it('should return true', () => {
nextProps = { ...props, row: { ...row, alert: 'test' } };
expect(wrapper.instance().shouldComponentUpdate(nextProps)).toBe(false);
});
});
});
describe('if column.isDummyField is true', () => { describe('if column.isDummyField is true', () => {
describe('when content is change', () => { describe('when content is change', () => {
const column = { dataField: '', text: 'Product Name', isDummyField: true }; const column = { dataField: '', text: 'Product Name', isDummyField: true };

View File

@@ -73,15 +73,15 @@ describe('DataContext', () => {
expect(SelectionContext.Consumer).toBeDefined(); expect(SelectionContext.Consumer).toBeDefined();
}); });
it('should have correct state.data', () => { it('should have correct this.selected', () => {
expect(wrapper.state().selected).toEqual([]); expect(wrapper.instance().selected).toEqual([]);
}); });
it('should pass correct sort props to children element', () => { it('should pass correct sort props to children element', () => {
expect(wrapper.length).toBe(1); expect(wrapper.length).toBe(1);
expect(mockBase).toHaveBeenCalledWith({ expect(mockBase).toHaveBeenCalledWith({
...defaultSelectRow, ...defaultSelectRow,
selected: wrapper.state().selected, selected: wrapper.instance().selected,
onRowSelect: wrapper.instance().handleRowSelect, onRowSelect: wrapper.instance().handleRowSelect,
onAllRowsSelect: wrapper.instance().handleAllRowsSelect, onAllRowsSelect: wrapper.instance().handleAllRowsSelect,
allRowsNotSelected: true, allRowsNotSelected: true,
@@ -104,8 +104,8 @@ describe('DataContext', () => {
}); });
}); });
it('should have correct state.selected', () => { it('should have correct this.selected', () => {
expect(wrapper.state().selected).toEqual(newSelectRow.selected); expect(wrapper.instance().selected).toEqual(newSelectRow.selected);
}); });
describe('if nextProps.selectRow is not existing', () => { describe('if nextProps.selectRow is not existing', () => {
@@ -120,8 +120,8 @@ describe('DataContext', () => {
}); });
}); });
it('should keep origin state.selected', () => { it('should keep origin this.selected', () => {
expect(wrapper.state().selected).toEqual(defaultSelected); expect(wrapper.instance().selected).toEqual(defaultSelected);
}); });
}); });
@@ -131,8 +131,8 @@ describe('DataContext', () => {
wrapper.instance().componentWillReceiveProps({}); wrapper.instance().componentWillReceiveProps({});
}); });
it('should not set state.selected', () => { it('should not set this.selected', () => {
expect(wrapper.state().selected).toEqual([]); expect(wrapper.instance().selected).toEqual([]);
}); });
}); });
}); });
@@ -148,8 +148,8 @@ describe('DataContext', () => {
wrapper = shallow(shallowContext(selectRow)); wrapper = shallow(shallowContext(selectRow));
}); });
it('should have correct state.data', () => { it('should have correct this.selected', () => {
expect(wrapper.state().selected).toEqual(selectRow.selected); expect(wrapper.instance().selected).toEqual(selectRow.selected);
}); });
}); });
@@ -164,12 +164,12 @@ describe('DataContext', () => {
wrapper = shallow(shallowContext(selectRow)); wrapper = shallow(shallowContext(selectRow));
}); });
it('should set state.selected correctly', () => { it('should set this.selected correctly', () => {
wrapper.instance().handleRowSelect(firstSelectedRow, true, rowIndex); wrapper.instance().handleRowSelect(firstSelectedRow, true, rowIndex);
expect(wrapper.state('selected')).toEqual([firstSelectedRow]); expect(wrapper.instance().selected).toEqual([firstSelectedRow]);
wrapper.instance().handleRowSelect(secondSelectedRow, true, rowIndex); wrapper.instance().handleRowSelect(secondSelectedRow, true, rowIndex);
expect(wrapper.state('selected')).toEqual([secondSelectedRow]); expect(wrapper.instance().selected).toEqual([secondSelectedRow]);
}); });
}); });
@@ -178,18 +178,19 @@ describe('DataContext', () => {
wrapper = shallow(shallowContext()); wrapper = shallow(shallowContext());
}); });
it('should set state.selected correctly', () => { it('should set this.selected correctly', () => {
wrapper.instance().handleRowSelect(firstSelectedRow, true, rowIndex); wrapper.instance().handleRowSelect(firstSelectedRow, true, rowIndex);
expect(wrapper.state('selected')).toEqual(expect.arrayContaining([firstSelectedRow])); expect(wrapper.instance().selected).toEqual(expect.arrayContaining([firstSelectedRow]));
wrapper.instance().handleRowSelect(secondSelectedRow, true, rowIndex); wrapper.instance().handleRowSelect(secondSelectedRow, true, rowIndex);
expect(wrapper.state('selected')).toEqual(expect.arrayContaining([firstSelectedRow, secondSelectedRow])); expect(wrapper.instance().selected)
.toEqual(expect.arrayContaining([firstSelectedRow, secondSelectedRow]));
wrapper.instance().handleRowSelect(firstSelectedRow, false, rowIndex); wrapper.instance().handleRowSelect(firstSelectedRow, false, rowIndex);
expect(wrapper.state('selected')).toEqual(expect.arrayContaining([secondSelectedRow])); expect(wrapper.instance().selected).toEqual(expect.arrayContaining([secondSelectedRow]));
wrapper.instance().handleRowSelect(secondSelectedRow, false, rowIndex); wrapper.instance().handleRowSelect(secondSelectedRow, false, rowIndex);
expect(wrapper.state('selected')).toEqual([]); expect(wrapper.instance().selected).toEqual([]);
}); });
}); });
@@ -220,8 +221,8 @@ describe('DataContext', () => {
wrapper.instance().handleAllRowsSelect(e, false); wrapper.instance().handleAllRowsSelect(e, false);
}); });
it('should set state.selected correctly', () => { it('should set this.selected correctly', () => {
expect(wrapper.state('selected')).toEqual(data.map(d => d[keyField])); expect(wrapper.instance().selected).toEqual(data.map(d => d[keyField]));
}); });
describe('when selectRow.onSelectAll is defined', () => { describe('when selectRow.onSelectAll is defined', () => {
@@ -237,7 +238,7 @@ describe('DataContext', () => {
it('should call selectRow.onSelectAll correctly', () => { it('should call selectRow.onSelectAll correctly', () => {
expect(onSelectAll).toHaveBeenCalledWith( expect(onSelectAll).toHaveBeenCalledWith(
true, true,
dataOperator.getSelectedRows(data, keyField, wrapper.state('selected')), dataOperator.getSelectedRows(data, keyField, wrapper.instance().selected),
e e
); );
}); });
@@ -253,8 +254,8 @@ describe('DataContext', () => {
wrapper.instance().handleAllRowsSelect(e, true); wrapper.instance().handleAllRowsSelect(e, true);
}); });
it('should set state.selected correctly', () => { it('should set this.selected correctly', () => {
expect(wrapper.state('selected')).toEqual([]); expect(wrapper.instance().selected).toEqual([]);
}); });
describe('when selectRow.onSelectAll is defined', () => { describe('when selectRow.onSelectAll is defined', () => {