diff --git a/docs/row-expand.md b/docs/row-expand.md index ce710de..025d03d 100644 --- a/docs/row-expand.md +++ b/docs/row-expand.md @@ -15,6 +15,7 @@ * [showExpandColumn](#showExpandColumn) * [onlyOneExpanding](#onlyOneExpanding) * [expandByColumnOnly](#expandByColumnOnly) +* [expandColumnPosition](#expandColumnPosition) * [expandColumnRenderer](#expandColumnRenderer) * [expandHeaderColumnRenderer](#expandHeaderColumnRenderer) @@ -153,3 +154,14 @@ const expandRow = { expandByColumnOnly: true }; ``` + +### expandRow.expandColumnPosition - [String] +Default is `left`. You can give this as `right` for rendering expand column in the right side. + +```js +const expandRow = { + renderer: (row) => ..., + showExpandColumn: true, + expandColumnPosition: 'right' +}; +``` diff --git a/packages/react-bootstrap-table2-example/examples/row-expand/expand-column-position.js b/packages/react-bootstrap-table2-example/examples/row-expand/expand-column-position.js new file mode 100644 index 0000000..8b07b34 --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/row-expand/expand-column-position.js @@ -0,0 +1,76 @@ +import React from 'react'; + +import BootstrapTable from 'react-bootstrap-table-next'; +import Code from 'components/common/code-block'; +import { productsExpandRowsGenerator } from 'utils/common'; + +const products = productsExpandRowsGenerator(); + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'price', + text: 'Product Price' +}]; + +const expandRow = { + renderer: row => ( +
+

{ `This Expand row is belong to rowKey ${row.id}` }

+

You can render anything here, also you can add additional data on every row object

+

expandRow.renderer callback will pass the origin row object to you

+
+ ), + showExpandColumn: true, + expandColumnPosition: 'right' +}; + +const sourceCode = `\ +import BootstrapTable from 'react-bootstrap-table-next'; + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name' +}, { + dataField: 'price', + text: 'Product Price' +}]; + +const expandRow = { + renderer: row => ( +
+

{ \`This Expand row is belong to rowKey $\{row.id}\` }

+

You can render anything here, also you can add additional data on every row object

+

expandRow.renderer callback will pass the origin row object to you

+
+ ), + showExpandColumn: true, + expandColumnPosition: 'right' +}; + + +`; + +export default () => ( +
+ + { sourceCode } +
+); diff --git a/packages/react-bootstrap-table2-example/stories/index.js b/packages/react-bootstrap-table2-example/stories/index.js index 56735cb..0461549 100644 --- a/packages/react-bootstrap-table2-example/stories/index.js +++ b/packages/react-bootstrap-table2-example/stories/index.js @@ -142,6 +142,7 @@ import ExpandColumn from 'examples/row-expand/expand-column'; import OnlyExpandByColumn from 'examples/row-expand/expand-by-column-only.js'; import ExpandOnlyOne from 'examples/row-expand/expand-only-one'; import CustomExpandColumn from 'examples/row-expand/custom-expand-column'; +import ExpandColumnPosition from 'examples/row-expand/expand-column-position'; import ExpandHooks from 'examples/row-expand/expand-hooks'; // pagination @@ -349,6 +350,7 @@ storiesOf('Row Expand', module) .add('Only Expand by Indicator', () => ) .add('Expand Only One Row at The Same Time', () => ) .add('Custom Expand Indicator', () => ) + .add('Expand Column Position', () => ) .add('Expand Hooks', () => ); storiesOf('Pagination', module) diff --git a/packages/react-bootstrap-table2/src/bootstrap-table.js b/packages/react-bootstrap-table2/src/bootstrap-table.js index c77c107..7c3a727 100644 --- a/packages/react-bootstrap-table2/src/bootstrap-table.js +++ b/packages/react-bootstrap-table2/src/bootstrap-table.js @@ -158,7 +158,11 @@ BootstrapTable.propTypes = { onlyOneExpanding: PropTypes.bool, expandByColumnOnly: PropTypes.bool, expandColumnRenderer: PropTypes.func, - expandHeaderColumnRenderer: PropTypes.func + expandHeaderColumnRenderer: PropTypes.func, + expandColumnPosition: PropTypes.oneOf([ + Const.INDICATOR_POSITION_LEFT, + Const.INDICATOR_POSITION_RIGHT + ]) }), rowStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), rowEvents: PropTypes.object, diff --git a/packages/react-bootstrap-table2/src/const.js b/packages/react-bootstrap-table2/src/const.js index 6c47b1c..ce1b7e4 100644 --- a/packages/react-bootstrap-table2/src/const.js +++ b/packages/react-bootstrap-table2/src/const.js @@ -6,5 +6,7 @@ export default { ROW_SELECT_DISABLED: 'ROW_SELECT_DISABLED', CHECKBOX_STATUS_CHECKED: 'checked', CHECKBOX_STATUS_INDETERMINATE: 'indeterminate', - CHECKBOX_STATUS_UNCHECKED: 'unchecked' + CHECKBOX_STATUS_UNCHECKED: 'unchecked', + INDICATOR_POSITION_LEFT: 'left', + INDICATOR_POSITION_RIGHT: 'right' }; diff --git a/packages/react-bootstrap-table2/src/header.js b/packages/react-bootstrap-table2/src/header.js index e8a6fb3..2606852 100644 --- a/packages/react-bootstrap-table2/src/header.js +++ b/packages/react-bootstrap-table2/src/header.js @@ -7,6 +7,7 @@ import SelectionHeaderCell from './row-selection/selection-header-cell'; import ExpandHeaderCell from './row-expand/expand-header-cell'; import withHeaderSelection from './row-selection/selection-header-cell-consumer'; import withHeaderExpansion from './row-expand/expand-header-cell-consumer'; +import Const from './const'; const Header = (props) => { const { @@ -32,36 +33,49 @@ const Header = (props) => { SelectionHeaderCellComp = withHeaderSelection(SelectionHeaderCell); } + const isRenderExpandColumnInLeft = ( + expandColumnPosition = Const.INDICATOR_POSITION_LEFT + ) => expandColumnPosition === Const.INDICATOR_POSITION_LEFT; + + const childrens = [ + columns.map((column, i) => { + if (!column.hidden) { + const currSort = column.dataField === sortField; + const isLastSorting = column.dataField === sortField; + + return ( + ); + } + return false; + }) + ]; + + if (!selectRow.hideSelectColumn) { + childrens.unshift(); + } + + if (expandRow.showExpandColumn) { + if (isRenderExpandColumnInLeft(expandRow.expandColumnPosition)) { + childrens.unshift(); + } else { + childrens.push(); + } + } + return ( - - { - !selectRow.hideSelectColumn ? - : null - } - { - columns.map((column, i) => { - if (!column.hidden) { - const currSort = column.dataField === sortField; - const isLastSorting = column.dataField === sortField; - - return ( - ); - } - return false; - }) - } + { childrens } ); diff --git a/packages/react-bootstrap-table2/src/row/aggregate-row.js b/packages/react-bootstrap-table2/src/row/aggregate-row.js index dfba8b5..96b7dbe 100644 --- a/packages/react-bootstrap-table2/src/row/aggregate-row.js +++ b/packages/react-bootstrap-table2/src/row/aggregate-row.js @@ -1,3 +1,4 @@ +/* eslint class-methods-use-this: 0 */ /* eslint react/prop-types: 0 */ /* eslint no-plusplus: 0 */ import React from 'react'; @@ -8,6 +9,7 @@ import SelectionCell from '../row-selection/selection-cell'; import shouldUpdater from './should-updater'; import eventDelegater from './event-delegater'; import RowPureContent from './row-pure-content'; +import Const from '../const'; export default class RowAggregator extends shouldUpdater(eventDelegater(React.Component)) { static propTypes = { @@ -43,6 +45,12 @@ export default class RowAggregator extends shouldUpdater(eventDelegater(React.Co return this.shouldUpdateRowContent; } + isRenderExpandColumnInLeft( + expandColumnPosition = Const.INDICATOR_POSITION_LEFT + ) { + return expandColumnPosition === Const.INDICATOR_POSITION_LEFT; + } + render() { const { row, @@ -64,7 +72,7 @@ export default class RowAggregator extends shouldUpdater(eventDelegater(React.Co } = this.props; const key = _.get(row, keyField); const { hideSelectColumn, clickToSelect } = selectRow; - const { showExpandColumn } = expandRow; + const { showExpandColumn, expandColumnPosition } = expandRow; const newAttrs = this.delegate({ ...attrs }); if (clickToSelect || !!expandRow.renderer) { @@ -73,47 +81,59 @@ export default class RowAggregator extends shouldUpdater(eventDelegater(React.Co let tabIndexStart = (rowIndex * visibleColumnSize) + 1; + const childrens = [( + + )]; + + if (!hideSelectColumn) { + childrens.unshift(( + + )); + } + + if (showExpandColumn) { + const expandCell = ( + + ); + if (this.isRenderExpandColumnInLeft(expandColumnPosition)) { + childrens.unshift(expandCell); + } else { + childrens.push(expandCell); + } + } + return ( - { - showExpandColumn ? ( - - ) : null - } - { - !hideSelectColumn - ? ( - - ) - : null - } - + { childrens } ); } diff --git a/packages/react-bootstrap-table2/test/contexts/index.test.js b/packages/react-bootstrap-table2/test/contexts/index.test.js index 76caecb..737fcb9 100644 --- a/packages/react-bootstrap-table2/test/contexts/index.test.js +++ b/packages/react-bootstrap-table2/test/contexts/index.test.js @@ -225,4 +225,31 @@ describe('Context', () => { expect(wrapper.instance().PaginationContext).toBeDefined(); }); }); + + describe('if registerExposedAPI props is defined', () => { + const registerExposedAPI = jest.fn(); + beforeEach(() => { + const PaginationContext = React.createContext(); + const paginator = { + createContext: jest.fn().mockReturnValue({ + Provider: PaginationContext.Provider, + Consumer: PaginationContext.Consumer + }) + }; + wrapper = shallow( + + ); + wrapper.render(); + }); + + it('should call props.registerExposedAPI correctly', () => { + expect(registerExposedAPI).toHaveBeenCalledTimes(1); + }); + }); }); diff --git a/packages/react-bootstrap-table2/test/header.test.js b/packages/react-bootstrap-table2/test/header.test.js index ecb2318..263ac54 100644 --- a/packages/react-bootstrap-table2/test/header.test.js +++ b/packages/react-bootstrap-table2/test/header.test.js @@ -254,5 +254,33 @@ describe('Header', () => { expect(wrapper.find(ExpandHeaderCell).length).toBe(1); }); }); + + describe('if props.expandRow.showExpandColumn is true but props.expandRow.expandColumnPosition is "right"', () => { + beforeEach(() => { + const expandRow = { + renderer: jest.fn(), + showExpandColumn: true, + expandColumnPosition: Const.INDICATOR_POSITION_RIGHT + }; + wrapper = mount( + +
+ + ); + }); + + it('should render expansion column correctly', () => { + const header = wrapper.find(Header).children(); + expect(header.children().children().last().find(ExpandHeaderCell)).toHaveLength(1); + }); + }); }); }); diff --git a/packages/react-bootstrap-table2/test/row/aggregate-row.test.js b/packages/react-bootstrap-table2/test/row/aggregate-row.test.js index 76aa625..b314470 100644 --- a/packages/react-bootstrap-table2/test/row/aggregate-row.test.js +++ b/packages/react-bootstrap-table2/test/row/aggregate-row.test.js @@ -9,6 +9,7 @@ import bindExpansion from '../../src/row-expand/row-consumer'; import ExpandCell from '../../src/row-expand/expand-cell'; import SelectionCell from '../../src/row-selection/selection-cell'; import RowAggregator from '../../src/row/aggregate-row'; +import Const from '../../src/const'; describe('Row Aggregator', () => { let wrapper; @@ -157,6 +158,27 @@ describe('Row Aggregator', () => { expect(expandCell.props().expanded).toEqual(rowAggregator.props().expanded); }); }); + + describe('if props.expandRow.showExpandColumn is true but props.expandRow.expandColumnPosition is "right"', () => { + beforeEach(() => { + const expandRow = { + renderer: jest.fn(), + showExpandColumn: true, + expandColumnPosition: Const.INDICATOR_POSITION_RIGHT + }; + wrapper = mount( + + + + ); + }); + + it('should render expansion column correctly', () => { + rowAggregator = wrapper.find(RowAggregator); + expect(rowAggregator).toHaveLength(1); + expect(rowAggregator.children().children().last().type()).toEqual(ExpandCell); + }); + }); }); describe('createClickEventHandler', () => {