diff --git a/docs/src/App.js b/docs/src/App.js
index d788f8a..70e68b1 100644
--- a/docs/src/App.js
+++ b/docs/src/App.js
@@ -15,8 +15,8 @@ import HOCReadme from "./stories/HOCReadme.js";
// import Tester from './examples/expander';
const stories = [
- { name: "Readme", component: Readme },
- { name: "HOC Readme", component: HOCReadme },
+ { name: 'Readme', component: Readme },
+ { name: 'HOC Readme', component: HOCReadme },
// { name: 'Tester', component: Test },
{ name: "Simple Table", component: CodeSandbox("X6npLXPRW") },
@@ -61,10 +61,12 @@ const stories = [
name: "Multiple Pagers (Top and Bottom)",
component: CodeSandbox("VEZ8OgvX")
},
- { name: "Tree Table (HOC)", component: CodeSandbox("lxmr4wynzq") },
- { name: "Select Table (HOC)", component: CodeSandbox("7yq5ylw09j") },
- { name: "Select Tree Table (HOC)", component: CodeSandbox("2p7jp4klwp") }
-];
+
+ { name: 'Tree Table (HOC)', component: CodeSandbox('lxmr4wynzq') },
+ { name: 'Select Table (HOC)', component: CodeSandbox('7yq5ylw09j') },
+ { name: 'Select Tree Table (HOC)', component: CodeSandbox('2p7jp4klwp') },
+ { name: 'Foldable Table (HOC)', component: CodeSandbox('2p7jp4klwp') },
+]
export default class App extends React.Component {
render() {
diff --git a/docs/src/examples/foldabletable/FoldableTableCustomState.js b/docs/src/examples/foldabletable/FoldableTableCustomState.js
new file mode 100644
index 0000000..b2c0f55
--- /dev/null
+++ b/docs/src/examples/foldabletable/FoldableTableCustomState.js
@@ -0,0 +1,110 @@
+import React from 'react'
+import ReactTable from '../../../../lib/index'
+import FoldableTableHOC from '../../../../lib/hoc/foldableTable'
+import selectTableHOC from '../../../../lib/hoc/selectTable'
+
+const FoldableTable = FoldableTableHOC(selectTableHOC(ReactTable))
+
+export default class FoldableTableCustomState extends React.Component {
+ constructor(props, context) {
+ super(props, context)
+
+ this.state = { folded: {}, seleted: {}, selectedAll: false }
+ }
+
+ getData = () => [{
+ id: 1,
+ first_name: 'Jeanette',
+ 'last_name': 'Penddreth',
+ email: 'jpenddreth0@census.gov',
+ 'gender': 'Female',
+ ip_address: '26.58.193.2',
+ }, {
+ 'id': 2,
+ 'first_name': 'Giavani',
+ last_name: 'Frediani',
+ 'email': 'gfrediani1@senate.gov',
+ 'gender': 'Male',
+ 'ip_address': '229.179.4.212',
+ }, {
+ 'id': 3,
+ first_name: 'Noell',
+ last_name: 'Bea',
+ 'email': 'nbea2@imageshack.us',
+ gender: 'Female',
+ ip_address: '180.66.162.255',
+ }, {
+ 'id': 4,
+ 'first_name': 'Willard',
+ 'last_name': 'Valek',
+ email: 'wvalek3@vk.com',
+ 'gender': 'Male',
+ ip_address: '67.76.188.26',
+ }];
+
+ toggleSelection = (key, shift, row) => {
+ const { selected } = this.state
+ let newSelected = Object.assign({}, selected)
+ newSelected[key] = !newSelected[key]
+ this.setState(p => ({ selected: newSelected }))
+ };
+
+ toggleAll = () => {
+ const { selectedAll } = this.state
+
+ if (selectedAll) { this.setState(p => { return { selectedAll: false, seleted: {} } }); }
+ else {
+ const data = this.getData()
+
+ let newSelected = {}
+ data.forEach(d => newSelected[d.id] = true)
+ this.setState(p => ({ selectedAll: true, seleted: newSelected }))
+ }
+ }
+
+ isSelected = key => this.state.seleted[key];
+
+ render() {
+ return ( this.setState(p => { return { folded: newFolded } })}
+ folded={this.state.folded}
+
+ data={this.getData()}
+ columns={[{
+ Header: "Name",
+ foldable: true,
+ columns: [
+ {
+ Header: "First Name",
+ accessor: "first_name"
+ },
+ {
+ Header: "Last Name",
+ accessor: "last_name"
+ }
+ ]
+ }, {
+ Header: "Info",
+ foldable: true,
+ columns: [
+ {
+ Header: "Email",
+ accessor: "email"
+ },
+ {
+ Header: "Gender",
+ accessor: "gender"
+ }
+ ]
+ }]
+ }> )
+ }
+}
diff --git a/docs/src/examples/foldabletable/FoldableTableWithHeader.js b/docs/src/examples/foldabletable/FoldableTableWithHeader.js
new file mode 100644
index 0000000..110f882
--- /dev/null
+++ b/docs/src/examples/foldabletable/FoldableTableWithHeader.js
@@ -0,0 +1,71 @@
+import React from 'react'
+import ReactTable from '../../../../lib/index'
+import FoldableTableHOC from '../../../../lib/hoc/foldableTable'
+
+const FoldableTable = FoldableTableHOC(ReactTable)
+
+export default class FoldableTableWithHeader extends React.Component {
+
+ getData = () => [{
+ id: 1,
+ first_name: 'Jeanette',
+ last_name: 'Penddreth',
+ 'email': 'jpenddreth0@census.gov',
+ gender: 'Female',
+ 'ip_address': '26.58.193.2',
+ }, {
+ 'id': 2,
+ first_name: 'Giavani',
+ last_name: 'Frediani',
+ email: 'gfrediani1@senate.gov',
+ gender: 'Male',
+ 'ip_address': '229.179.4.212',
+ }, {
+ 'id': 3,
+ 'first_name': 'Noell',
+ last_name: 'Bea',
+ 'email': 'nbea2@imageshack.us',
+ 'gender': 'Female',
+ ip_address: '180.66.162.255',
+ }, {
+ 'id': 4,
+ 'first_name': 'Willard',
+ 'last_name': 'Valek',
+ email: 'wvalek3@vk.com',
+ 'gender': 'Male',
+ ip_address: '67.76.188.26',
+ }];
+
+ render() {
+ return ( )
+ }
+}
diff --git a/docs/src/examples/foldabletable/FoldableTableWithoutHeader.js b/docs/src/examples/foldabletable/FoldableTableWithoutHeader.js
new file mode 100644
index 0000000..3ad242f
--- /dev/null
+++ b/docs/src/examples/foldabletable/FoldableTableWithoutHeader.js
@@ -0,0 +1,64 @@
+import React from 'react';
+import ReactTable from '../../../../lib/index';
+import FoldableTableHOC from '../../../../lib/hoc/foldableTable';
+
+const FoldableTable = FoldableTableHOC(ReactTable);
+
+export default class FoldableTableWithoutHeader extends React.Component {
+
+ getData = () => [{
+ "id": 1,
+ "first_name": "Jeanette",
+ "last_name": "Penddreth",
+ "email": "jpenddreth0@census.gov",
+ "gender": "Female",
+ "ip_address": "26.58.193.2"
+ }, {
+ "id": 2,
+ "first_name": "Giavani",
+ "last_name": "Frediani",
+ "email": "gfrediani1@senate.gov",
+ "gender": "Male",
+ "ip_address": "229.179.4.212"
+ }, {
+ "id": 3,
+ "first_name": "Noell",
+ "last_name": "Bea",
+ "email": "nbea2@imageshack.us",
+ "gender": "Female",
+ "ip_address": "180.66.162.255"
+ }, {
+ "id": 4,
+ "first_name": "Willard",
+ "last_name": "Valek",
+ "email": "wvalek3@vk.com",
+ "gender": "Male",
+ "ip_address": "67.76.188.26"
+ }];
+
+ render() {
+ return
+ }
+}
diff --git a/docs/src/examples/foldabletable/index.js b/docs/src/examples/foldabletable/index.js
new file mode 100644
index 0000000..10f0448
--- /dev/null
+++ b/docs/src/examples/foldabletable/index.js
@@ -0,0 +1,30 @@
+
+import React from 'react'
+import '../../../../react-table.css'
+
+import FoldableTableWithHeader from './FoldableTableWithHeader'
+import FoldableTableWithoutHeader from './FoldableTableWithoutHeader'
+import FoldableTableCustomState from './FoldableTableCustomState'
+
+class FaldableComponentTest extends React.Component {
+ render() {
+
+ return (
+
+
- Sample With Header Columns
+
+
+
+
- Sample With Normal Columns
+
+
+
+
- Custom State and selectedTable
+
+
+
+ )
+ }
+}
+
+export default FaldableComponentTest
diff --git a/docs/src/examples/index.js b/docs/src/examples/index.js
index 8e50611..69b737a 100644
--- a/docs/src/examples/index.js
+++ b/docs/src/examples/index.js
@@ -1,7 +1,13 @@
/* eslint-disable */
-import TreeTable from "./treetable";
-import SelectTable from "./selecttable";
-import SelectTreeTable from "./selecttreetable";
+import TreeTable from './treetable'
+import SelectTable from './selecttable'
+import SelectTreeTable from './selecttreetable'
+import FoldableTable from './foldabletable';
-export { TreeTable, SelectTable, SelectTreeTable };
+export {
+ TreeTable,
+ SelectTable,
+ SelectTreeTable,
+ FoldableTable
+}
diff --git a/src/hoc/README.md b/src/hoc/README.md
index 1b8f85e..954fc8e 100644
--- a/src/hoc/README.md
+++ b/src/hoc/README.md
@@ -103,6 +103,107 @@ const SelectTreeTable = selectTableHOC(treeTableHOC(ReactTable));
In this particular instance it is (probably) because the functions need access to the state on the wrapped component to manage
the selected items. Although that is not totally clearly the issue.
+### FoldableTable
+FoldableTable is a HOC that make the columns are foldable. The reason I developed this HOC because when working on the real project related to the financial which display so many columns for validation and comparison.
+
+So foldable columns allow users to temporary hidden the unwanted to columns so that they can focus on the data that they want to see.
+
+#### How it work
+```javascfript
+import ReactTable from 'react-table'
+import FoldableTableHOC from 'react-table/lib/hoc/foldableTable'
+
+const FoldableTable = FoldableTableHOC(ReactTable);
+```
+It will scan all the columns which `foldable` is `true` and apply the foldable column feature. This feature will work for both normal columns and header columns as samples below.
+
+- With Header Columns
+```javascript
+render(){
+ return
+}
+```
+
+
+
+- With Nornal Columns
+```javascript
+render() {
+ return
+}
+```
+
+
+
+- The `FoldableTable` also fully compatible with existing HOCs, below is with selectTableHOC.
+
+
+
+#### State management
+If you would like to manage the state of FoldableTable, then add the following codes.
+```javascript
+render() {
+ return this.setState(p => { return { folded: newFolded } })}
+ folded={this.state.folded}
+ />
+}
+```
+#### Custom Compoments
+ - FoldIconComponent: to render the Icon of buttons.
+ - FoldButtonComponent: to render the folding buttons for each Column.
+ With default rendering as below.
+```javascript
+const defaultFoldIconComponent = ({ collapsed }) => {
+ //Render your Icon here
+}
+
+const defaultFoldButtonComponent = ({ header, collapsed, icon, onClick }) => {
+ //Render your button here.
+}
+```
+
## HOC Guide for ReactTable
There are a few rules required when writing a HOC for ReactTable (other than meeting the normal lint standards - which are
diff --git a/src/hoc/foldableTable/index.js b/src/hoc/foldableTable/index.js
new file mode 100644
index 0000000..b6263ea
--- /dev/null
+++ b/src/hoc/foldableTable/index.js
@@ -0,0 +1,225 @@
+import React from 'react';
+import left from './left.svg';
+import right from './right.svg';
+
+const defaultFoldIconComponent = ({ collapsed }) => {
+ const style = { width: 25 };
+
+ if (collapsed)
+ return
+ return
+}
+
+const defaultFoldButtonComponent = ({ header, collapsed, icon, onClick }) => {
+ const style = {
+ marginLeft: "0px",
+ marginTop: "-5px",
+ marginBottom: "-8px",
+ float: "left",
+ cursor: "pointer"
+ };
+
+ return (
+
+ {icon}
+
+ {!collapsed &&
{header}
}
+
);
+}
+
+export default (ReactTable) => {
+
+ const wrapper = class RTFoldableTable extends React.Component {
+ constructor(props, context) {
+ super(props, context);
+
+ this.state = {
+ folded: props.onFoldChange ? undefined : {},
+ resized: props.resized || []
+ };
+ }
+
+ componentWillReceiveProps(newProps) {
+ if (this.state.resized !== newProps.resized)
+ this.setState(p => { return { resized: newProps.resized } });
+ }
+
+ onResizedChange = resized => {
+ const { onResizedChange } = this.props;
+ if (onResizedChange)
+ onResizedChange(resized);
+ else this.setState(p => { return { resized } });
+ }
+
+ removeResized = column => {
+ const { id } = column;
+ if (!id) return;
+
+ const { resized } = this.state;
+ if (!resized) return;
+
+ const rs = resized.find(r => r.id === id);
+ if (!rs) return;
+
+ const newResized = resized.filter(r => r !== rs);
+ this.onResizedChange(newResized);
+ }
+
+ // this is so we can expose the underlying ReactTable.
+ getWrappedInstance = () => {
+ if (!this.wrappedInstance) console.warn('RTFoldableTable - No wrapped instance');
+ if (this.wrappedInstance.getWrappedInstance) return this.wrappedInstance.getWrappedInstance();
+ else return this.wrappedInstance
+ }
+
+ getCopiedKey = key => {
+ const { foldableOriginalKey } = this.props;
+ return `${foldableOriginalKey}${key}`;
+ }
+
+ copyOriginals = column => {
+ const { FoldedColumn } = this.props;
+
+ //Stop copy if the column already copied
+ if (column.original_Header) return;
+
+ Object.keys(FoldedColumn).forEach(k => {
+ const copiedKey = this.getCopiedKey(k);
+
+ if (k === "Cell")
+ column[copiedKey] = column[k] ? column[k] : c => c.value;
+ else column[copiedKey] = column[k];
+ });
+
+ //Copy sub Columns
+ if (column.columns && !column.original_Columns)
+ column.original_Columns = column.columns;
+
+ //Copy Header
+ if (!column.original_Header)
+ column.original_Header = column.Header;
+ }
+
+ restoreToOriginal = column => {
+ const { FoldedColumn } = this.props;
+
+ Object.keys(FoldedColumn).forEach(k => {
+ //ignore header as handling by foldableHeaderRender
+ if (k === "Header") return;
+
+ const copiedKey = this.getCopiedKey(k);
+ column[k] = column[copiedKey];
+ });
+
+ if (column.columns && column.original_Columns)
+ column.columns = column.original_Columns;
+ }
+
+ getState = () => this.props.onFoldChange ? this.props.folded : this.state.folded;
+
+ isFolded = col => {
+ const folded = this.getState();
+ return folded[col.id] === true;
+ }
+
+ foldingHandler = col => {
+ if (!col || !col.id) return;
+
+ const { onFoldChange } = this.props;
+ const folded = this.getState();
+ const { id } = col;
+
+ let newFold = Object.assign({}, folded);
+ newFold[id] = !newFold[id];
+
+ //Remove the Resized if have
+ this.removeResized(col);
+
+ if (onFoldChange)
+ onFoldChange(newFold);
+ else this.setState(previous => { return { folded: newFold }; });
+ }
+
+ foldableHeaderRender = (cell) => {
+ const { FoldButtonComponent, FoldIconComponent } = this.props;
+ const { column } = cell;
+ const collapsed = this.isFolded(column);
+ const icon = React.createElement(FoldIconComponent, { collapsed });
+ const onClick = () => this.foldingHandler(column);
+
+ return React.createElement(FoldButtonComponent, { header: column.original_Header, collapsed, icon, onClick });
+ }
+
+ applyFoldableForColumn = column => {
+ const collapsed = this.isFolded(column);
+ const { FoldedColumn } = this.props;
+
+ //Handle Column Header
+ if (column.columns) {
+ if (collapsed) {
+ column.columns = [FoldedColumn];
+ column.width = FoldedColumn.width;
+ column.style = FoldedColumn.style;
+ }
+ else this.restoreToOriginal(column);
+ }
+ //Handle Normal Column.
+ else if (collapsed)
+ column = Object.assign(column, FoldedColumn);
+ else {
+ this.restoreToOriginal(column);
+ }
+ }
+
+ applyFoldableForColumns = columns => {
+ return columns.map((col, index) => {
+ if (!col.foldable) return col;
+
+ //If col don't have id then generate id based on index
+ if (!col.id)
+ col.id = `col_${index}`;
+
+ this.copyOriginals(col);
+ //Replace current header with internal header render.
+ col.Header = c => this.foldableHeaderRender(c);
+ //apply foldable
+ this.applyFoldableForColumn(col);
+
+ //return the new column out
+ return col;
+ });
+ }
+
+ render() {
+ const { columns: originalCols, FoldButtonComponent, FoldIconComponent, FoldedColumn, ...rest } = this.props;
+ const columns = this.applyFoldableForColumns([...originalCols]);
+
+ const extra = {
+ columns,
+ onResizedChange: this.onResizedChange,
+ resized: this.state.resized
+ };
+
+ return (
+ this.wrappedInstance = r} />
+ )
+ }
+ }
+
+ wrapper.displayName = 'RTFoldableTable';
+ wrapper.defaultProps =
+ {
+ FoldIconComponent: defaultFoldIconComponent,
+ FoldButtonComponent: defaultFoldButtonComponent,
+ foldableOriginalKey: 'original_',
+ FoldedColumn: {
+ Cell: c => '',
+ width: 30,
+ sortable: false,
+ resizable: false,
+ filterable: false,
+ }
+ }
+
+ return wrapper;
+}
\ No newline at end of file
diff --git a/src/hoc/foldableTable/left.svg b/src/hoc/foldableTable/left.svg
new file mode 100644
index 0000000..f0383f7
--- /dev/null
+++ b/src/hoc/foldableTable/left.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/hoc/foldableTable/right.svg b/src/hoc/foldableTable/right.svg
new file mode 100644
index 0000000..5088e25
--- /dev/null
+++ b/src/hoc/foldableTable/right.svg
@@ -0,0 +1 @@
+
\ No newline at end of file