From e31b5eb691ecbc2265d7e37fc582ce77998684b8 Mon Sep 17 00:00:00 2001 From: Bill Parrott Date: Mon, 3 Jun 2019 09:26:15 -0500 Subject: [PATCH 1/7] set tabindex to 0 for table headers; fixes #955 --- packages/react-bootstrap-table2/src/header-cell.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-bootstrap-table2/src/header-cell.js b/packages/react-bootstrap-table2/src/header-cell.js index 773a939..708800b 100644 --- a/packages/react-bootstrap-table2/src/header-cell.js +++ b/packages/react-bootstrap-table2/src/header-cell.js @@ -41,7 +41,7 @@ const HeaderCell = (props) => { const cellAttrs = { ..._.isFunction(headerAttrs) ? headerAttrs(column, index) : headerAttrs, ...headerEvents, - tabIndex: index + 1 + tabIndex: 0 }; let sortSymbol; From 7c8bf00cdeb44490de7b4dd0ef9c0ed553e6edd7 Mon Sep 17 00:00:00 2001 From: Bill Parrott Date: Wed, 28 Aug 2019 15:32:22 -0500 Subject: [PATCH 2/7] execute react-codemod on entire codebase to remove warnings on React 16.9.x --- packages/react-bootstrap-table2-editor/src/context.js | 4 +++- .../react-bootstrap-table2-editor/src/editing-cell.js | 7 ++++--- .../react-bootstrap-table2-editor/test/context.test.js | 8 ++++---- .../react-bootstrap-table2-filter/src/components/text.js | 3 ++- packages/react-bootstrap-table2-filter/src/context.js | 3 ++- .../test/components/text.test.js | 2 +- .../react-bootstrap-table2-paginator/src/data-context.js | 5 +++-- .../src/pagination-handler.js | 7 ++++--- .../react-bootstrap-table2-paginator/src/state-context.js | 3 ++- .../test/data-context.test.js | 4 ++-- .../test/pagination-handler.test.js | 8 ++++---- .../test/state-context.test.js | 4 ++-- .../src/search/SearchBar.js | 3 ++- .../react-bootstrap-table2-toolkit/src/search/context.js | 3 ++- packages/react-bootstrap-table2/src/bootstrap-table.js | 3 ++- .../react-bootstrap-table2/src/contexts/data-context.js | 3 ++- packages/react-bootstrap-table2/src/contexts/index.js | 7 ++++--- .../src/contexts/row-expand-context.js | 3 ++- .../src/contexts/selection-context.js | 3 ++- .../test/contexts/data-context.test.js | 2 +- .../test/contexts/selection-context.test.js | 6 +++--- 21 files changed, 53 insertions(+), 38 deletions(-) diff --git a/packages/react-bootstrap-table2-editor/src/context.js b/packages/react-bootstrap-table2-editor/src/context.js index ea3c1f0..7394070 100644 --- a/packages/react-bootstrap-table2-editor/src/context.js +++ b/packages/react-bootstrap-table2-editor/src/context.js @@ -16,6 +16,7 @@ export default ( static propTypes = { data: PropTypes.array.isRequired, selectRow: PropTypes.object, + // eslint-disable-next-line react/no-unused-prop-types options: PropTypes.shape({ mode: PropTypes.oneOf([CLICK_TO_CELL_EDIT, DBCLICK_TO_CELL_EDIT]).isRequired, onErrorMessageDisappear: PropTypes.func, @@ -43,7 +44,8 @@ export default ( }; } - componentWillReceiveProps(nextProps) { + // eslint-disable-next-line camelcase, react/sort-comp + UNSAFE_componentWillReceiveProps(nextProps) { if (nextProps.cellEdit && isRemoteCellEdit()) { if (nextProps.cellEdit.options.errorMessage) { this.setState(() => ({ diff --git a/packages/react-bootstrap-table2-editor/src/editing-cell.js b/packages/react-bootstrap-table2-editor/src/editing-cell.js index 2a0d85b..0fdfac3 100644 --- a/packages/react-bootstrap-table2-editor/src/editing-cell.js +++ b/packages/react-bootstrap-table2-editor/src/editing-cell.js @@ -15,7 +15,7 @@ import EditorIndicator from './editor-indicator'; import { TIME_TO_CLOSE_MESSAGE, EDITTYPE } from './const'; export default (_, onStartEdit) => - class EditingCell extends Component { + (class EditingCell extends Component { static propTypes = { row: PropTypes.object.isRequired, rowIndex: PropTypes.number.isRequired, @@ -51,7 +51,8 @@ export default (_, onStartEdit) => }; } - componentWillReceiveProps({ message }) { + // eslint-disable-next-line camelcase, react/sort-comp + UNSAFE_componentWillReceiveProps({ message }) { if (_.isDefined(message)) { this.createTimer(); this.setState(() => ({ @@ -223,4 +224,4 @@ export default (_, onStartEdit) => ); } - }; + }); diff --git a/packages/react-bootstrap-table2-editor/test/context.test.js b/packages/react-bootstrap-table2-editor/test/context.test.js index 57b56bf..65e9d2c 100644 --- a/packages/react-bootstrap-table2-editor/test/context.test.js +++ b/packages/react-bootstrap-table2-editor/test/context.test.js @@ -117,7 +117,7 @@ describe('CellEditContext', () => { wrapper = shallow(shallowContext()); wrapper.setState(initialState); wrapper.render(); - wrapper.instance().componentWillReceiveProps({}); + wrapper.instance().UNSAFE_componentWillReceiveProps({}); }); it('should not set state.message', () => { @@ -138,7 +138,7 @@ describe('CellEditContext', () => { wrapper = shallow(shallowContext()); wrapper.setState(initialState); wrapper.render(); - wrapper.instance().componentWillReceiveProps({ + wrapper.instance().UNSAFE_componentWillReceiveProps({ cellEdit: cellEditFactory(defaultCellEdit) }); }); @@ -164,7 +164,7 @@ describe('CellEditContext', () => { wrapper = shallow(shallowContext(defaultCellEdit, true)); wrapper.setState(initialState); wrapper.render(); - wrapper.instance().componentWillReceiveProps({ + wrapper.instance().UNSAFE_componentWillReceiveProps({ cellEdit: cellEditFactory({ ...defaultCellEdit, errorMessage: message @@ -190,7 +190,7 @@ describe('CellEditContext', () => { beforeEach(() => { wrapper = shallow(shallowContext(defaultCellEdit, true)); wrapper.setState(initialState); - wrapper.instance().componentWillReceiveProps({ + wrapper.instance().UNSAFE_componentWillReceiveProps({ cellEdit: cellEditFactory({ ...defaultCellEdit }) }); wrapper.update(); diff --git a/packages/react-bootstrap-table2-filter/src/components/text.js b/packages/react-bootstrap-table2-filter/src/components/text.js index a359a95..5bbf401 100644 --- a/packages/react-bootstrap-table2-filter/src/components/text.js +++ b/packages/react-bootstrap-table2-filter/src/components/text.js @@ -41,7 +41,8 @@ class TextFilter extends Component { } } - componentWillReceiveProps(nextProps) { + // eslint-disable-next-line camelcase, react/sort-comp + UNSAFE_componentWillReceiveProps(nextProps) { if (nextProps.defaultValue !== this.props.defaultValue) { this.applyFilter(nextProps.defaultValue); } diff --git a/packages/react-bootstrap-table2-filter/src/context.js b/packages/react-bootstrap-table2-filter/src/context.js index 013be6e..44824ee 100644 --- a/packages/react-bootstrap-table2-filter/src/context.js +++ b/packages/react-bootstrap-table2-filter/src/context.js @@ -37,7 +37,8 @@ export default ( } } - componentWillReceiveProps(nextProps) { + // eslint-disable-next-line camelcase, react/sort-comp + UNSAFE_componentWillReceiveProps(nextProps) { // let nextData = nextProps.data; if (!isRemoteFiltering() && !_.isEqual(nextProps.data, this.data)) { this.doFilter(nextProps, this.isEmitDataChange); diff --git a/packages/react-bootstrap-table2-filter/test/components/text.test.js b/packages/react-bootstrap-table2-filter/test/components/text.test.js index fbc849f..fbb2200 100644 --- a/packages/react-bootstrap-table2-filter/test/components/text.test.js +++ b/packages/react-bootstrap-table2-filter/test/components/text.test.js @@ -144,7 +144,7 @@ describe('Text Filter', () => { ); instance = wrapper.instance(); - instance.componentWillReceiveProps(nextProps); + instance.UNSAFE_componentWillReceiveProps(nextProps); }); it('should setting state correctly when props.defaultValue is changed', () => { diff --git a/packages/react-bootstrap-table2-paginator/src/data-context.js b/packages/react-bootstrap-table2-paginator/src/data-context.js index 654e9f8..153884c 100644 --- a/packages/react-bootstrap-table2-paginator/src/data-context.js +++ b/packages/react-bootstrap-table2-paginator/src/data-context.js @@ -21,8 +21,9 @@ class PaginationDataProvider extends Provider { isRemotePagination: PropTypes.func.isRequired } - componentWillReceiveProps(nextProps) { - super.componentWillReceiveProps(nextProps); + // eslint-disable-next-line camelcase, react/sort-comp + UNSAFE_componentWillReceiveProps(nextProps) { + super.UNSAFE_componentWillReceiveProps(nextProps); const { currSizePerPage } = this; const { custom, onPageChange } = nextProps.pagination.options; diff --git a/packages/react-bootstrap-table2-paginator/src/pagination-handler.js b/packages/react-bootstrap-table2-paginator/src/pagination-handler.js index fcc9e11..00e67df 100644 --- a/packages/react-bootstrap-table2-paginator/src/pagination-handler.js +++ b/packages/react-bootstrap-table2-paginator/src/pagination-handler.js @@ -4,7 +4,7 @@ import React, { Component } from 'react'; import pageResolver from './page-resolver'; export default WrappedComponent => - class PaginationHandler extends pageResolver(Component) { + (class PaginationHandler extends pageResolver(Component) { constructor(props) { super(props); this.handleChangePage = this.handleChangePage.bind(this); @@ -12,7 +12,8 @@ export default WrappedComponent => this.state = this.initialState(); } - componentWillReceiveProps(nextProps) { + // eslint-disable-next-line camelcase, react/sort-comp + UNSAFE_componentWillReceiveProps(nextProps) { const { dataSize, currSizePerPage } = nextProps; if (currSizePerPage !== this.props.currSizePerPage || dataSize !== this.props.dataSize) { const totalPages = this.calculateTotalPage(currSizePerPage, dataSize); @@ -73,5 +74,5 @@ export default WrappedComponent => /> ); } - }; + }); diff --git a/packages/react-bootstrap-table2-paginator/src/state-context.js b/packages/react-bootstrap-table2-paginator/src/state-context.js index 3f616cb..df52fad 100644 --- a/packages/react-bootstrap-table2-paginator/src/state-context.js +++ b/packages/react-bootstrap-table2-paginator/src/state-context.js @@ -45,7 +45,8 @@ class StateProvider extends React.Component { this.dataChangeListener.on('filterChanged', this.handleDataSizeChange); } - componentWillReceiveProps(nextProps) { + // eslint-disable-next-line camelcase, react/sort-comp + UNSAFE_componentWillReceiveProps(nextProps) { const { custom } = nextProps.pagination.options; // user should align the page when the page is not fit to the data size when remote enable diff --git a/packages/react-bootstrap-table2-paginator/test/data-context.test.js b/packages/react-bootstrap-table2-paginator/test/data-context.test.js index ba920cc..48dd1aa 100644 --- a/packages/react-bootstrap-table2-paginator/test/data-context.test.js +++ b/packages/react-bootstrap-table2-paginator/test/data-context.test.js @@ -174,7 +174,7 @@ describe('PaginationDataContext', () => { data: [], pagination: { ...defaultPagination } }; - instance.componentWillReceiveProps(nextProps); + instance.UNSAFE_componentWillReceiveProps(nextProps); }); it('should reset currPage to first page', () => { @@ -195,7 +195,7 @@ describe('PaginationDataContext', () => { data: [], pagination: { ...defaultPagination, options: { onPageChange } } }; - instance.componentWillReceiveProps(nextProps); + instance.UNSAFE_componentWillReceiveProps(nextProps); }); it('should call options.onPageChange correctly', () => { diff --git a/packages/react-bootstrap-table2-paginator/test/pagination-handler.test.js b/packages/react-bootstrap-table2-paginator/test/pagination-handler.test.js index 4c295a1..b9216d1 100644 --- a/packages/react-bootstrap-table2-paginator/test/pagination-handler.test.js +++ b/packages/react-bootstrap-table2-paginator/test/pagination-handler.test.js @@ -164,13 +164,13 @@ describe('paginationHandler', () => { }); it('should setting correct state.totalPages', () => { - instance.componentWillReceiveProps(nextProps); + instance.UNSAFE_componentWillReceiveProps(nextProps); expect(instance.state.totalPages).toEqual( instance.calculateTotalPage(nextProps.currSizePerPage)); }); it('should setting correct state.lastPage', () => { - instance.componentWillReceiveProps(nextProps); + instance.UNSAFE_componentWillReceiveProps(nextProps); const totalPages = instance.calculateTotalPage(nextProps.currSizePerPage); expect(instance.state.lastPage).toEqual( instance.calculateLastPage(totalPages)); @@ -186,13 +186,13 @@ describe('paginationHandler', () => { }); it('should setting correct state.totalPages', () => { - instance.componentWillReceiveProps(nextProps); + instance.UNSAFE_componentWillReceiveProps(nextProps); expect(instance.state.totalPages).toEqual( instance.calculateTotalPage(nextProps.currSizePerPage, nextProps.dataSize)); }); it('should setting correct state.lastPage', () => { - instance.componentWillReceiveProps(nextProps); + instance.UNSAFE_componentWillReceiveProps(nextProps); const totalPages = instance.calculateTotalPage( nextProps.currSizePerPage, nextProps.dataSize); expect(instance.state.lastPage).toEqual( diff --git a/packages/react-bootstrap-table2-paginator/test/state-context.test.js b/packages/react-bootstrap-table2-paginator/test/state-context.test.js index bc4a91c..c17630e 100644 --- a/packages/react-bootstrap-table2-paginator/test/state-context.test.js +++ b/packages/react-bootstrap-table2-paginator/test/state-context.test.js @@ -156,7 +156,7 @@ describe('PaginationStateContext', () => { data, pagination: { ...defaultPagination, options: { page: 3, sizePerPage: 5, totalSize: 50 } } }; - instance.componentWillReceiveProps(nextProps); + instance.UNSAFE_componentWillReceiveProps(nextProps); }); it('should always reset currPage and currSizePerPage', () => { @@ -181,7 +181,7 @@ describe('PaginationStateContext', () => { options: { page: 3, sizePerPage: 5, custom: true, totalSize: 50 } } }; - instance.componentWillReceiveProps(nextProps); + instance.UNSAFE_componentWillReceiveProps(nextProps); }); it('should always reset currPage and currSizePerPage', () => { diff --git a/packages/react-bootstrap-table2-toolkit/src/search/SearchBar.js b/packages/react-bootstrap-table2-toolkit/src/search/SearchBar.js index 70909e0..fba26dc 100644 --- a/packages/react-bootstrap-table2-toolkit/src/search/SearchBar.js +++ b/packages/react-bootstrap-table2-toolkit/src/search/SearchBar.js @@ -34,7 +34,8 @@ class SearchBar extends React.Component { }; } - componentWillReceiveProps(nextProps) { + // eslint-disable-next-line camelcase, react/sort-comp + UNSAFE_componentWillReceiveProps(nextProps) { this.setState({ value: nextProps.searchText }); } diff --git a/packages/react-bootstrap-table2-toolkit/src/search/context.js b/packages/react-bootstrap-table2-toolkit/src/search/context.js index bfed70d..fd7474e 100644 --- a/packages/react-bootstrap-table2-toolkit/src/search/context.js +++ b/packages/react-bootstrap-table2-toolkit/src/search/context.js @@ -35,7 +35,8 @@ export default (options = { this.state = { data: initialData }; } - componentWillReceiveProps(nextProps) { + // eslint-disable-next-line camelcase, react/sort-comp + UNSAFE_componentWillReceiveProps(nextProps) { if (nextProps.searchText !== this.props.searchText) { if (isRemoteSearch()) { handleRemoteSearchChange(nextProps.searchText); diff --git a/packages/react-bootstrap-table2/src/bootstrap-table.js b/packages/react-bootstrap-table2/src/bootstrap-table.js index 692c29f..f2e490a 100644 --- a/packages/react-bootstrap-table2/src/bootstrap-table.js +++ b/packages/react-bootstrap-table2/src/bootstrap-table.js @@ -18,7 +18,8 @@ class BootstrapTable extends PropsBaseResolver(Component) { this.validateProps(); } - componentWillReceiveProps(nextProps) { + // eslint-disable-next-line camelcase, react/sort-comp + UNSAFE_componentWillReceiveProps(nextProps) { if (nextProps.onDataSizeChange && !nextProps.pagination) { if (nextProps.data.length !== this.props.data.length) { nextProps.onDataSizeChange({ dataSize: nextProps.data.length }); diff --git a/packages/react-bootstrap-table2/src/contexts/data-context.js b/packages/react-bootstrap-table2/src/contexts/data-context.js index 3394c7a..ca01393 100644 --- a/packages/react-bootstrap-table2/src/contexts/data-context.js +++ b/packages/react-bootstrap-table2/src/contexts/data-context.js @@ -12,7 +12,8 @@ export default () => { state = { data: this.props.data }; - componentWillReceiveProps(nextProps) { + // eslint-disable-next-line camelcase, react/sort-comp + UNSAFE_componentWillReceiveProps(nextProps) { this.setState(() => ({ data: nextProps.data })); } diff --git a/packages/react-bootstrap-table2/src/contexts/index.js b/packages/react-bootstrap-table2/src/contexts/index.js index 1793dfb..109c675 100644 --- a/packages/react-bootstrap-table2/src/contexts/index.js +++ b/packages/react-bootstrap-table2/src/contexts/index.js @@ -14,7 +14,7 @@ import { BootstrapContext } from './bootstrap'; import dataOperator from '../store/operators'; const withContext = Base => - class BootstrapTableContainer extends remoteResolver(Component) { + (class BootstrapTableContainer extends remoteResolver(Component) { constructor(props) { super(props); this.DataContext = createDataContext(); @@ -83,7 +83,8 @@ const withContext = Base => } } - componentWillReceiveProps(nextProps) { + // eslint-disable-next-line camelcase, react/sort-comp + UNSAFE_componentWillReceiveProps(nextProps) { if (!nextProps.pagination && this.props.pagination) { this.PaginationContext = null; } @@ -374,6 +375,6 @@ const withContext = Base => ); } - }; + }); export default withContext; diff --git a/packages/react-bootstrap-table2/src/contexts/row-expand-context.js b/packages/react-bootstrap-table2/src/contexts/row-expand-context.js index e1c5e47..46273c7 100644 --- a/packages/react-bootstrap-table2/src/contexts/row-expand-context.js +++ b/packages/react-bootstrap-table2/src/contexts/row-expand-context.js @@ -16,7 +16,8 @@ class RowExpandProvider extends React.Component { state = { expanded: this.props.expandRow.expanded || [], isClosing: this.props.expandRow.isClosing || [] }; - componentWillReceiveProps(nextProps) { + // eslint-disable-next-line camelcase, react/sort-comp + UNSAFE_componentWillReceiveProps(nextProps) { if (nextProps.expandRow) { const nextExpanded = nextProps.expandRow.expanded || this.state.expanded; const isClosing = this.state.expanded.reduce((acc, cur) => { diff --git a/packages/react-bootstrap-table2/src/contexts/selection-context.js b/packages/react-bootstrap-table2/src/contexts/selection-context.js index 573c54f..a973536 100644 --- a/packages/react-bootstrap-table2/src/contexts/selection-context.js +++ b/packages/react-bootstrap-table2/src/contexts/selection-context.js @@ -19,7 +19,8 @@ class SelectionProvider extends React.Component { this.selected = props.selectRow.selected || []; } - componentWillReceiveProps(nextProps) { + // eslint-disable-next-line camelcase, react/sort-comp + UNSAFE_componentWillReceiveProps(nextProps) { if (nextProps.selectRow) { this.selected = nextProps.selectRow.selected || this.selected; } diff --git a/packages/react-bootstrap-table2/test/contexts/data-context.test.js b/packages/react-bootstrap-table2/test/contexts/data-context.test.js index 0761640..7e6dab3 100644 --- a/packages/react-bootstrap-table2/test/contexts/data-context.test.js +++ b/packages/react-bootstrap-table2/test/contexts/data-context.test.js @@ -81,7 +81,7 @@ describe('DataContext', () => { beforeEach(() => { wrapper = shallow(shallowContext()); - wrapper.instance().componentWillReceiveProps({ + wrapper.instance().UNSAFE_componentWillReceiveProps({ data: newData }); }); diff --git a/packages/react-bootstrap-table2/test/contexts/selection-context.test.js b/packages/react-bootstrap-table2/test/contexts/selection-context.test.js index 1196088..107c4fc 100644 --- a/packages/react-bootstrap-table2/test/contexts/selection-context.test.js +++ b/packages/react-bootstrap-table2/test/contexts/selection-context.test.js @@ -99,7 +99,7 @@ describe('DataContext', () => { beforeEach(() => { wrapper = shallow(shallowContext()); - wrapper.instance().componentWillReceiveProps({ + wrapper.instance().UNSAFE_componentWillReceiveProps({ selectRow: newSelectRow }); }); @@ -115,7 +115,7 @@ describe('DataContext', () => { ...defaultSelectRow, selected: defaultSelected })); - wrapper.instance().componentWillReceiveProps({ + wrapper.instance().UNSAFE_componentWillReceiveProps({ selectRow: defaultSelectRow }); }); @@ -128,7 +128,7 @@ describe('DataContext', () => { describe('if nextProps.selectRow is not existing', () => { beforeEach(() => { wrapper = shallow(shallowContext()); - wrapper.instance().componentWillReceiveProps({}); + wrapper.instance().UNSAFE_componentWillReceiveProps({}); }); it('should not set this.selected', () => { From d9acbace67986e846e6666b010a6118f425a51c4 Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sat, 31 Aug 2019 14:18:55 +0800 Subject: [PATCH 3/7] refine #1073 --- .../src/context.js | 5 +-- .../src/editing-cell.js | 14 ++++---- .../src/components/text.js | 10 +++--- .../src/context.js | 20 +++++------ .../src/pagination-handler.js | 6 ++-- .../src/state-context.js | 36 +++++++++---------- .../src/search/SearchBar.js | 10 +++--- .../src/search/context.js | 22 ++++++------ .../src/bootstrap-table.js | 2 +- .../src/contexts/data-context.js | 10 +++--- .../src/contexts/index.js | 6 ++-- .../src/contexts/row-expand-context.js | 10 +++--- .../src/contexts/selection-context.js | 12 +++---- 13 files changed, 82 insertions(+), 81 deletions(-) diff --git a/packages/react-bootstrap-table2-editor/src/context.js b/packages/react-bootstrap-table2-editor/src/context.js index 7394070..30f5e6a 100644 --- a/packages/react-bootstrap-table2-editor/src/context.js +++ b/packages/react-bootstrap-table2-editor/src/context.js @@ -1,5 +1,8 @@ +/* eslint disable-next-line: 0 */ /* eslint react/prop-types: 0 */ /* eslint react/require-default-props: 0 */ +/* eslint camelcase: 0 */ +/* eslint react/no-unused-prop-types: 0 */ import React from 'react'; import PropTypes from 'prop-types'; import { CLICK_TO_CELL_EDIT, DBCLICK_TO_CELL_EDIT } from './const'; @@ -16,7 +19,6 @@ export default ( static propTypes = { data: PropTypes.array.isRequired, selectRow: PropTypes.object, - // eslint-disable-next-line react/no-unused-prop-types options: PropTypes.shape({ mode: PropTypes.oneOf([CLICK_TO_CELL_EDIT, DBCLICK_TO_CELL_EDIT]).isRequired, onErrorMessageDisappear: PropTypes.func, @@ -44,7 +46,6 @@ export default ( }; } - // eslint-disable-next-line camelcase, react/sort-comp UNSAFE_componentWillReceiveProps(nextProps) { if (nextProps.cellEdit && isRemoteCellEdit()) { if (nextProps.cellEdit.options.errorMessage) { diff --git a/packages/react-bootstrap-table2-editor/src/editing-cell.js b/packages/react-bootstrap-table2-editor/src/editing-cell.js index 0fdfac3..e729998 100644 --- a/packages/react-bootstrap-table2-editor/src/editing-cell.js +++ b/packages/react-bootstrap-table2-editor/src/editing-cell.js @@ -2,6 +2,7 @@ /* eslint no-return-assign: 0 */ /* eslint class-methods-use-this: 0 */ /* eslint jsx-a11y/no-noninteractive-element-interactions: 0 */ +/* eslint camelcase: 0 */ import React, { Component } from 'react'; import cs from 'classnames'; import PropTypes from 'prop-types'; @@ -15,7 +16,7 @@ import EditorIndicator from './editor-indicator'; import { TIME_TO_CLOSE_MESSAGE, EDITTYPE } from './const'; export default (_, onStartEdit) => - (class EditingCell extends Component { + class EditingCell extends Component { static propTypes = { row: PropTypes.object.isRequired, rowIndex: PropTypes.number.isRequired, @@ -51,7 +52,10 @@ export default (_, onStartEdit) => }; } - // eslint-disable-next-line camelcase, react/sort-comp + componentWillUnmount() { + this.clearTimer(); + } + UNSAFE_componentWillReceiveProps({ message }) { if (_.isDefined(message)) { this.createTimer(); @@ -61,10 +65,6 @@ export default (_, onStartEdit) => } } - componentWillUnmount() { - this.clearTimer(); - } - clearTimer() { if (this.indicatorTimer) { clearTimeout(this.indicatorTimer); @@ -224,4 +224,4 @@ export default (_, onStartEdit) => ); } - }); + }; diff --git a/packages/react-bootstrap-table2-filter/src/components/text.js b/packages/react-bootstrap-table2-filter/src/components/text.js index 5bbf401..b02e6d5 100644 --- a/packages/react-bootstrap-table2-filter/src/components/text.js +++ b/packages/react-bootstrap-table2-filter/src/components/text.js @@ -1,6 +1,7 @@ /* eslint react/require-default-props: 0 */ /* eslint react/prop-types: 0 */ /* eslint no-return-assign: 0 */ +/* eslint camelcase: 0 */ import React, { Component } from 'react'; import { PropTypes } from 'prop-types'; @@ -41,17 +42,16 @@ class TextFilter extends Component { } } - // eslint-disable-next-line camelcase, react/sort-comp + componentWillUnmount() { + this.cleanTimer(); + } + UNSAFE_componentWillReceiveProps(nextProps) { if (nextProps.defaultValue !== this.props.defaultValue) { this.applyFilter(nextProps.defaultValue); } } - componentWillUnmount() { - this.cleanTimer(); - } - filter(e) { e.stopPropagation(); this.cleanTimer(); diff --git a/packages/react-bootstrap-table2-filter/src/context.js b/packages/react-bootstrap-table2-filter/src/context.js index 44824ee..f9be85f 100644 --- a/packages/react-bootstrap-table2-filter/src/context.js +++ b/packages/react-bootstrap-table2-filter/src/context.js @@ -1,5 +1,6 @@ /* eslint react/prop-types: 0 */ /* eslint react/require-default-props: 0 */ +/* eslint camelcase: 0 */ import React from 'react'; import PropTypes from 'prop-types'; @@ -37,16 +38,6 @@ export default ( } } - // eslint-disable-next-line camelcase, react/sort-comp - UNSAFE_componentWillReceiveProps(nextProps) { - // let nextData = nextProps.data; - if (!isRemoteFiltering() && !_.isEqual(nextProps.data, this.data)) { - this.doFilter(nextProps, this.isEmitDataChange); - } else { - this.data = nextProps.data; - } - } - onFilter(column, filterType, initialize = false) { return (filterVal) => { // watch out here if migration to context API, #334 @@ -91,6 +82,15 @@ export default ( return this.data; } + UNSAFE_componentWillReceiveProps(nextProps) { + // let nextData = nextProps.data; + if (!isRemoteFiltering() && !_.isEqual(nextProps.data, this.data)) { + this.doFilter(nextProps, this.isEmitDataChange); + } else { + this.data = nextProps.data; + } + } + doFilter(props, ignoreEmitDataChange = false) { const { dataChangeListener, data, columns } = props; const result = filters(data, columns, _)(this.currFilters); diff --git a/packages/react-bootstrap-table2-paginator/src/pagination-handler.js b/packages/react-bootstrap-table2-paginator/src/pagination-handler.js index 00e67df..412258b 100644 --- a/packages/react-bootstrap-table2-paginator/src/pagination-handler.js +++ b/packages/react-bootstrap-table2-paginator/src/pagination-handler.js @@ -1,10 +1,11 @@ /* eslint react/prop-types: 0 */ +/* eslint camelcase: 0 */ import React, { Component } from 'react'; import pageResolver from './page-resolver'; export default WrappedComponent => - (class PaginationHandler extends pageResolver(Component) { + class PaginationHandler extends pageResolver(Component) { constructor(props) { super(props); this.handleChangePage = this.handleChangePage.bind(this); @@ -12,7 +13,6 @@ export default WrappedComponent => this.state = this.initialState(); } - // eslint-disable-next-line camelcase, react/sort-comp UNSAFE_componentWillReceiveProps(nextProps) { const { dataSize, currSizePerPage } = nextProps; if (currSizePerPage !== this.props.currSizePerPage || dataSize !== this.props.dataSize) { @@ -74,5 +74,5 @@ export default WrappedComponent => /> ); } - }); + }; diff --git a/packages/react-bootstrap-table2-paginator/src/state-context.js b/packages/react-bootstrap-table2-paginator/src/state-context.js index df52fad..b1079ef 100644 --- a/packages/react-bootstrap-table2-paginator/src/state-context.js +++ b/packages/react-bootstrap-table2-paginator/src/state-context.js @@ -1,6 +1,7 @@ /* eslint react/prop-types: 0 */ /* eslint react/require-default-props: 0 */ /* eslint no-lonely-if: 0 */ +/* eslint camelcase: 0 */ import React from 'react'; import EventEmitter from 'events'; import Const from './const'; @@ -45,24 +46,6 @@ class StateProvider extends React.Component { this.dataChangeListener.on('filterChanged', this.handleDataSizeChange); } - // eslint-disable-next-line camelcase, react/sort-comp - UNSAFE_componentWillReceiveProps(nextProps) { - const { custom } = nextProps.pagination.options; - - // user should align the page when the page is not fit to the data size when remote enable - if (this.isRemotePagination() || custom) { - if (typeof nextProps.pagination.options.page !== 'undefined') { - this.currPage = nextProps.pagination.options.page; - } - if (typeof nextProps.pagination.options.sizePerPage !== 'undefined') { - this.currSizePerPage = nextProps.pagination.options.sizePerPage; - } - if (typeof nextProps.pagination.options.totalSize !== 'undefined') { - this.dataSize = nextProps.pagination.options.totalSize; - } - } - } - getPaginationProps = () => { const { pagination: { options }, bootstrap4 } = this.props; const { currPage, currSizePerPage, dataSize } = this; @@ -114,6 +97,23 @@ class StateProvider extends React.Component { getPaginationRemoteEmitter = () => this.remoteEmitter || this.props.remoteEmitter; + UNSAFE_componentWillReceiveProps(nextProps) { + const { custom } = nextProps.pagination.options; + + // user should align the page when the page is not fit to the data size when remote enable + if (this.isRemotePagination() || custom) { + if (typeof nextProps.pagination.options.page !== 'undefined') { + this.currPage = nextProps.pagination.options.page; + } + if (typeof nextProps.pagination.options.sizePerPage !== 'undefined') { + this.currSizePerPage = nextProps.pagination.options.sizePerPage; + } + if (typeof nextProps.pagination.options.totalSize !== 'undefined') { + this.dataSize = nextProps.pagination.options.totalSize; + } + } + } + isRemotePagination = () => { const e = {}; this.remoteEmitter.emit('isRemotePagination', e); diff --git a/packages/react-bootstrap-table2-toolkit/src/search/SearchBar.js b/packages/react-bootstrap-table2-toolkit/src/search/SearchBar.js index fba26dc..9bef75f 100644 --- a/packages/react-bootstrap-table2-toolkit/src/search/SearchBar.js +++ b/packages/react-bootstrap-table2-toolkit/src/search/SearchBar.js @@ -1,3 +1,4 @@ +/* eslint camelcase: 0 */ /* eslint no-return-assign: 0 */ import React from 'react'; import PropTypes from 'prop-types'; @@ -34,11 +35,6 @@ class SearchBar extends React.Component { }; } - // eslint-disable-next-line camelcase, react/sort-comp - UNSAFE_componentWillReceiveProps(nextProps) { - this.setState({ value: nextProps.searchText }); - } - onChangeValue = (e) => { this.setState({ value: e.target.value }); } @@ -51,6 +47,10 @@ class SearchBar extends React.Component { debounceCallback(); } + UNSAFE_componentWillReceiveProps(nextProps) { + this.setState({ value: nextProps.searchText }); + } + render() { const { className, diff --git a/packages/react-bootstrap-table2-toolkit/src/search/context.js b/packages/react-bootstrap-table2-toolkit/src/search/context.js index fd7474e..50dafc4 100644 --- a/packages/react-bootstrap-table2-toolkit/src/search/context.js +++ b/packages/react-bootstrap-table2-toolkit/src/search/context.js @@ -3,6 +3,7 @@ /* eslint no-continue: 0 */ /* eslint no-lonely-if: 0 */ /* eslint class-methods-use-this: 0 */ +/* eslint camelcase: 0 */ import React from 'react'; import PropTypes from 'prop-types'; @@ -35,7 +36,16 @@ export default (options = { this.state = { data: initialData }; } - // eslint-disable-next-line camelcase, react/sort-comp + getSearched() { + return this.state.data; + } + + triggerListener(result) { + if (this.props.dataChangeListener) { + this.props.dataChangeListener.emit('filterChanged', result.length); + } + } + UNSAFE_componentWillReceiveProps(nextProps) { if (nextProps.searchText !== this.props.searchText) { if (isRemoteSearch()) { @@ -60,16 +70,6 @@ export default (options = { } } - getSearched() { - return this.state.data; - } - - triggerListener(result) { - if (this.props.dataChangeListener) { - this.props.dataChangeListener.emit('filterChanged', result.length); - } - } - search(props) { const { data, columns } = props; const searchText = props.searchText.toLowerCase(); diff --git a/packages/react-bootstrap-table2/src/bootstrap-table.js b/packages/react-bootstrap-table2/src/bootstrap-table.js index f2e490a..338a428 100644 --- a/packages/react-bootstrap-table2/src/bootstrap-table.js +++ b/packages/react-bootstrap-table2/src/bootstrap-table.js @@ -1,3 +1,4 @@ +/* eslint camelcase: 0 */ /* eslint arrow-body-style: 0 */ import React, { Component } from 'react'; @@ -18,7 +19,6 @@ class BootstrapTable extends PropsBaseResolver(Component) { this.validateProps(); } - // eslint-disable-next-line camelcase, react/sort-comp UNSAFE_componentWillReceiveProps(nextProps) { if (nextProps.onDataSizeChange && !nextProps.pagination) { if (nextProps.data.length !== this.props.data.length) { diff --git a/packages/react-bootstrap-table2/src/contexts/data-context.js b/packages/react-bootstrap-table2/src/contexts/data-context.js index ca01393..1e207d8 100644 --- a/packages/react-bootstrap-table2/src/contexts/data-context.js +++ b/packages/react-bootstrap-table2/src/contexts/data-context.js @@ -1,3 +1,4 @@ +/* eslint camelcase: 0 */ import React, { Component } from 'react'; import PropTypes from 'prop-types'; @@ -12,11 +13,6 @@ export default () => { state = { data: this.props.data }; - // eslint-disable-next-line camelcase, react/sort-comp - UNSAFE_componentWillReceiveProps(nextProps) { - this.setState(() => ({ data: nextProps.data })); - } - getData = (filterProps, searchProps, sortProps, paginationProps) => { if (paginationProps) return paginationProps.data; else if (sortProps) return sortProps.data; @@ -25,6 +21,10 @@ export default () => { return this.props.data; } + UNSAFE_componentWillReceiveProps(nextProps) { + this.setState(() => ({ data: nextProps.data })); + } + render() { return ( - (class BootstrapTableContainer extends remoteResolver(Component) { + class BootstrapTableContainer extends remoteResolver(Component) { constructor(props) { super(props); this.DataContext = createDataContext(); @@ -83,7 +84,6 @@ const withContext = Base => } } - // eslint-disable-next-line camelcase, react/sort-comp UNSAFE_componentWillReceiveProps(nextProps) { if (!nextProps.pagination && this.props.pagination) { this.PaginationContext = null; @@ -375,6 +375,6 @@ const withContext = Base => ); } - }); + }; export default withContext; diff --git a/packages/react-bootstrap-table2/src/contexts/row-expand-context.js b/packages/react-bootstrap-table2/src/contexts/row-expand-context.js index 46273c7..fb1aed0 100644 --- a/packages/react-bootstrap-table2/src/contexts/row-expand-context.js +++ b/packages/react-bootstrap-table2/src/contexts/row-expand-context.js @@ -1,3 +1,4 @@ +/* eslint camelcase: 0 */ /* eslint react/prop-types: 0 */ import React from 'react'; import PropTypes from 'prop-types'; @@ -16,7 +17,10 @@ class RowExpandProvider extends React.Component { state = { expanded: this.props.expandRow.expanded || [], isClosing: this.props.expandRow.isClosing || [] }; - // eslint-disable-next-line camelcase, react/sort-comp + onClosed = (closedRow) => { + this.setState({ isClosing: this.state.isClosing.filter(value => value !== closedRow) }); + }; + UNSAFE_componentWillReceiveProps(nextProps) { if (nextProps.expandRow) { const nextExpanded = nextProps.expandRow.expanded || this.state.expanded; @@ -37,10 +41,6 @@ class RowExpandProvider extends React.Component { } } - onClosed = (closedRow) => { - this.setState({ isClosing: this.state.isClosing.filter(value => value !== closedRow) }); - }; - handleRowExpand = (rowKey, expanded, rowIndex, e) => { const { data, keyField, expandRow: { onExpand, onlyOneExpanding, nonExpandable } } = this.props; if (nonExpandable && _.contains(nonExpandable, rowKey)) { diff --git a/packages/react-bootstrap-table2/src/contexts/selection-context.js b/packages/react-bootstrap-table2/src/contexts/selection-context.js index a973536..31a0e43 100644 --- a/packages/react-bootstrap-table2/src/contexts/selection-context.js +++ b/packages/react-bootstrap-table2/src/contexts/selection-context.js @@ -1,3 +1,4 @@ +/* eslint camelcase: 0 */ /* eslint react/prop-types: 0 */ import React from 'react'; import PropTypes from 'prop-types'; @@ -19,18 +20,17 @@ class SelectionProvider extends React.Component { this.selected = props.selectRow.selected || []; } - // eslint-disable-next-line camelcase, react/sort-comp + // exposed API + getSelected() { + return this.selected; + } + UNSAFE_componentWillReceiveProps(nextProps) { if (nextProps.selectRow) { this.selected = nextProps.selectRow.selected || this.selected; } } - // exposed API - getSelected() { - return this.selected; - } - handleRowSelect = (rowKey, checked, rowIndex, e) => { const { data, keyField, selectRow: { mode, onSelect } } = this.props; const { ROW_SELECT_SINGLE } = Const; From 00b1558df0710267b4c3cb2ce788ac647796d52e Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sat, 7 Sep 2019 14:44:18 +0800 Subject: [PATCH 4/7] fix #1078 --- .../examples/search/custom-match-function.js | 116 ++++++++++++++++++ .../stories/index.js | 4 +- .../react-bootstrap-table2-toolkit/README.md | 27 ++++ .../src/search/context.js | 20 ++- 4 files changed, 162 insertions(+), 5 deletions(-) create mode 100644 packages/react-bootstrap-table2-example/examples/search/custom-match-function.js diff --git a/packages/react-bootstrap-table2-example/examples/search/custom-match-function.js b/packages/react-bootstrap-table2-example/examples/search/custom-match-function.js new file mode 100644 index 0000000..afcccd1 --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/search/custom-match-function.js @@ -0,0 +1,116 @@ +/* eslint react/prop-types: 0 */ +/* eslint no-unused-vars: 0 */ +import React from 'react'; + +import BootstrapTable from 'react-bootstrap-table-next'; +import ToolkitProvider, { Search } from 'react-bootstrap-table2-toolkit'; +import Code from 'components/common/code-block'; +import { productsGenerator } from 'utils/common'; + +const { SearchBar } = Search; +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 } from 'react-bootstrap-table2-toolkit'; + +const { SearchBar } = Search; +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'price', + text: 'Product Price' +}]; + +// Implement startWith instead of contain +function customMatchFunc({ + searchText, + value, + column, + row +}) { + if (typeof value !== 'undefined') { + return value.startsWith(searchText); + } + return false; +} + +export default () => ( +
+ + { + props => ( +
+

Input something at below input field:

+ +
+ +
+ ) + } +
+ { sourceCode } +
+); +`; + +// Implement startWith instead of contain +function customMatchFunc({ + searchText, + value, + column, + row +}) { + if (typeof value !== 'undefined') { + return `${value}`.toLowerCase().startsWith(searchText.toLowerCase()); + } + return false; +} + +export default () => ( +
+

Custom a search match function by startWith instead of contain

+ + { + props => ( +
+

Input something at below input field:

+ +
+ +
+ ) + } +
+ { sourceCode } +
+); diff --git a/packages/react-bootstrap-table2-example/stories/index.js b/packages/react-bootstrap-table2-example/stories/index.js index 283278c..c58f70a 100644 --- a/packages/react-bootstrap-table2-example/stories/index.js +++ b/packages/react-bootstrap-table2-example/stories/index.js @@ -195,6 +195,7 @@ import FullyCustomSearch from 'examples/search/fully-custom-search'; import SearchFormattedData from 'examples/search/search-formatted'; import CustomSearchValue from 'examples/search/custom-search-value'; import SearchableColumn from 'examples/search/searchable-column'; +import CustomMatchFunction from 'examples/search/custom-match-function'; // CSV import ExportCSV from 'examples/csv'; @@ -451,7 +452,8 @@ storiesOf('Table Search', module) .add('Searchable Column', () => ) .add('Fully Custom Search', () => ) .add('Search Formatted Value', () => ) - .add('Custom Search Value', () => ); + .add('Custom Search Value', () => ) + .add('Custom match function', () => ); storiesOf('Column Toggle', module) .addDecorator(bootstrapStyle()) diff --git a/packages/react-bootstrap-table2-toolkit/README.md b/packages/react-bootstrap-table2-toolkit/README.md index 444d10e..c28a623 100644 --- a/packages/react-bootstrap-table2-toolkit/README.md +++ b/packages/react-bootstrap-table2-toolkit/README.md @@ -98,6 +98,33 @@ Accept a string that will be used for default searching when first time table re ``` +#### onColumnMatch - [function] +Acccpt a function which will be called when table try to match every cells when search happening. This function accept an object like below example: + +```js +function onColumnMatch({ + searchText, + value, + column, + row +}) { + // implement your custom match logic on every cell value +} + + + // ... + +``` + +> Notes: You have to return `true` when your match logic is positive and vice versa. + #### searchFormatted - [bool] If you want to search on the formatted data, you are supposed to enable this props. `react-bootstrap-table2` will check if you define the `column.formatter` when doing search. diff --git a/packages/react-bootstrap-table2-toolkit/src/search/context.js b/packages/react-bootstrap-table2-toolkit/src/search/context.js index 50dafc4..ec94da7 100644 --- a/packages/react-bootstrap-table2-toolkit/src/search/context.js +++ b/packages/react-bootstrap-table2-toolkit/src/search/context.js @@ -8,7 +8,8 @@ import React from 'react'; import PropTypes from 'prop-types'; export default (options = { - searchFormatted: false + searchFormatted: false, + onColumnMatch: null }) => ( _, isRemoteSearch, @@ -83,11 +84,22 @@ export default (options = { } else if (column.filterValue) { targetValue = column.filterValue(targetValue, row); } - if (targetValue !== null && typeof targetValue !== 'undefined') { - targetValue = targetValue.toString().toLowerCase(); - if (targetValue.indexOf(searchText) > -1) { + if (options.onColumnMatch) { + if (options.onColumnMatch({ + searchText, + value: targetValue, + column, + row + })) { return true; } + } else { + if (targetValue !== null && typeof targetValue !== 'undefined') { + targetValue = targetValue.toString().toLowerCase(); + if (targetValue.indexOf(searchText) > -1) { + return true; + } + } } } return false; From ec1f96cd1fbac3f08164f6dc922cb41272640e79 Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sat, 7 Sep 2019 15:56:13 +0800 Subject: [PATCH 5/7] fix #1082 --- docs/columns.md | 37 ++++++++- .../examples/sort/custom-sort-value.js | 78 +++++++++++++++++++ .../src/utils/common.js | 5 ++ .../stories/index.js | 2 + .../react-bootstrap-table2/src/store/sort.js | 11 ++- 5 files changed, 129 insertions(+), 4 deletions(-) create mode 100644 packages/react-bootstrap-table2-example/examples/sort/custom-sort-value.js diff --git a/docs/columns.md b/docs/columns.md index 525ec4d..723367b 100644 --- a/docs/columns.md +++ b/docs/columns.md @@ -13,6 +13,7 @@ Available properties in a column object: * [formatExtraData](#formatExtraData) * [type](#type) * [sort](#sort) +* [sortValue](#sortValue) * [sortFunc](#sortFunc) * [sortCaret](#sortCaret) * [onSort](#onSort) @@ -141,8 +142,42 @@ Specify the data type on column. Available value so far is `string`, `number`, ` ## column.sort - [Bool] Enable the column sort via a `true` value given. +## column.sortValue - [Function] +`column.sortValue` only work when `column.sort` enabled. This prop allow you to replace the value when table sorting. + +For example, consider following data: + +```js +const types = ['Cloud Service', 'Message Service', 'Add Service', 'Edit Service', 'Money']; +const data = [{id: 1, type: 2}, {id: 2, type: 1}, {id: 3, type:0}]; +const columns = [{ + dataField: 'id', + text: 'Job ID' +}, { + dataField: 'type', + text: 'Job Type' + sort: true, + formatter: (cell, row) => types[cell] +}] +``` + +In above case, when user try to sort Job Type column which will sort the original value: 0, 1, 2 but we display the type name via [`column.formatter`](#formatter), which will lead confuse because we are sorting by type value instead of type name. So `sortValue` is a way for you to decide what kind of value should be adopted when sorting on a specify column: + +```js +const columns = [{ + dataField: 'id', + text: 'Job ID' +}, { + dataField: 'type', + text: 'Job Type' + sort: true, + formatter: (cell, row) => types[cell], + sortValue: (cell, row) => types[cell] // we use type name to sort. +}] +``` + ## column.sortFunc - [Function] -`column.sortFunc` only work when `column.sort` is enable. `sortFunc` allow you to define your sorting algorithm. This callback function accept six arguments: +`column.sortFunc` only work when `column.sort` enabled. `sortFunc` allow you to define your sorting algorithm. This callback function accept six arguments: ```js { diff --git a/packages/react-bootstrap-table2-example/examples/sort/custom-sort-value.js b/packages/react-bootstrap-table2-example/examples/sort/custom-sort-value.js new file mode 100644 index 0000000..74e7f84 --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/sort/custom-sort-value.js @@ -0,0 +1,78 @@ +/* eslint no-unused-vars: 0 */ +import React from 'react'; + +import BootstrapTable from 'react-bootstrap-table-next'; +import Code from 'components/common/code-block'; +import { jobsGenerator1 } from 'utils/common'; + +const jobs = jobsGenerator1(8); + +const types = ['Cloud Service', 'Message Service', 'Add Service', 'Edit Service', 'Money']; + +const columns = [{ + dataField: 'id', + text: 'Job ID' +}, { + dataField: 'name', + text: 'Job Name' +}, { + dataField: 'owner', + text: 'Job Owner' +}, { + dataField: 'type', + text: 'Job Type', + sort: true, + formatter: (cell, row) => types[cell], + sortValue: (cell, row) => types[cell] +}]; + +const sourceCode = `\ +import BootstrapTable from 'react-bootstrap-table-next'; + +const types = ['Cloud Service', 'Message Service', 'Add Service', 'Edit Service', 'Money']; + +const columns = [{ + dataField: 'id', + text: 'Job ID' +}, { + dataField: 'name', + text: 'Job Name' +}, { + dataField: 'owner', + text: 'Job Owner' +}, { + dataField: 'type', + text: 'Job Type', + sort: true, + formatter: (cell, row) => types[cell], + sortValue: (cell, row) => types[cell] +}]; + + +`; + +export default class Test extends React.Component { + constructor(props) { + super(props); + this.state = { data: jobs }; + } + + handleClick = () => { + this.setState(() => { + const newProducts = jobsGenerator1(21); + return { + data: newProducts + }; + }); + } + + render() { + return ( +
+ + + { sourceCode } +
+ ); + } +} diff --git a/packages/react-bootstrap-table2-example/src/utils/common.js b/packages/react-bootstrap-table2-example/src/utils/common.js index f6baec2..5592779 100644 --- a/packages/react-bootstrap-table2-example/src/utils/common.js +++ b/packages/react-bootstrap-table2-example/src/utils/common.js @@ -29,6 +29,11 @@ export const withOnSale = rows => rows.map((row) => { return row; }); +export const withRandomPrice = rows => rows.map((row) => { + row.price = Math.floor((Math.random() * 10) + 2000); + return row; +}); + export const productsQualityGenerator = (quantity = 5, factor = 0) => Array.from({ length: quantity }, (value, index) => ({ id: index + factor, diff --git a/packages/react-bootstrap-table2-example/stories/index.js b/packages/react-bootstrap-table2-example/stories/index.js index c58f70a..5587d0b 100644 --- a/packages/react-bootstrap-table2-example/stories/index.js +++ b/packages/react-bootstrap-table2-example/stories/index.js @@ -104,6 +104,7 @@ import EnableSortTable from 'examples/sort/enable-sort-table'; import DefaultSortTable from 'examples/sort/default-sort-table'; import DefaultSortDirectionTable from 'examples/sort/default-sort-direction'; import SortEvents from 'examples/sort/sort-events'; +import CustomSortValue from 'examples/sort/custom-sort-value'; import CustomSortTable from 'examples/sort/custom-sort-table'; import CustomSortCaretTable from 'examples/sort/custom-sort-caret'; import HeaderSortingClassesTable from 'examples/sort/header-sorting-classes'; @@ -357,6 +358,7 @@ storiesOf('Sort Table', module) .add('Default Sort Table', () => ) .add('Default Sort Direction Table', () => ) .add('Sort Events', () => ) + .add('Custom Sort Value', () => ) .add('Custom Sort Fuction', () => ) .add('Custom Sort Caret', () => ) .add('Custom Classes on Sorting Header Column', () => ) diff --git a/packages/react-bootstrap-table2/src/store/sort.js b/packages/react-bootstrap-table2/src/store/sort.js index dd2fd21..1f349ac 100644 --- a/packages/react-bootstrap-table2/src/store/sort.js +++ b/packages/react-bootstrap-table2/src/store/sort.js @@ -14,14 +14,19 @@ function comparator(a, b) { return result; } -export const sort = (data, sortOrder, { dataField, sortFunc }) => { +export const sort = (data, sortOrder, { dataField, sortFunc, sortValue }) => { const _data = [...data]; _data.sort((a, b) => { let result; let valueA = _.get(a, dataField); let valueB = _.get(b, dataField); - valueA = _.isDefined(valueA) ? valueA : ''; - valueB = _.isDefined(valueB) ? valueB : ''; + if (sortValue) { + valueA = sortValue(valueA, a); + valueB = sortValue(valueB, b); + } else { + valueA = _.isDefined(valueA) ? valueA : ''; + valueB = _.isDefined(valueB) ? valueB : ''; + } if (sortFunc) { result = sortFunc(valueA, valueB, sortOrder, dataField, a, b); From 16128e77e61329d52f425ce0857731abdad3de28 Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sat, 7 Sep 2019 16:14:06 +0800 Subject: [PATCH 6/7] fix #1077 --- docs/columns.md | 2 +- .../header-columns/column-event-table.js | 4 +- .../src/cell-event-delegater.js | 4 +- .../react-bootstrap-table2/src/header-cell.js | 211 +++++++++--------- 4 files changed, 113 insertions(+), 108 deletions(-) diff --git a/docs/columns.md b/docs/columns.md index 723367b..8770eb6 100644 --- a/docs/columns.md +++ b/docs/columns.md @@ -456,7 +456,7 @@ If the events is not listed above, the callback function will only pass the `eve { // omit... headerEvents: { - onClick: e => { ... } + onClick: (e, column, columnIndex) => { ... } } } ``` diff --git a/packages/react-bootstrap-table2-example/examples/header-columns/column-event-table.js b/packages/react-bootstrap-table2-example/examples/header-columns/column-event-table.js index d4394a7..3312b39 100644 --- a/packages/react-bootstrap-table2-example/examples/header-columns/column-event-table.js +++ b/packages/react-bootstrap-table2-example/examples/header-columns/column-event-table.js @@ -12,7 +12,7 @@ const columns = [{ dataField: 'id', text: 'Product ID', headerEvents: { - onClick: () => alert('Click on Product ID header column') + onClick: (e, column, columnIndex) => alert(`Click on Product ID header column, columnIndex: ${columnIndex}`) } }, { dataField: 'name', @@ -29,7 +29,7 @@ const columns = [{ dataField: 'id', text: 'Product ID', headerEvents: { - onClick: () => alert('Click on Product ID header column') + onClick: (e, column, columnIndex) => alert('Click on Product ID header column') } }, { dataField: 'name', diff --git a/packages/react-bootstrap-table2/src/cell-event-delegater.js b/packages/react-bootstrap-table2/src/cell-event-delegater.js index 14c2fa0..689f2c1 100644 --- a/packages/react-bootstrap-table2/src/cell-event-delegater.js +++ b/packages/react-bootstrap-table2/src/cell-event-delegater.js @@ -17,8 +17,8 @@ export default ExtendBase => createDefaultEventHandler(cb) { return (e) => { - const { column, columnIndex } = this.props; - cb(e, column, columnIndex); + const { column, columnIndex, index } = this.props; + cb(e, column, typeof columnIndex !== 'undefined' ? columnIndex : index); }; } diff --git a/packages/react-bootstrap-table2/src/header-cell.js b/packages/react-bootstrap-table2/src/header-cell.js index f2b5106..22c3fca 100644 --- a/packages/react-bootstrap-table2/src/header-cell.js +++ b/packages/react-bootstrap-table2/src/header-cell.js @@ -7,119 +7,124 @@ import Const from './const'; import SortSymbol from './sort/symbol'; import SortCaret from './sort/caret'; import _ from './utils'; +import eventDelegater from './cell-event-delegater'; -const HeaderCell = (props) => { - const { - column, - index, - onSort, - sorting, - sortOrder, - isLastSorting, - onFilter, - currFilters, - onExternalFilter - } = props; +class HeaderCell extends eventDelegater(React.Component) { + render() { + const { + column, + index, + onSort, + sorting, + sortOrder, + isLastSorting, + onFilter, + currFilters, + onExternalFilter + } = this.props; - const { - text, - sort, - sortCaret, - filter, - filterRenderer, - headerTitle, - headerAlign, - headerFormatter, - headerEvents, - headerClasses, - headerStyle, - headerAttrs, - headerSortingClasses, - headerSortingStyle - } = column; + const { + text, + sort, + sortCaret, + filter, + filterRenderer, + headerTitle, + headerAlign, + headerFormatter, + headerEvents, + headerClasses, + headerStyle, + headerAttrs, + headerSortingClasses, + headerSortingStyle + } = column; - const cellAttrs = { - ..._.isFunction(headerAttrs) ? headerAttrs(column, index) : headerAttrs, - ...headerEvents, - tabIndex: 0 - }; + const delegateEvents = this.delegate(headerEvents); - let sortSymbol; - let filterElm; - let cellStyle = {}; - let cellClasses = _.isFunction(headerClasses) ? headerClasses(column, index) : headerClasses; - - if (headerStyle) { - cellStyle = _.isFunction(headerStyle) ? headerStyle(column, index) : headerStyle; - cellStyle = cellStyle ? { ...cellStyle } : cellStyle; - } - - if (headerTitle) { - cellAttrs.title = _.isFunction(headerTitle) ? headerTitle(column, index) : text; - } - - if (headerAlign) { - cellStyle.textAlign = _.isFunction(headerAlign) ? headerAlign(column, index) : headerAlign; - } - - if (sort) { - const customClick = cellAttrs.onClick; - cellAttrs.onClick = (e) => { - onSort(column); - if (_.isFunction(customClick)) customClick(e); + const cellAttrs = { + ..._.isFunction(headerAttrs) ? headerAttrs(column, index) : headerAttrs, + ...delegateEvents, + tabIndex: 0 }; - cellAttrs.className = cs(cellAttrs.className, 'sortable'); - if (sorting) { - sortSymbol = sortCaret ? sortCaret(sortOrder, column) : ; + let sortSymbol; + let filterElm; + let cellStyle = {}; + let cellClasses = _.isFunction(headerClasses) ? headerClasses(column, index) : headerClasses; - // append customized classes or style if table was sorting based on the current column. - cellClasses = cs( - cellClasses, - _.isFunction(headerSortingClasses) - ? headerSortingClasses(column, sortOrder, isLastSorting, index) - : headerSortingClasses - ); - - cellStyle = { - ...cellStyle, - ..._.isFunction(headerSortingStyle) - ? headerSortingStyle(column, sortOrder, isLastSorting, index) - : headerSortingStyle - }; - } else { - sortSymbol = sortCaret ? sortCaret(undefined, column) : ; + if (headerStyle) { + cellStyle = _.isFunction(headerStyle) ? headerStyle(column, index) : headerStyle; + cellStyle = cellStyle ? { ...cellStyle } : cellStyle; } + + if (headerTitle) { + cellAttrs.title = _.isFunction(headerTitle) ? headerTitle(column, index) : text; + } + + if (headerAlign) { + cellStyle.textAlign = _.isFunction(headerAlign) ? headerAlign(column, index) : headerAlign; + } + + if (sort) { + const customClick = cellAttrs.onClick; + cellAttrs.onClick = (e) => { + onSort(column); + if (_.isFunction(customClick)) customClick(e); + }; + cellAttrs.className = cs(cellAttrs.className, 'sortable'); + + if (sorting) { + sortSymbol = sortCaret ? sortCaret(sortOrder, column) : ; + + // append customized classes or style if table was sorting based on the current column. + cellClasses = cs( + cellClasses, + _.isFunction(headerSortingClasses) + ? headerSortingClasses(column, sortOrder, isLastSorting, index) + : headerSortingClasses + ); + + cellStyle = { + ...cellStyle, + ..._.isFunction(headerSortingStyle) + ? headerSortingStyle(column, sortOrder, isLastSorting, index) + : headerSortingStyle + }; + } else { + sortSymbol = sortCaret ? sortCaret(undefined, column) : ; + } + } + + if (cellClasses) cellAttrs.className = cs(cellAttrs.className, cellClasses); + if (!_.isEmptyObject(cellStyle)) cellAttrs.style = cellStyle; + + if (filterRenderer) { + const onCustomFilter = onExternalFilter(column, filter.props.type); + filterElm = filterRenderer(onCustomFilter, column); + } else if (filter) { + filterElm = ( + + ); + } + + const children = headerFormatter ? + headerFormatter(column, index, { sortElement: sortSymbol, filterElement: filterElm }) : + text; + + if (headerFormatter) { + return React.createElement('th', cellAttrs, children); + } + + return React.createElement('th', cellAttrs, children, sortSymbol, filterElm); } - - if (cellClasses) cellAttrs.className = cs(cellAttrs.className, cellClasses); - if (!_.isEmptyObject(cellStyle)) cellAttrs.style = cellStyle; - - if (filterRenderer) { - const onCustomFilter = onExternalFilter(column, filter.props.type); - filterElm = filterRenderer(onCustomFilter, column); - } else if (filter) { - filterElm = ( - - ); - } - - const children = headerFormatter ? - headerFormatter(column, index, { sortElement: sortSymbol, filterElement: filterElm }) : - text; - - if (headerFormatter) { - return React.createElement('th', cellAttrs, children); - } - - return React.createElement('th', cellAttrs, children, sortSymbol, filterElm); -}; +} HeaderCell.propTypes = { column: PropTypes.shape({ From 7d28d461859eb57944b99611fb8e9e4cc58d38bb Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sat, 7 Sep 2019 16:27:18 +0800 Subject: [PATCH 7/7] enhance footer event --- docs/columns.md | 2 +- .../examples/footer/column-event-table.js | 4 +- .../react-bootstrap-table2/src/footer-cell.js | 95 ++++++++++--------- 3 files changed, 53 insertions(+), 48 deletions(-) diff --git a/docs/columns.md b/docs/columns.md index 8770eb6..6d77335 100644 --- a/docs/columns.md +++ b/docs/columns.md @@ -666,7 +666,7 @@ It's also available to custom via a callback function: { // omit... footerEvents: { - onClick: e => { ... } + onClick: (e, column, columnIndex) => { ... } } } ``` diff --git a/packages/react-bootstrap-table2-example/examples/footer/column-event-table.js b/packages/react-bootstrap-table2-example/examples/footer/column-event-table.js index 6837eee..943c680 100644 --- a/packages/react-bootstrap-table2-example/examples/footer/column-event-table.js +++ b/packages/react-bootstrap-table2-example/examples/footer/column-event-table.js @@ -12,7 +12,7 @@ const columns = [{ dataField: 'id', text: 'Product ID', footerEvents: { - onClick: () => alert('Click on Product ID footer column') + onClick: (e, column, columnIndex) => alert(`Click on Product ID header column, columnIndex: ${columnIndex}`) }, footer: 'Footer 1' }, { @@ -32,7 +32,7 @@ const columns = [{ dataField: 'id', text: 'Product ID', footerEvents: { - onClick: () => alert('Click on Product ID footer column') + onClick: (e, column, columnIndex) => alert('Click on Product ID footer column') }, footer: 'Footer 1' }, { diff --git a/packages/react-bootstrap-table2/src/footer-cell.js b/packages/react-bootstrap-table2/src/footer-cell.js index 2995f4a..e47ad0a 100644 --- a/packages/react-bootstrap-table2/src/footer-cell.js +++ b/packages/react-bootstrap-table2/src/footer-cell.js @@ -4,56 +4,61 @@ import cs from 'classnames'; import PropTypes from 'prop-types'; import _ from './utils'; +import eventDelegater from './cell-event-delegater'; -const FooterCell = (props) => { - const { index, column, columnData } = props; +class FooterCell extends eventDelegater(React.Component) { + render() { + const { index, column, columnData } = this.props; - const { - footer, - footerTitle, - footerAlign, - footerFormatter, - footerEvents, - footerClasses, - footerStyle, - footerAttrs - } = column; + const { + footer, + footerTitle, + footerAlign, + footerFormatter, + footerEvents, + footerClasses, + footerStyle, + footerAttrs + } = column; - const cellAttrs = { - ...(_.isFunction(footerAttrs) ? footerAttrs(column, index) : footerAttrs), - ...footerEvents - }; + const delegateEvents = this.delegate(footerEvents); + const cellAttrs = { + ...(_.isFunction(footerAttrs) ? footerAttrs(column, index) : footerAttrs), + ...delegateEvents + }; - let text = ''; - if (_.isString(footer)) { - text = footer; - } else if (_.isFunction(footer)) { - text = footer(columnData, column, index); + + let text = ''; + if (_.isString(footer)) { + text = footer; + } else if (_.isFunction(footer)) { + text = footer(columnData, column, index); + } + + let cellStyle = {}; + const cellClasses = _.isFunction(footerClasses) ? footerClasses(column, index) : footerClasses; + + if (footerStyle) { + cellStyle = _.isFunction(footerStyle) ? footerStyle(column, index) : footerStyle; + cellStyle = cellStyle ? { ...cellStyle } : cellStyle; + } + + if (footerTitle) { + cellAttrs.title = _.isFunction(footerTitle) ? footerTitle(column, index) : text; + } + + if (footerAlign) { + cellStyle.textAlign = _.isFunction(footerAlign) ? footerAlign(column, index) : footerAlign; + } + + if (cellClasses) cellAttrs.className = cs(cellAttrs.className, cellClasses); + if (!_.isEmptyObject(cellStyle)) cellAttrs.style = cellStyle; + + const children = footerFormatter ? footerFormatter(column, index) : text; + + return React.createElement('th', cellAttrs, children); } - - let cellStyle = {}; - const cellClasses = _.isFunction(footerClasses) ? footerClasses(column, index) : footerClasses; - - if (footerStyle) { - cellStyle = _.isFunction(footerStyle) ? footerStyle(column, index) : footerStyle; - cellStyle = cellStyle ? { ...cellStyle } : cellStyle; - } - - if (footerTitle) { - cellAttrs.title = _.isFunction(footerTitle) ? footerTitle(column, index) : text; - } - - if (footerAlign) { - cellStyle.textAlign = _.isFunction(footerAlign) ? footerAlign(column, index) : footerAlign; - } - - if (cellClasses) cellAttrs.className = cs(cellAttrs.className, cellClasses); - if (!_.isEmptyObject(cellStyle)) cellAttrs.style = cellStyle; - - const children = footerFormatter ? footerFormatter(column, index) : text; - - return React.createElement('th', cellAttrs, children); -}; +} FooterCell.propTypes = { columnData: PropTypes.array,