diff --git a/packages/react-bootstrap-table2/src/bootstrap-table.js b/packages/react-bootstrap-table2/src/bootstrap-table.js
index 7f3a16c..e3dd58d 100644
--- a/packages/react-bootstrap-table2/src/bootstrap-table.js
+++ b/packages/react-bootstrap-table2/src/bootstrap-table.js
@@ -72,6 +72,7 @@ class BootstrapTable extends PropsBaseResolver(Component) {
});
const tableCaption = (caption &&
{ caption });
+ const expandRow = this.resolveExpandRowProps();
return (
@@ -86,6 +87,7 @@ class BootstrapTable extends PropsBaseResolver(Component) {
onFilter={ this.props.onFilter }
onExternalFilter={ this.props.onExternalFilter }
selectRow={ headerCellSelectionInfo }
+ expandRow={ expandRow }
/>
({ expanded: currExpanded }));
}
+ handleAllRowExpand = (e, expandAll) => {
+ const {
+ data,
+ keyField,
+ expandRow: {
+ onExpandAll,
+ nonExpandable
+ }
+ } = this.props;
+ const { expanded } = this.state;
+
+ let currExpanded;
+
+ if (expandAll) {
+ currExpanded = expanded.concat(dataOperator.expandableKeys(data, keyField, nonExpandable));
+ } else {
+ currExpanded = expanded.filter(s => typeof data.find(d => d[keyField] === s) === 'undefined');
+ }
+
+ if (onExpandAll) {
+ onExpandAll(expandAll, dataOperator.getExpandedRows(data, keyField, currExpanded), e);
+ }
+
+ this.setState(() => ({ expanded: currExpanded }));
+ }
+
render() {
+ const { data, keyField } = this.props;
return (
{ this.props.children }
diff --git a/packages/react-bootstrap-table2/src/header.js b/packages/react-bootstrap-table2/src/header.js
index 0b8ee80..67568ea 100644
--- a/packages/react-bootstrap-table2/src/header.js
+++ b/packages/react-bootstrap-table2/src/header.js
@@ -5,6 +5,7 @@ import Const from './const';
import HeaderCell from './header-cell';
import SelectionHeaderCell from './row-selection/selection-header-cell';
+import ExpandHeaderCell from './row-expand/expand-header-cell';
const Header = (props) => {
const { ROW_SELECT_DISABLED } = Const;
@@ -17,12 +18,21 @@ const Header = (props) => {
sortField,
sortOrder,
selectRow,
- onExternalFilter
+ onExternalFilter,
+ expandRow
} = props;
return (
+ {
+ (expandRow && expandRow.showExpandColumn)
+ ? : null
+ }
{
(selectRow.mode !== ROW_SELECT_DISABLED && !selectRow.hideSelectColumn)
? : null
@@ -62,7 +72,8 @@ Header.propTypes = {
sortOrder: PropTypes.string,
selectRow: PropTypes.object,
onExternalFilter: PropTypes.func,
- className: PropTypes.string
+ className: PropTypes.string,
+ expandRow: PropTypes.object
};
export default Header;
diff --git a/packages/react-bootstrap-table2/src/props-resolver/expand-row-resolver.js b/packages/react-bootstrap-table2/src/props-resolver/expand-row-resolver.js
index c959776..015e321 100644
--- a/packages/react-bootstrap-table2/src/props-resolver/expand-row-resolver.js
+++ b/packages/react-bootstrap-table2/src/props-resolver/expand-row-resolver.js
@@ -1,12 +1,14 @@
export default ExtendBase =>
class ExpandRowResolver extends ExtendBase {
resolveExpandRowProps() {
- const { expandRow, expanded, onRowExpand } = this.props;
+ const { expandRow, expanded, onRowExpand, onAllRowExpand, isAnyExpands } = this.props;
if (expandRow) {
return {
...expandRow,
expanded,
onRowExpand,
+ onAllRowExpand,
+ isAnyExpands,
nonExpandable: expandRow.nonExpandable || []
};
}
diff --git a/packages/react-bootstrap-table2/src/row-expand/expand-cell.js b/packages/react-bootstrap-table2/src/row-expand/expand-cell.js
new file mode 100644
index 0000000..3df5b1c
--- /dev/null
+++ b/packages/react-bootstrap-table2/src/row-expand/expand-cell.js
@@ -0,0 +1,42 @@
+/* eslint
+ react/require-default-props: 0
+ jsx-a11y/no-noninteractive-element-interactions: 0
+*/
+/* eslint no-nested-ternary: 0 */
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+
+export default class ExpandCell extends Component {
+ static propTypes = {
+ rowKey: PropTypes.any,
+ expanded: PropTypes.bool.isRequired,
+ onRowExpand: PropTypes.func.isRequired,
+ expandColumnRenderer: PropTypes.func,
+ rowIndex: PropTypes.number
+ }
+
+ constructor() {
+ super();
+ this.handleClick = this.handleClick.bind(this);
+ }
+
+ handleClick(e) {
+ const { rowKey, expanded, onRowExpand, rowIndex } = this.props;
+
+ onRowExpand(rowKey, expanded, rowIndex, e);
+ }
+
+ render() {
+ const { expanded, expandColumnRenderer } = this.props;
+
+ return (
+ |
+ {
+ expandColumnRenderer ? expandColumnRenderer({
+ expanded
+ }) : (expanded ? '(-)' : '(+)')
+ }
+ |
+ );
+ }
+}
diff --git a/packages/react-bootstrap-table2/src/row-expand/expand-header-cell.js b/packages/react-bootstrap-table2/src/row-expand/expand-header-cell.js
new file mode 100644
index 0000000..65c099b
--- /dev/null
+++ b/packages/react-bootstrap-table2/src/row-expand/expand-header-cell.js
@@ -0,0 +1,40 @@
+/* eslint react/require-default-props: 0 */
+/* eslint no-nested-ternary: 0 */
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+
+export default class SelectionHeaderCell extends Component {
+ static propTypes = {
+ anyExpands: PropTypes.bool.isRequired,
+ onAllRowExpand: PropTypes.func.isRequired,
+ renderer: PropTypes.func
+ }
+
+ constructor() {
+ super();
+ this.handleCheckBoxClick = this.handleCheckBoxClick.bind(this);
+ }
+
+ handleCheckBoxClick(e) {
+ const { anyExpands, onAllRowExpand } = this.props;
+
+ onAllRowExpand(e, !anyExpands);
+ }
+
+ render() {
+ const { anyExpands, renderer } = this.props;
+ const attrs = {
+ onClick: this.handleCheckBoxClick
+ };
+
+ return (
+
+ {
+ renderer ?
+ renderer({ isAnyExpands: anyExpands }) :
+ (anyExpands ? '(-)' : '(+)')
+ }
+ |
+ );
+ }
+}
diff --git a/packages/react-bootstrap-table2/src/row.js b/packages/react-bootstrap-table2/src/row.js
index b6222bb..1196716 100644
--- a/packages/react-bootstrap-table2/src/row.js
+++ b/packages/react-bootstrap-table2/src/row.js
@@ -6,6 +6,7 @@ import PropTypes from 'prop-types';
import _ from './utils';
import Cell from './cell';
import SelectionCell from './row-selection/selection-cell';
+import ExpandCell from './row-expand/expand-cell';
import eventDelegater from './row-event-delegater';
import Const from './const';
@@ -22,6 +23,8 @@ class Row extends eventDelegater(Component) {
cellEdit,
selected,
selectRow,
+ expanded,
+ expandRow,
selectable,
editable: editableRow
} = this.props;
@@ -39,10 +42,21 @@ class Row extends eventDelegater(Component) {
const key = _.get(row, keyField);
const { hideSelectColumn } = selectRow;
+ const { showExpandColumn } = expandRow || {};
const trAttrs = this.delegate(attrs);
return (
+ {
+ showExpandColumn ? (
+
+ ) : null
+ }
{
(selectRow.mode !== Const.ROW_SELECT_DISABLED && !hideSelectColumn)
? (
diff --git a/packages/react-bootstrap-table2/src/store/expand.js b/packages/react-bootstrap-table2/src/store/expand.js
new file mode 100644
index 0000000..31feb0a
--- /dev/null
+++ b/packages/react-bootstrap-table2/src/store/expand.js
@@ -0,0 +1,28 @@
+import _ from '../utils';
+import { getRowByRowId } from './rows';
+
+export const isAnyExpands = (
+ data,
+ keyField,
+ expanded = []
+) => {
+ for (let i = 0; i < data.length; i += 1) {
+ const rowKey = _.get(data[i], keyField);
+ if (typeof expanded.find(x => x === rowKey) !== 'undefined') {
+ return true;
+ }
+ }
+ return false;
+};
+
+export const expandableKeys = (data, keyField, skips = []) => {
+ if (skips.length === 0) {
+ return data.map(row => _.get(row, keyField));
+ }
+ return data
+ .filter(row => !skips.includes(_.get(row, keyField)))
+ .map(row => _.get(row, keyField));
+};
+
+export const getExpandedRows = (data, keyField, expanded) =>
+ expanded.map(k => getRowByRowId(data, keyField, k));
diff --git a/packages/react-bootstrap-table2/src/store/operators.js b/packages/react-bootstrap-table2/src/store/operators.js
index c01ddad..de055ee 100644
--- a/packages/react-bootstrap-table2/src/store/operators.js
+++ b/packages/react-bootstrap-table2/src/store/operators.js
@@ -1,11 +1,13 @@
import * as rows from './rows';
import * as selection from './selection';
+import * as expand from './expand';
import * as mutate from './mutate';
import * as sort from './sort';
export default {
...rows,
...selection,
+ ...expand,
...mutate,
...sort
};