Examples Refactor + multiSort flag (#619)

* chore: Update the devDependencies for the linter

* A few HOC examples for react-table.
Not really integrated with the whole codesandbox.io approach.

* Missing dependency - shortid

* Refactor HOCs to /src/hoc
Still have to write the HOCReadme.md (still just a placeholder for now)

* Refactor complete
May need to remove some redundant code

* Text change for the HOC samples

* Introduced a 'multiSort' flag
Defaults to 'true'
A 'false' value will turn multi-sort off.

* refactor: Fix defaultProps.js linter errors

* refactor: Fix lifecycle.js linter errors

* refactor: Fix pagination.js linter errors

* refactor: Fix propTypes.js linter errors

* refactor: Fix utils.js linter errors

* refactor: Fix methods.js linter errors

* refactor: Fix index.js linter errors

* Fix for linter changes + CHANGELOG update
This commit is contained in:
Gary Menzel 2017-11-23 15:30:07 +11:00 committed by GitHub
parent 1cf9e49952
commit f74ba3cc16
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 1312 additions and 412 deletions

View File

@ -1,3 +1,58 @@
## 6.7.4
#### Fixes & Optimizations
- Fix Prop types for columns
## 6.7.3
#### Fixes & Optimizations
- Fix the rest of the proptypes
## 6.7.2
#### Fixes & Optimizations
- `getPropTypes` proptype check
## 6.7.1
#### Fixes & Optimizations
- `eslint-config` moved to dev deps
## 6.7.0
## 6.7.0-alpha-0
#### New Features
- Expose page/pageSize to rows/cells
- Supply sort direction to custom sort methods
#### Fixes & Optimizations
- README updates
- Linter cleanup
- Added PropTypes node module
- Deps, linting and style upgrades
## 6.6.0
#### Fixes & Optimizations
- moved repo to react-tools
- Doc examples moved to codesandbox.io
- README updates
- CSS refacting for rt-tfoot to match rt-thead
- CSS more specific for input and select
## 6.5.3
#### Fixes & Optimizations
- `onClick` proxying and eslint
## 6.5.2
#### New Features
- Provide onClick handleOriginal function - #406
#### Fixes & Optimizations
- README updates
- `makePathArray` in utils - #326
- Various fixes: #294, #376, #398, #415,
## 6.5.1
#### Fixes & Optimizations
- `defaultExpanded` now works correctly - #372
- `column.getProps().rest` props are now applied correctly
- `makeTemplateComponent` now supports `displayName` - #289
## 6.5.0
##### New Features
- `column.filterAll` - defaults to `false`, but when set to `true` will provide the entire array of rows to `filterMethod` as opposed to one row at a time. This allows for more fine-grained filtering using any method you can dream up. See the [Custom Filtering example](https://react-table.js.org/#/story/custom-filtering) for more info.

View File

@ -171,6 +171,7 @@ These are all of the available props (and their default values) for the main `<R
collapseOnDataChange: true,
freezeWhenExpanded: false,
sortable: true,
multiSort: true,
resizable: true,
filterable: false,
defaultSortDesc: false,
@ -833,6 +834,9 @@ Sorting comes built in with React-Table.
## Multi-Sort
When clicking on a column header, hold shift to multi-sort! You can toggle `ascending` `descending` and `none` for multi-sort columns. Clicking on a header without holding shift will clear the multi-sort and replace it with the single sort of that column. It's quite handy!
You can set the `multiSort` prop to `false` to disable this feature (which may be useful for server-side sorting when you are not
going to sort multiple columns).
## Custom Sorting Algorithm
To override the default sorting algorithm for the whole table use the `defaultSortMethod` prop.

View File

@ -10,6 +10,15 @@
"babel-preset-react": "6.11.1",
"babel-preset-stage-2": "6.13.0",
"eslint": "^4.1.1",
"eslint-config-standard": "^10.2.1",
"eslint-plugin-class-property": "^1.0.6",
"eslint-plugin-import": "^2.8.0",
"eslint-plugin-jsx-a11y": "^6.0.2",
"eslint-plugin-node": "^5.2.1",
"eslint-plugin-promise": "^3.6.0",
"eslint-plugin-react": "^7.4.0",
"eslint-plugin-standard": "^3.0.1",
"html-element-attributes": "^1.3.0",
"match-sorter": "^1.8.0",
"npm-run-all": "^3.1.1",
"onchange": "^3.0.2",

View File

@ -1,3 +1,5 @@
/* eslint-disable */
import React from 'react'
//
import ReactStory, { defaultProps } from 'react-story'
@ -6,6 +8,18 @@ import './stories/utils/prism.css'
import '../../react-table.css'
import Readme from './stories/Readme.js'
import HOCReadme from './stories/HOCReadme.js'
// import Tester from './examples/expander';
// import { TreeTable, SelectTable, SelectTreeTable } from './examples/index'
//
// const exampleStories = [
// // examples
// { name: 'TreeTable', component: TreeTable },
// { name: 'SelectTable', component: SelectTable },
// { name: 'SelectTreeTable', component: SelectTreeTable },
// ]
import { TreeTable, CheckboxTable } from './examples/index'
@ -17,7 +31,9 @@ const exampleStories = [
const stories = [
{ name: 'Readme', component: Readme },
{ name: 'HOC Readme', component: HOCReadme },
// { name: 'Tester', component: Tester },
{ name: 'Simple Table', component: CodeSandbox('X6npLXPRW') },
{
name: 'Cell Renderers & Custom Components',
@ -60,10 +76,9 @@ const stories = [
name: 'Multiple Pagers (Top and Bottom)',
component: CodeSandbox('VEZ8OgvX'),
},
// other examples
...exampleStories,
{ name: 'Tree Table (HOC)', component: CodeSandbox('lxmr4wynzq') },
{ name: 'Select Table (HOC)', component: CodeSandbox('7yq5ylw09j') },
{ name: 'Select Tree Table (HOC)', component: CodeSandbox('2p7jp4klwp') },
]
export default class App extends React.Component {

View File

@ -0,0 +1,54 @@
/* eslint-disable */
import React from 'react';
import ReactTable from '../../../../lib/index'
import '../../../../react-table.css'
const data = [
{one:"1.1",two:"1.2"},
{one:"2.1",two:"2.2"},
{one:"3.1",two:"3.2"},
{one:"4.1",two:"4.2"},
]
const columns = [
{accessor:'one', Header: 'One'},
{accessor:'two', Header: 'Two'},
]
class ExpanderComponent extends React.Component {
render()
{
return (
<div className={`rt-expander ${this.props.isExpanded ? '-open' : ''}`}>
&bull;
</div>
)
}
}
class SubComponent extends React.Component {
render()
{
return <div>Nothing</div>
}
}
export default class ComponentTest extends React.Component {
render()
{
const rtProps = {
data,
columns,
ExpanderComponent: (props)=><ExpanderComponent {...props} />,
SubComponent: (props)=><SubComponent {...props} />,
multiSort: false,
}
return (
<ReactTable
{...rtProps}
/>
)
}
}

View File

@ -1,8 +1,11 @@
/* eslint-disable */
import TreeTable from './treetable';
import CheckboxTable from './checkbox';
import TreeTable from './treetable'
import SelectTable from './selecttable'
import SelectTreeTable from './selecttreetable'
export {
TreeTable,
CheckboxTable,
SelectTable,
SelectTreeTable,
}

View File

@ -0,0 +1,174 @@
import React from 'react';
import shortid from 'shortid';
import ReactTable from '../../../../lib/index'
import '../../../../react-table.css'
import selectTableHOC from '../../../../lib/hoc/selectTable'
const SelectTable = selectTableHOC(ReactTable);
async function getData()
{
const result = await ( await fetch('/au_500_tree.json') ).json();
// we are adding a unique ID to the data for tracking the selected records
return result.map((item)=>{
const _id = shortid.generate();
return {
_id,
...item,
}
});
}
function getColumns(data)
{
const columns = [];
const sample = data[0];
for(let key in sample)
{
if(key==='_id') continue;
columns.push({
accessor: key,
Header: key,
})
}
return columns;
}
export class ComponentTest extends React.Component {
constructor(props) {
super(props);
this.state =
{
data: null,
columns: null,
selection: [],
selectAll: false,
selectType: 'checkbox',
};
}
componentDidMount()
{
getData().then((data)=>{
const columns = getColumns(data);
this.setState({ data, columns });
});
}
toggleSelection = (key,shift,row) => {
/*
Implementation of how to manage the selection state is up to the developer.
This implementation uses an array stored in the component state.
Other implementations could use object keys, a Javascript Set, or Redux... etc.
*/
// start off with the existing state
if (this.state.selectType === 'radio') {
let selection = [];
if (selection.indexOf(key)<0) selection.push(key);
this.setState({selection});
} else {
let selection = [
...this.state.selection
];
const keyIndex = selection.indexOf(key);
// check to see if the key exists
if(keyIndex>=0) {
// it does exist so we will remove it using destructing
selection = [
...selection.slice(0,keyIndex),
...selection.slice(keyIndex+1)
]
} else {
// it does not exist so add it
selection.push(key);
}
// update the state
this.setState({selection});
}
}
toggleAll = () => {
/*
'toggleAll' is a tricky concept with any filterable table
do you just select ALL the records that are in your data?
OR
do you only select ALL the records that are in the current filtered data?
The latter makes more sense because 'selection' is a visual thing for the user.
This is especially true if you are going to implement a set of external functions
that act on the selected information (you would not want to DELETE the wrong thing!).
So, to that end, access to the internals of ReactTable are required to get what is
currently visible in the table (either on the current page or any other page).
The HOC provides a method call 'getWrappedInstance' to get a ref to the wrapped
ReactTable and then get the internal state and the 'sortedData'.
That can then be iterrated to get all the currently visible records and set
the selection state.
*/
const selectAll = this.state.selectAll?false:true;
const selection = [];
if(selectAll)
{
// we need to get at the internals of ReactTable
const wrappedInstance = this.selectTable.getWrappedInstance();
// the 'sortedData' property contains the currently accessible records based on the filter and sort
const currentRecords = wrappedInstance.getResolvedState().sortedData;
// we just push all the IDs onto the selection array
currentRecords.forEach((item)=>{
if(item._original)
{
selection.push(item._original._id);
}
})
}
this.setState({selectAll,selection})
}
isSelected = (key) => {
/*
Instead of passing our external selection state we provide an 'isSelected'
callback and detect the selection state ourselves. This allows any implementation
for selection (either an array, object keys, or even a Javascript Set object).
*/
return this.state.selection.includes(key);
}
logSelection = () => {
console.log('selection:',this.state.selection);
}
toggleType = () => {
this.setState({ selectType: this.state.selectType === 'radio' ? 'checkbox' : 'radio', selection: [], selectAll: false, });
}
render(){
const { toggleSelection, toggleAll, isSelected, logSelection, toggleType } = this;
const { data, columns, selectAll, selectType } = this.state;
const extraProps =
{
selectAll,
isSelected,
toggleAll,
toggleSelection,
selectType,
}
return (
<div style={{ padding: '10px'}}>
<h1>react-table - Select Table</h1>
<button onClick={toggleType}>Select Type: <strong>{selectType}</strong></button>
<button onClick={logSelection}>Log Selection to Console</button>
{` (${this.state.selection.length}) selected`}
{
data?
<SelectTable
data={data}
columns={columns}
ref={(r)=>this.selectTable = r}
className="-striped -highlight"
{...extraProps}
/>
:null
}
</div>
);
}
}
export default ComponentTest;

View File

@ -0,0 +1,216 @@
import React from 'react';
import shortid from 'shortid';
import ReactTable from '../../../../lib/index'
import '../../../../react-table.css'
import selectTableHOC from '../../../../lib/hoc/selectTable'
import treeTableHOC from '../../../../lib/hoc/treeTable'
const SelectTreeTable = selectTableHOC(treeTableHOC(ReactTable));
async function getData()
{
const result = await ( await fetch('/au_500_tree.json') ).json();
// we are adding a unique ID to the data for tracking the selected records
return result.map((item)=>{
const _id = shortid.generate();
return {
_id,
...item,
}
});
}
function getColumns(data)
{
const columns = [];
const sample = data[0];
for(let key in sample)
{
if(key==='_id') continue;
columns.push({
accessor: key,
Header: key,
})
}
return columns;
}
function getNodes(data,node=[])
{
data.forEach((item)=>{
if(item.hasOwnProperty('_subRows') && item._subRows)
{
node = getNodes(item._subRows,node);
} else {
node.push(item._original);
}
});
return node;
}
export class ComponentTest extends React.Component {
constructor(props) {
super(props);
this.state =
{
data: null,
columns: null,
selection: [],
selectAll: false,
selectType: 'checkbox',
};
}
componentDidMount()
{
getData().then((data)=>{
const columns = getColumns(data);
const pivotBy = ['state','post'];
this.setState({ data, columns, pivotBy });
});
}
toggleSelection = (key,shift,row) => {
/*
Implementation of how to manage the selection state is up to the developer.
This implementation uses an array stored in the component state.
Other implementations could use object keys, a Javascript Set, or Redux... etc.
*/
// start off with the existing state
if (this.state.selectType === 'radio') {
let selection = [];
if (selection.indexOf(key)<0) selection.push(key);
this.setState({selection});
} else {
let selection = [
...this.state.selection
];
const keyIndex = selection.indexOf(key);
// check to see if the key exists
if(keyIndex>=0) {
// it does exist so we will remove it using destructing
selection = [
...selection.slice(0,keyIndex),
...selection.slice(keyIndex+1)
]
} else {
// it does not exist so add it
selection.push(key);
}
// update the state
this.setState({selection});
}
}
toggleAll = () => {
/*
'toggleAll' is a tricky concept with any filterable table
do you just select ALL the records that are in your data?
OR
do you only select ALL the records that are in the current filtered data?
The latter makes more sense because 'selection' is a visual thing for the user.
This is especially true if you are going to implement a set of external functions
that act on the selected information (you would not want to DELETE the wrong thing!).
So, to that end, access to the internals of ReactTable are required to get what is
currently visible in the table (either on the current page or any other page).
The HOC provides a method call 'getWrappedInstance' to get a ref to the wrapped
ReactTable and then get the internal state and the 'sortedData'.
That can then be iterrated to get all the currently visible records and set
the selection state.
*/
const selectAll = this.state.selectAll?false:true;
const selection = [];
if(selectAll)
{
// we need to get at the internals of ReactTable
const wrappedInstance = this.selectTable.getWrappedInstance();
// the 'sortedData' property contains the currently accessible records based on the filter and sort
const currentRecords = wrappedInstance.getResolvedState().sortedData;
// we need to get all the 'real' (original) records out to get at their IDs
const nodes = getNodes(currentRecords);
// we just push all the IDs onto the selection array
nodes.forEach((item)=>{
selection.push(item._id);
})
}
this.setState({selectAll,selection})
}
isSelected = (key) => {
/*
Instead of passing our external selection state we provide an 'isSelected'
callback and detect the selection state ourselves. This allows any implementation
for selection (either an array, object keys, or even a Javascript Set object).
*/
return this.state.selection.includes(key);
}
logSelection = () => {
console.log('selection:',this.state.selection);
}
toggleType = () => {
this.setState({ selectType: this.state.selectType === 'radio' ? 'checkbox' : 'radio', selection: [], selectAll: false, });
}
toggleTree = () => {
if(this.state.pivotBy.length) {
this.setState({pivotBy:[],expanded:{}});
} else {
this.setState({pivotBy:['state','post'],expanded:{}});
}
}
onExpandedChange = (expanded) => {
this.setState({expanded});
}
render(){
const { toggleSelection, toggleAll, isSelected, logSelection, toggleType, toggleTree, onExpandedChange, } = this;
const { data, columns, selectAll, selectType, pivotBy, expanded, } = this.state;
const extraProps =
{
selectAll,
isSelected,
toggleAll,
toggleSelection,
selectType,
pivotBy,
expanded,
onExpandedChange,
pageSize: 5,
}
return (
<div style={{ padding: '10px'}}>
<h1>react-table - Select Tree Table</h1>
<p>This example combines two HOCs (the TreeTable and the SelectTable) to make a composite component.</p>
<p>We'll call it SelectTreeTable!</p>
<p>Here is what the buttons do:</p>
<ul>
<li><strong>Toggle Tree:</strong> enables or disabled the pivotBy on the table.</li>
<li><strong>Select Type:</strong> changes from 'checkbox' to 'radio' and back again.</li>
<li><strong>Log Selection to Console:</strong> open your console to see what has been selected.</li>
</ul>
<p>
<strong>NOTE:</strong> the selection is maintained when toggling the tree on and off but is cleared
when switching between select types (radio, checkbox).
</p>
<button onClick={toggleTree}>Toggle Tree [{pivotBy && pivotBy.length ? pivotBy.join(', ') : ''}]</button>
<button onClick={toggleType}>Select Type: <strong>{selectType}</strong></button>
<button onClick={logSelection}>Log Selection to Console</button>
{` (${this.state.selection.length}) selected`}
{
data?
<SelectTreeTable
data={data}
columns={columns}
ref={(r)=>this.selectTable = r}
className="-striped -highlight"
freezeWhenExpanded={true}
{...extraProps}
/>
:null
}
</div>
);
}
}
export default ComponentTest;

View File

@ -4,7 +4,7 @@ import React from 'react';
import ReactTable from '../../../../lib/index'
import '../../../../react-table.css'
import treeTableHOC from './treeTableHOC';
import treeTableHOC from '../../../../lib/hoc/treeTable'
async function getData()
{

View File

@ -0,0 +1,23 @@
/* eslint-disable */
import React from 'react'
import marked from 'marked'
//
import HOCReadme from '!raw!../../../src/hoc/README.md'
import 'github-markdown-css/github-markdown.css'
import './utils/prism.js'
export default class HOCStory extends React.Component {
render () {
return (
<div style={{ padding: '10px' }}>
<span
className='markdown-body'
dangerouslySetInnerHTML={{ __html: marked(HOCReadme) }}
/>
</div>
)
}
componentDidMount () {
global.Prism && global.Prism.highlightAll()
}
}

View File

@ -2417,7 +2417,7 @@ eslint-config-standard-jsx@4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/eslint-config-standard-jsx/-/eslint-config-standard-jsx-4.0.2.tgz#009e53c4ddb1e9ee70b4650ffe63a7f39f8836e1"
eslint-config-standard@10.2.1:
eslint-config-standard@10.2.1, eslint-config-standard@^10.2.1:
version "10.2.1"
resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-10.2.1.tgz#c061e4d066f379dc17cd562c64e819b4dd454591"
@ -2492,7 +2492,7 @@ eslint-plugin-import@2.0.1:
minimatch "^3.0.3"
pkg-up "^1.0.0"
eslint-plugin-import@^2.7.0:
eslint-plugin-import@^2.7.0, eslint-plugin-import@^2.8.0:
version "2.8.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.8.0.tgz#fa1b6ef31fcb3c501c09859c1b86f1fc5b986894"
dependencies:
@ -2545,6 +2545,15 @@ eslint-plugin-jsx-a11y@^6.0.2:
emoji-regex "^6.1.0"
jsx-ast-utils "^1.4.0"
eslint-plugin-node@^5.2.1:
version "5.2.1"
resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-5.2.1.tgz#80df3253c4d7901045ec87fa660a284e32bdca29"
dependencies:
ignore "^3.3.6"
minimatch "^3.0.4"
resolve "^1.3.3"
semver "5.3.0"
eslint-plugin-node@~4.2.2:
version "4.2.2"
resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-4.2.2.tgz#82959ca9aed79fcbd28bb1b188d05cac04fb3363"
@ -2555,6 +2564,10 @@ eslint-plugin-node@~4.2.2:
resolve "^1.1.7"
semver "5.3.0"
eslint-plugin-promise@^3.6.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-3.6.0.tgz#54b7658c8f454813dc2a870aff8152ec4969ba75"
eslint-plugin-promise@~3.5.0:
version "3.5.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-3.5.0.tgz#78fbb6ffe047201627569e85a6c5373af2a68fca"
@ -2585,7 +2598,7 @@ eslint-plugin-react@~6.10.0:
jsx-ast-utils "^1.3.4"
object.assign "^4.0.4"
eslint-plugin-standard@~3.0.1:
eslint-plugin-standard@^3.0.1, eslint-plugin-standard@~3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-3.0.1.tgz#34d0c915b45edc6f010393c7eef3823b08565cf2"
@ -3479,6 +3492,10 @@ html-element-attributes@^1.0.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/html-element-attributes/-/html-element-attributes-1.2.0.tgz#8b1c7aaf94353fd9b455c27ec7ebaf1583e29fd0"
html-element-attributes@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/html-element-attributes/-/html-element-attributes-1.3.0.tgz#f06ebdfce22de979db82020265cac541fb17d4fc"
html-encoding-sniffer@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz#e70d84b94da53aa375e11fe3a351be6642ca46f8"
@ -3612,6 +3629,10 @@ ignore@^3.3.3:
version "3.3.3"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.3.tgz#432352e57accd87ab3110e82d3fea0e47812156d"
ignore@^3.3.6:
version "3.3.7"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.7.tgz#612289bfb3c220e186a58118618d5be8c1bab021"
imurmurhash@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
@ -6113,6 +6134,12 @@ resolve@^1.1.6, resolve@^1.1.7, resolve@^1.2.0:
dependencies:
path-parse "^1.0.5"
resolve@^1.3.3:
version "1.5.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36"
dependencies:
path-parse "^1.0.5"
restore-cursor@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541"
@ -6322,6 +6349,10 @@ shellwords@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b"
shortid@^2.2.8:
version "2.2.8"
resolved "https://registry.yarnpkg.com/shortid/-/shortid-2.2.8.tgz#033b117d6a2e975804f6f0969dbe7d3d0b355131"
signal-exit@^3.0.0, signal-exit@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"

View File

@ -22,6 +22,7 @@ export default {
collapseOnDataChange: true,
freezeWhenExpanded: false,
sortable: true,
multiSort: true,
resizable: true,
filterable: false,
defaultSortDesc: false,
@ -29,12 +30,14 @@ export default {
defaultFiltered: [],
defaultResized: [],
defaultExpanded: {},
// eslint-disable-next-line no-unused-vars
defaultFilterMethod: (filter, row, column) => {
const id = filter.pivotId || filter.id
return row[id] !== undefined
? String(row[id]).startsWith(filter.value)
: true
},
// eslint-disable-next-line no-unused-vars
defaultSortMethod: (a, b, desc) => {
// force null and undefined to the bottom
a = a === null || a === undefined ? '' : a
@ -49,7 +52,8 @@ export default {
if (a < b) {
return -1
}
// returning 0, undefined or any falsey value will use subsequent sorts or the index as a tiebreaker
// returning 0, undefined or any falsey value will use subsequent sorts or
// the index as a tiebreaker
return 0
},
@ -176,24 +180,24 @@ export default {
TbodyComponent: _.makeTemplateComponent('rt-tbody', 'Tbody'),
TrGroupComponent: _.makeTemplateComponent('rt-tr-group', 'TrGroup'),
TrComponent: _.makeTemplateComponent('rt-tr', 'Tr'),
ThComponent: ({ toggleSort, className, children, ...rest }) => {
return (
<div
className={classnames(className, 'rt-th')}
onClick={e => {
toggleSort && toggleSort(e)
}}
{...rest}
>
{children}
</div>
)
},
ThComponent: ({ toggleSort, className, children, ...rest }) => (
<div
className={classnames(className, 'rt-th')}
onClick={e => (
toggleSort && toggleSort(e)
)}
role="button"
tabIndex={0}
{...rest}
>
{children}
</div>
),
TdComponent: _.makeTemplateComponent('rt-td', 'Td'),
TfootComponent: _.makeTemplateComponent('rt-tfoot', 'Tfoot'),
FilterComponent: ({ filter, onChange }) => (
<input
type='text'
type="text"
style={{
width: '100%',
}}
@ -215,6 +219,7 @@ export default {
const previewValues = subRows
.filter(d => typeof d[column.id] !== 'undefined')
.map((row, i) => (
// eslint-disable-next-line react/no-array-index-key
<span key={i}>
{row[column.id]}
{i < subRows.length - 1 ? ', ' : ''}
@ -236,7 +241,7 @@ export default {
className={classnames('-loading', { '-active': loading }, className)}
{...rest}
>
<div className='-loading-inner'>
<div className="-loading-inner">
{loadingText}
</div>
</div>

122
src/hoc/README.md Normal file
View File

@ -0,0 +1,122 @@
<div style="text-align:center;">
<a href="https://github.com/react-tools/react-table" target="\_parent"><img src="https://github.com/react-tools/media/raw/master/logo-react-table.png" alt="React Table Logo" style="width:450px;"/></a>
</div>
# ReactTable - expanding with HOCs
This documentation is about expanding ReactTable using Higher Order Components/Functions.
## Covered in this README
- A Brief explanation of HOCs and why they are a good approach for ReactTable enhancements
- Documentation of the currently available HOCs
- TreeTable
- SelectTable
- Documentation of the standard for writing HOCs with ReactTable
## What are HOCs and why use them with ReactTable
HOCs (or Higher Order Components/Functions) are either a React Component (or a function that returns a React Component)
that are used to enhance the functionality of an existing component. How much you can enhance depends on the props that
the component exposes.
Fortunately, ReactTable exposes a LOT of functionality as props to the component. In some cases there are too many
props to keep track of and that is where HOCs come in.
You can write a HOC that just focusses on the additional functionality you want to enhance and keep those enhancements to
reuse over and over again when you need them. You don't have to edit the ReactSource code, just wrap ReactTable in one or
more HOCs (more on some issues related to chaining HOCs later) that provide the additional functionality you want to expose.
The most obvious HOC is one that can add `checkbox` or select functionality. The HOC included provides `select` functionality
that allows the developer to specify if they want a `checkbox` or `radio` style of select column. The implementation of the
selection is recorded (e.g. in component state, Redux, etc.) and how to manage multiple selections. The HOC really only handles
the rendering pieces.
But there is more documentation on the `select` HOC below.
## Currently Available HOCs
### TreeTable
TreeTable takes over the rendering of the generated pivot rows of ReactTable so that they appear more like an expandable Tree.
It accomplishes this by rendering a 100% wide div and then only rendering the cell that controls the pivot at that level.
Using it is as simple as doing the following:
```javascript
import ReactTable from 'react-table'
import treeTableHOC from 'react-table/lib/hoc/treeTable'
const TreeTable = treeTableHOC(ReactTable)
```
After you have done the above, you can then use `TreeTable` just as you would `ReactTable` but it will render pivots using
the Tree style described above.
### SelectTable
SelectTable is a little trickier. The HOCs attempt to avoid adding additional state and, as there is no internal ID for a row that
can be relied on to be static (ReactTable just reuses indexes when rendering) the developer has to maintain the state outside of even
the wrapped component. So it is largely based on callbacks.
You include the HOC in the same manner as you would for the treeTableHOC but then need to provide the following overrides:
- isSelected - returns `true` if the key passed is selected otherwise it should return `false`
- selectAll - a property that indicates if the selectAll is set (`true|false`)
- toggleAll - called when the user clicks the `selectAll` checkbox/radio
- toggleSelection - called when the use clicks a specific checkbox/radio in a row
- selectType - either `checkbox|radio` to indicate what type of selection is required
In the case of `radio` there is no `selectAll` displayed but the developer is responsible for only making one selection in
the controlling component's state. You could select multiple but it wouldn't make sense and you should use `checkbox` instead.
You also have to decide what `selectAll` means. Given ReactTable is a paged solution there are other records off-page. When someone
selects the `selectAll` checkbox, should it mark every possible record, only what might be visible to due a Filter or only those items
on the current page?
The example opts for the middle approach so it gets a `ref` to the ReactTable instance and pulls the `sortedData` out of the resolved
state (then walks through those records and pulls their ID into the `selection` state of the controlling component).
You can also replace the input component that is used to render the select box and select all box:
- SelectAllInputComponent - the checkbox in the top left corner
- SelectInputComponent - the checkbox used on a row
### SelectTreeTable
SelectTreeTable is a combination of TreeTable and SelectTable.
To function correctly the chain has to be in the correct order as follows (see the comments in the guid on HOCs below).
```Javascript
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.
## 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
still being developed).
Firstly, there are issues with `ref` when you write a HOC. Consider a deeply nested component wrapped in multiple HOCs...
A HOC in the middle of the chain requires access to the instance of the component it thinks it is wrapping but there is at
least one other wrapper in the way. The challenge is: How do I get to the actual wrapped component?
Each HOC is required to be a React Class so that a `ref` can be obtained against each component:
```Javascript
<Component ... ref={r => this.wrappedInstance = r} />
```
*NOTE:* "Component" can also be the `<ReactTable />` instance.
Then the following method needs
to be placed on the class so that it exposes the correct instance of ReactTable:
```Javascript
getWrappedInstance() {
if (!this.wrappedInstance) console.warn('<component name here> - No wrapped instance')
if (this.wrappedInstance.getWrappedInstance) return this.wrappedInstance.getWrappedInstance()
else return this.wrappedInstance
}
```
Essentially this will walk down the chain (if there are chained HOCs) and stop when it gets to the end and return the wrapped instance.
Finally, sometimes the chains need to be in a specific order to function correctly. It is not clear if this is just an architectural
issue or if it would be better solved using a library like `recompose`. Anyone who is able to contribute a reliable solution to this
is welcome to submit a PR.

View File

@ -0,0 +1,111 @@
/* eslint-disable */
import React from 'react';
const defaultSelectInputComponent = (props) => {
return (
<input
type={props.selectType || 'checkbox'}
checked={props.checked}
onClick={(e)=>{
const { shiftKey } = e;
e.stopPropagation();
props.onClick(props.id, shiftKey, props.row);
}}
onChange={()=>{}}
/>
)
}
export default (Component) => {
const wrapper = class RTSelectTable extends React.Component {
constructor(props)
{
super(props);
}
rowSelector(row) {
if(!row || !row.hasOwnProperty(this.props.keyField)) return null;
const { toggleSelection, selectType, keyField } = this.props;
const checked = this.props.isSelected(row[this.props.keyField]);
const inputProps =
{
checked,
onClick: toggleSelection,
selectType,
id: row[keyField],
row,
}
return React.createElement(this.props.SelectInputComponent,inputProps);
}
headSelector(row) {
const { selectType } = this.props;
if (selectType === 'radio') return null;
const { toggleAll, selectAll: checked, SelectAllInputComponent, } = this.props;
const inputProps =
{
checked,
onClick: toggleAll,
selectType,
}
return React.createElement(SelectAllInputComponent,inputProps);
}
// this is so we can expose the underlying ReactTable to get at the sortedData for selectAll
getWrappedInstance() {
if (!this.wrappedInstance) console.warn('RTSelectTable - No wrapped instance');
if (this.wrappedInstance.getWrappedInstance) return this.wrappedInstance.getWrappedInstance();
else return this.wrappedInstance
}
render()
{
const {
columns:originalCols, isSelected, toggleSelection, toggleAll, keyField, selectAll,
selectType, SelectAllInputComponent, SelectInputComponent,
...rest
} = this.props;
const select = {
id: '_selector',
accessor: ()=>'x', // this value is not important
Header: this.headSelector.bind(this),
Cell: (ci) => { return this.rowSelector.bind(this)(ci.original); },
width: 30,
filterable: false,
sortable: false,
resizable: false,
style: { textAlign: 'center' },
}
const columns = [
select,
...originalCols,
];
const extra = {
columns,
};
return (
<Component {...rest} {...extra} ref={(r)=>this.wrappedInstance=r}/>
)
}
}
wrapper.displayName = 'RTSelectTable';
wrapper.defaultProps =
{
keyField: '_id',
isSelected: (key)=>{ console.log('No isSelected handler provided:',{key})},
selectAll: false,
toggleSelection: (key, shift, row)=>{ console.log('No toggleSelection handler provided:', { key, shift, row }) },
toggleAll: () => { console.log('No toggleAll handler provided.') },
selectType: 'check',
SelectInputComponent: defaultSelectInputComponent,
SelectAllInputComponent: defaultSelectInputComponent,
}
return wrapper;
}

View File

@ -0,0 +1,80 @@
/* eslint-disable */
import React from 'react'
export default (Component) => {
const wrapper = class RTTreeTable extends React.Component {
constructor(props)
{
super(props);
this.getWrappedInstance.bind(this);
this.TrComponent.bind(this);
this.getTrProps.bind(this);
}
// this is so we can expose the underlying ReactTable to get at the sortedData for selectAll
getWrappedInstance = () => {
if (!this.wrappedInstance) console.warn('RTTreeTable - No wrapped instance');
if (this.wrappedInstance.getWrappedInstance) return this.wrappedInstance.getWrappedInstance();
else return this.wrappedInstance
}
TrComponent = (props) => {
const {
ri,
...rest
} = props;
if(ri && ri.groupedByPivot) {
const cell = {...props.children[ri.level]};
cell.props.style.flex = 'unset';
cell.props.style.width = '100%';
cell.props.style.maxWidth = 'unset';
cell.props.style.paddingLeft = `${this.props.treeTableIndent*ri.level}px`;
// cell.props.style.backgroundColor = '#DDD';
cell.props.style.borderBottom = '1px solid rgba(128,128,128,0.2)';
return <div className={`rt-tr ${rest.className}`} style={rest.style}>{cell}</div>;
}
return <Component.defaultProps.TrComponent {...rest} />;
}
getTrProps = (state,ri,ci,instance) => {
return {ri};
}
render() {
const { columns, treeTableIndent, ...rest } = this.props;
const { TrComponent, getTrProps } = this;
const extra = {
columns: columns.map((col)=>{
let column = col;
if(rest.pivotBy && rest.pivotBy.includes(col.accessor))
{
column = {
accessor: col.accessor,
width: `${treeTableIndent}px`,
show: false,
Header: '',
}
}
return column;
}),
TrComponent,
getTrProps,
};
return (
<Component {...rest} {...extra} ref={ r => this.wrappedInstance=r }/>
)
}
}
wrapper.displayName = 'RTTreeTable';
wrapper.defaultProps =
{
treeTableIndent: 10,
}
return wrapper;
}

View File

@ -80,6 +80,7 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
loadingText,
noDataText,
sortable,
multiSort,
resizable,
filterable,
// Pivoting State
@ -141,27 +142,25 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
const hasColumnFooter = allVisibleColumns.some(d => d.Footer)
const hasFilters = filterable || allVisibleColumns.some(d => d.filterable)
const recurseRowsViewIndex = (rows, path = [], index = -1) => {
return [
rows.map((row, i) => {
index++
const rowWithViewIndex = {
...row,
_viewIndex: index,
}
const newPath = path.concat([i])
if (rowWithViewIndex[subRowsKey] && _.get(expanded, newPath)) {
;[rowWithViewIndex[subRowsKey], index] = recurseRowsViewIndex(
rowWithViewIndex[subRowsKey],
newPath,
index
)
}
return rowWithViewIndex
}),
index,
]
}
const recurseRowsViewIndex = (rows, path = [], index = -1) => ([
rows.map((row, i) => {
index += 1
const rowWithViewIndex = {
...row,
_viewIndex: index,
}
const newPath = path.concat([i])
if (rowWithViewIndex[subRowsKey] && _.get(expanded, newPath)) {
[rowWithViewIndex[subRowsKey], index] = recurseRowsViewIndex(
rowWithViewIndex[subRowsKey],
newPath,
index,
)
}
return rowWithViewIndex
}),
index,
])
;[pageRows] = recurseRowsViewIndex(pageRows)
const canPrevious = page > 0
@ -171,7 +170,7 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
allVisibleColumns.map(d => {
const resizedColumn = resized.find(x => x.id === d.id) || {}
return _.getFirstDefined(resizedColumn.value, d.width, d.minWidth)
})
}),
)
let rowIndex = -1
@ -189,59 +188,45 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
rowMinWidth,
}
// Visual Components
const rootProps = _.splitProps(
getProps(finalState, undefined, undefined, this),
)
const tableProps = _.splitProps(
getTableProps(finalState, undefined, undefined, this),
)
const tBodyProps = _.splitProps(
getTbodyProps(finalState, undefined, undefined, this),
)
const loadingProps = getLoadingProps(finalState, undefined, undefined, this)
const noDataProps = getNoDataProps(finalState, undefined, undefined, this)
const resizerProps = getResizerProps(finalState, undefined, undefined, this)
const makeHeaderGroups = () => {
const theadGroupProps = _.splitProps(
getTheadGroupProps(finalState, undefined, undefined, this)
)
const theadGroupTrProps = _.splitProps(
getTheadGroupTrProps(finalState, undefined, undefined, this)
)
return (
<TheadComponent
className={classnames('-headerGroups', theadGroupProps.className)}
style={{
...theadGroupProps.style,
minWidth: `${rowMinWidth}px`,
}}
{...theadGroupProps.rest}
>
<TrComponent
className={theadGroupTrProps.className}
style={theadGroupTrProps.style}
{...theadGroupTrProps.rest}
>
{headerGroups.map(makeHeaderGroup)}
</TrComponent>
</TheadComponent>
)
}
// Visual Components
const makeHeaderGroup = (column, i) => {
const resizedValue = col =>
(resized.find(x => x.id === col.id) || {}).value
const flex = _.sum(
column.columns.map(
col => (col.width || resizedValue(col) ? 0 : col.minWidth)
)
col => (col.width || resizedValue(col) ? 0 : col.minWidth),
),
)
const width = _.sum(
column.columns.map(col =>
_.getFirstDefined(resizedValue(col), col.width, col.minWidth)
)
_.getFirstDefined(resizedValue(col), col.width, col.minWidth),
),
)
const maxWidth = _.sum(
column.columns.map(col =>
_.getFirstDefined(resizedValue(col), col.width, col.maxWidth)
)
_.getFirstDefined(resizedValue(col), col.width, col.maxWidth),
),
)
const theadGroupThProps = _.splitProps(
getTheadGroupThProps(finalState, undefined, column, this)
getTheadGroupThProps(finalState, undefined, column, this),
)
const columnHeaderProps = _.splitProps(
column.getHeaderProps(finalState, undefined, column, this)
column.getHeaderProps(finalState, undefined, column, this),
)
const classes = [
@ -269,7 +254,7 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
return (
<ThComponent
key={i + '-' + column.id}
key={`${i}-${column.id}`}
className={classnames(classes)}
style={{
...styles,
@ -279,34 +264,34 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
>
{_.normalizeComponent(column.Header, {
data: sortedData,
column: column,
column,
})}
</ThComponent>
)
}
const makeHeaders = () => {
const theadProps = _.splitProps(
getTheadProps(finalState, undefined, undefined, this)
const makeHeaderGroups = () => {
const theadGroupProps = _.splitProps(
getTheadGroupProps(finalState, undefined, undefined, this),
)
const theadTrProps = _.splitProps(
getTheadTrProps(finalState, undefined, undefined, this)
const theadGroupTrProps = _.splitProps(
getTheadGroupTrProps(finalState, undefined, undefined, this),
)
return (
<TheadComponent
className={classnames('-header', theadProps.className)}
className={classnames('-headerGroups', theadGroupProps.className)}
style={{
...theadProps.style,
...theadGroupProps.style,
minWidth: `${rowMinWidth}px`,
}}
{...theadProps.rest}
{...theadGroupProps.rest}
>
<TrComponent
className={theadTrProps.className}
style={theadTrProps.style}
{...theadTrProps.rest}
className={theadGroupTrProps.className}
style={theadGroupTrProps.style}
{...theadGroupTrProps.rest}
>
{allVisibleColumns.map(makeHeader)}
{headerGroups.map(makeHeaderGroup)}
</TrComponent>
</TheadComponent>
)
@ -320,18 +305,18 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
const width = _.getFirstDefined(
resizedCol.value,
column.width,
column.minWidth
column.minWidth,
)
const maxWidth = _.getFirstDefined(
resizedCol.value,
column.width,
column.maxWidth
column.maxWidth,
)
const theadThProps = _.splitProps(
getTheadThProps(finalState, undefined, column, this)
getTheadThProps(finalState, undefined, column, this),
)
const columnHeaderProps = _.splitProps(
column.getHeaderProps(finalState, undefined, column, this)
column.getHeaderProps(finalState, undefined, column, this),
)
const classes = [
@ -364,7 +349,7 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
return (
<ThComponent
key={i + '-' + column.id}
key={`${i}-${column.id}`}
className={classnames(
classes,
isResizable && 'rt-resizable-header',
@ -373,7 +358,7 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
!show && '-hidden',
pivotBy &&
pivotBy.slice(0, -1).includes(column.id) &&
'rt-header-pivot'
'rt-header-pivot',
)}
style={{
...styles,
@ -382,14 +367,14 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
maxWidth: _.asPx(maxWidth),
}}
toggleSort={e => {
isSortable && this.sortColumn(column, e.shiftKey)
if (isSortable) this.sortColumn(column, multiSort ? e.shiftKey : false)
}}
{...rest}
>
<div className={classnames(isResizable && 'rt-resizable-header-content')}>
{_.normalizeComponent(column.Header, {
data: sortedData,
column: column,
column,
})}
</div>
{resizer}
@ -397,28 +382,28 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
)
}
const makeFilters = () => {
const theadFilterProps = _.splitProps(
getTheadFilterProps(finalState, undefined, undefined, this)
const makeHeaders = () => {
const theadProps = _.splitProps(
getTheadProps(finalState, undefined, undefined, this),
)
const theadFilterTrProps = _.splitProps(
getTheadFilterTrProps(finalState, undefined, undefined, this)
const theadTrProps = _.splitProps(
getTheadTrProps(finalState, undefined, undefined, this),
)
return (
<TheadComponent
className={classnames('-filters', theadFilterProps.className)}
className={classnames('-header', theadProps.className)}
style={{
...theadFilterProps.style,
...theadProps.style,
minWidth: `${rowMinWidth}px`,
}}
{...theadFilterProps.rest}
{...theadProps.rest}
>
<TrComponent
className={theadFilterTrProps.className}
style={theadFilterTrProps.style}
{...theadFilterTrProps.rest}
className={theadTrProps.className}
style={theadTrProps.style}
{...theadTrProps.rest}
>
{allVisibleColumns.map(makeFilter)}
{allVisibleColumns.map(makeHeader)}
</TrComponent>
</TheadComponent>
)
@ -429,18 +414,18 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
const width = _.getFirstDefined(
resizedCol.value,
column.width,
column.minWidth
column.minWidth,
)
const maxWidth = _.getFirstDefined(
resizedCol.value,
column.width,
column.maxWidth
column.maxWidth,
)
const theadFilterThProps = _.splitProps(
getTheadFilterThProps(finalState, undefined, column, this)
getTheadFilterThProps(finalState, undefined, column, this),
)
const columnHeaderProps = _.splitProps(
column.getHeaderProps(finalState, undefined, column, this)
column.getHeaderProps(finalState, undefined, column, this),
)
const classes = [
@ -467,12 +452,12 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
const isFilterable = _.getFirstDefined(
column.filterable,
filterable,
false
false,
)
return (
<ThComponent
key={i + '-' + column.id}
key={`${i}-${column.id}`}
className={classnames(classes)}
style={{
...styles,
@ -490,21 +475,48 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
filter,
onChange: value => this.filterColumn(column, value),
},
defaultProps.column.Filter
defaultProps.column.Filter,
)
: null}
</ThComponent>
)
}
const makeFilters = () => {
const theadFilterProps = _.splitProps(
getTheadFilterProps(finalState, undefined, undefined, this),
)
const theadFilterTrProps = _.splitProps(
getTheadFilterTrProps(finalState, undefined, undefined, this),
)
return (
<TheadComponent
className={classnames('-filters', theadFilterProps.className)}
style={{
...theadFilterProps.style,
minWidth: `${rowMinWidth}px`,
}}
{...theadFilterProps.rest}
>
<TrComponent
className={theadFilterTrProps.className}
style={theadFilterTrProps.style}
{...theadFilterTrProps.rest}
>
{allVisibleColumns.map(makeFilter)}
</TrComponent>
</TheadComponent>
)
}
const makePageRow = (row, i, path = []) => {
const rowInfo = {
original: row[originalKey],
row: row,
row,
index: row[indexKey],
viewIndex: ++rowIndex,
pageSize: pageSize,
page: page,
viewIndex: rowIndex += 1,
pageSize,
page,
level: path.length,
nestingPath: path.concat([i]),
aggregated: row[aggregatedKey],
@ -514,14 +526,14 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
const isExpanded = _.get(expanded, rowInfo.nestingPath)
const trGroupProps = getTrGroupProps(finalState, rowInfo, undefined, this)
const trProps = _.splitProps(
getTrProps(finalState, rowInfo, undefined, this)
getTrProps(finalState, rowInfo, undefined, this),
)
return (
<TrGroupComponent key={rowInfo.nestingPath.join('_')} {...trGroupProps}>
<TrComponent
className={classnames(
trProps.className,
row._viewIndex % 2 ? '-even' : '-odd'
row._viewIndex % 2 ? '-even' : '-odd',
)}
style={trProps.style}
{...trProps.rest}
@ -533,18 +545,18 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
const width = _.getFirstDefined(
resizedCol.value,
column.width,
column.minWidth
column.minWidth,
)
const maxWidth = _.getFirstDefined(
resizedCol.value,
column.width,
column.maxWidth
column.maxWidth,
)
const tdProps = _.splitProps(
getTdProps(finalState, rowInfo, column, this)
getTdProps(finalState, rowInfo, column, this),
)
const columnProps = _.splitProps(
column.getProps(finalState, rowInfo, column, this)
column.getProps(finalState, rowInfo, column, this),
)
const classes = [
@ -594,10 +606,10 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
{
expanded: newExpanded,
},
() => {
() => (
onExpandedChange &&
onExpandedChange(newExpanded, cellInfo.nestingPath, e)
}
),
)
}
@ -605,7 +617,7 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
let resolvedCell = _.normalizeComponent(
column.Cell,
cellInfo,
value
value,
)
// Resolve Renderers
@ -632,7 +644,8 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
// Make it expandable by defualt
cellInfo.expandable = true
useOnExpanderClick = true
// If pivoted, has no subRows, and does not have a subComponent, do not make expandable
// If pivoted, has no subRows, and does not have a subComponent,
// do not make expandable
if (cellInfo.pivoted && !cellInfo.subRows && !SubComponent) {
cellInfo.expandable = false
}
@ -655,14 +668,14 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
...cellInfo,
value: row[pivotValKey],
},
row[pivotValKey]
row[pivotValKey],
)
} else if (isPreview) {
// Show the pivot preview
resolvedCell = _.normalizeComponent(
ResolvedAggregatedComponent,
cellInfo,
value
value,
)
} else {
resolvedCell = null
@ -671,7 +684,7 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
resolvedCell = _.normalizeComponent(
ResolvedAggregatedComponent,
cellInfo,
value
value,
)
}
@ -679,7 +692,7 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
resolvedCell = _.normalizeComponent(
ResolvedExpanderComponent,
cellInfo,
row[pivotValKey]
row[pivotValKey],
)
if (pivotBy) {
if (cellInfo.groupedByPivot) {
@ -695,7 +708,9 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
? onExpanderClick
: () => {}
// If there are multiple onClick events, make sure they don't override eachother. This should maybe be expanded to handle all function attributes
// If there are multiple onClick events, make sure they don't
// override eachother. This should maybe be expanded to handle all
// function attributes
const interactionProps = {
onClick: resolvedOnExpanderClick,
}
@ -715,12 +730,13 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
// Return the cell
return (
<TdComponent
key={i2 + '-' + column.id}
// eslint-disable-next-line react/no-array-index-key
key={`${i2}-${column.id}`}
className={classnames(
classes,
!show && 'hidden',
cellInfo.expandable && 'rt-expandable',
(isBranch || isPreview) && 'rt-pivot'
(isBranch || isPreview) && 'rt-pivot',
)}
style={{
...styles,
@ -740,7 +756,7 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
{rowInfo.subRows &&
isExpanded &&
rowInfo.subRows.map((d, i) =>
makePageRow(d, i, rowInfo.nestingPath)
makePageRow(d, i, rowInfo.nestingPath),
)}
{SubComponent &&
!rowInfo.subRows &&
@ -750,52 +766,26 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
)
}
const makePadRow = (row, i) => {
const trGroupProps = getTrGroupProps(
finalState,
undefined,
undefined,
this
)
const trProps = _.splitProps(
getTrProps(finalState, undefined, undefined, this)
)
return (
<TrGroupComponent key={i} {...trGroupProps}>
<TrComponent
className={classnames(
'-padRow',
(pageRows.length + i) % 2 ? '-even' : '-odd',
trProps.className
)}
style={trProps.style || {}}
>
{allVisibleColumns.map(makePadColumn)}
</TrComponent>
</TrGroupComponent>
)
}
const makePadColumn = (column, i) => {
const resizedCol = resized.find(x => x.id === column.id) || {}
const show =
typeof column.show === 'function' ? column.show() : column.show
let width = _.getFirstDefined(
const width = _.getFirstDefined(
resizedCol.value,
column.width,
column.minWidth
column.minWidth,
)
let flex = width
let maxWidth = _.getFirstDefined(
const flex = width
const maxWidth = _.getFirstDefined(
resizedCol.value,
column.width,
column.maxWidth
column.maxWidth,
)
const tdProps = _.splitProps(
getTdProps(finalState, undefined, column, this)
getTdProps(finalState, undefined, column, this),
)
const columnProps = _.splitProps(
column.getProps(finalState, undefined, column, this)
column.getProps(finalState, undefined, column, this),
)
const classes = [
@ -812,7 +802,7 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
return (
<TdComponent
key={i + '-' + column.id}
key={`${i}-${column.id}`}
className={classnames(classes, !show && 'hidden')}
style={{
...styles,
@ -827,10 +817,96 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
)
}
const makePadRow = (row, i) => {
const trGroupProps = getTrGroupProps(
finalState,
undefined,
undefined,
this,
)
const trProps = _.splitProps(
getTrProps(finalState, undefined, undefined, this),
)
return (
<TrGroupComponent key={i} {...trGroupProps}>
<TrComponent
className={classnames(
'-padRow',
(pageRows.length + i) % 2 ? '-even' : '-odd',
trProps.className,
)}
style={trProps.style || {}}
>
{allVisibleColumns.map(makePadColumn)}
</TrComponent>
</TrGroupComponent>
)
}
const makeColumnFooter = (column, i) => {
const resizedCol = resized.find(x => x.id === column.id) || {}
const show =
typeof column.show === 'function' ? column.show() : column.show
const width = _.getFirstDefined(
resizedCol.value,
column.width,
column.minWidth,
)
const maxWidth = _.getFirstDefined(
resizedCol.value,
column.width,
column.maxWidth,
)
const tFootTdProps = _.splitProps(
getTfootTdProps(finalState, undefined, undefined, this),
)
const columnProps = _.splitProps(
column.getProps(finalState, undefined, column, this),
)
const columnFooterProps = _.splitProps(
column.getFooterProps(finalState, undefined, column, this),
)
const classes = [
tFootTdProps.className,
column.className,
columnProps.className,
columnFooterProps.className,
]
const styles = {
...tFootTdProps.style,
...column.style,
...columnProps.style,
...columnFooterProps.style,
}
return (
<TdComponent
key={`${i}-${column.id}`}
className={classnames(classes, !show && 'hidden')}
style={{
...styles,
flex: `${width} 0 auto`,
width: _.asPx(width),
maxWidth: _.asPx(maxWidth),
}}
{...columnProps.rest}
{...tFootTdProps.rest}
{...columnFooterProps.rest}
>
{_.normalizeComponent(column.Footer, {
data: sortedData,
column,
})}
</TdComponent>
)
}
const makeColumnFooters = () => {
const tFootProps = getTfootProps(finalState, undefined, undefined, this)
const tFootTrProps = _.splitProps(
getTfootTrProps(finalState, undefined, undefined, this)
getTfootTrProps(finalState, undefined, undefined, this),
)
return (
<TfootComponent
@ -852,69 +928,9 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
)
}
const makeColumnFooter = (column, i) => {
const resizedCol = resized.find(x => x.id === column.id) || {}
const show =
typeof column.show === 'function' ? column.show() : column.show
const width = _.getFirstDefined(
resizedCol.value,
column.width,
column.minWidth
)
const maxWidth = _.getFirstDefined(
resizedCol.value,
column.width,
column.maxWidth
)
const tFootTdProps = _.splitProps(
getTfootTdProps(finalState, undefined, undefined, this)
)
const columnProps = _.splitProps(
column.getProps(finalState, undefined, column, this)
)
const columnFooterProps = _.splitProps(
column.getFooterProps(finalState, undefined, column, this)
)
const classes = [
tFootTdProps.className,
column.className,
columnProps.className,
columnFooterProps.className,
]
const styles = {
...tFootTdProps.style,
...column.style,
...columnProps.style,
...columnFooterProps.style,
}
return (
<TdComponent
key={i + '-' + column.id}
className={classnames(classes, !show && 'hidden')}
style={{
...styles,
flex: `${width} 0 auto`,
width: _.asPx(width),
maxWidth: _.asPx(maxWidth),
}}
{...columnProps.rest}
{...tFootTdProps.rest}
{...columnFooterProps.rest}
>
{_.normalizeComponent(column.Footer, {
data: sortedData,
column: column,
})}
</TdComponent>
)
}
const makePagination = () => {
const paginationProps = _.splitProps(
getPaginationProps(finalState, undefined, undefined, this)
getPaginationProps(finalState, undefined, undefined, this),
)
return (
<PaginationComponent
@ -931,19 +947,6 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
)
}
const rootProps = _.splitProps(
getProps(finalState, undefined, undefined, this)
)
const tableProps = _.splitProps(
getTableProps(finalState, undefined, undefined, this)
)
const tBodyProps = _.splitProps(
getTbodyProps(finalState, undefined, undefined, this)
)
const loadingProps = getLoadingProps(finalState, undefined, undefined, this)
const noDataProps = getNoDataProps(finalState, undefined, undefined, this)
const resizerProps = getResizerProps(finalState, undefined, undefined, this)
const makeTable = () => {
const pagination = makePagination()
return (
@ -956,14 +959,14 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
{...rootProps.rest}
>
{showPagination && showPaginationTop
? <div className='pagination-top'>
? <div className="pagination-top">
{pagination}
</div>
: null}
<TableComponent
className={classnames(
tableProps.className,
currentlyResizing ? 'rt-resizing' : ''
currentlyResizing ? 'rt-resizing' : '',
)}
style={tableProps.style}
{...tableProps.rest}
@ -985,7 +988,7 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
{hasColumnFooter ? makeColumnFooters() : null}
</TableComponent>
{showPagination && showPaginationBottom
? <div className='pagination-bottom'>
? <div className="pagination-bottom">
{pagination}
</div>
: null}

View File

@ -64,7 +64,7 @@ export default Base =>
if (freezeWhenExpanded) {
// if any rows are expanded, freeze the existing data and sorting
const keys = Object.keys(newResolvedState.expanded)
for (var i = 0; i < keys.length; i++) {
for (let i = 0; i < keys.length; i += 1) {
if (newResolvedState.expanded[keys[i]]) {
newResolvedState.frozen = true
break
@ -109,18 +109,18 @@ export default Base =>
newResolvedState.pages = newResolvedState.manual
? newResolvedState.pages
: Math.ceil(
newResolvedState.sortedData.length / newResolvedState.pageSize
newResolvedState.sortedData.length / newResolvedState.pageSize,
)
newResolvedState.page = Math.max(
newResolvedState.page >= newResolvedState.pages
? newResolvedState.pages - 1
: newResolvedState.page,
0
0,
)
}
return this.setState(newResolvedState, () => {
cb && cb()
if (cb) { cb() }
if (
oldState.page !== newResolvedState.page ||
oldState.pageSize !== newResolvedState.pageSize ||

View File

@ -42,7 +42,7 @@ export default Base =>
let expanderColumn = columns.find(
col =>
col.expander ||
(col.columns && col.columns.some(col2 => col2.expander))
(col.columns && col.columns.some(col2 => col2.expander)),
)
// The actual expander might be in the columns field of a group column
if (expanderColumn && !expanderColumn.expander) {
@ -91,48 +91,48 @@ export default Base =>
if (dcol.accessor && !dcol.id) {
console.warn(dcol)
throw new Error(
'A column id is required if using a non-string accessor for column above.'
'A column id is required if using a non-string accessor for column above.',
)
}
// Fall back to an undefined accessor
if (!dcol.accessor) {
dcol.accessor = d => undefined
dcol.accessor = () => undefined
}
return dcol
}
const allDecoratedColumns = []
// Decorate the columns
const decorateAndAddToAll = (column, parentColumn) => {
const decoratedColumn = makeDecoratedColumn(column, parentColumn)
allDecoratedColumns.push(decoratedColumn)
return decoratedColumn
}
const allDecoratedColumns = []
const decoratedColumns = columnsWithExpander.map((column, i) => {
const decoratedColumns = columnsWithExpander.map(column => {
if (column.columns) {
return {
...column,
columns: column.columns.map(d => decorateAndAddToAll(d, column)),
}
} else {
return decorateAndAddToAll(column)
}
return decorateAndAddToAll(column)
})
// Build the visible columns, headers and flat column list
let visibleColumns = decoratedColumns.slice()
let allVisibleColumns = []
visibleColumns = visibleColumns.map((column, i) => {
visibleColumns = visibleColumns.map(column => {
if (column.columns) {
const visibleSubColumns = column.columns.filter(
d =>
pivotBy.indexOf(d.id) > -1
? false
: _.getFirstDefined(d.show, true)
)
const visibleSubColumns = column.columns.filter(d => (
pivotBy.indexOf(d.id) > -1
? false
: _.getFirstDefined(d.show, true)
))
return {
...column,
columns: visibleSubColumns,
@ -141,13 +141,13 @@ export default Base =>
return column
})
visibleColumns = visibleColumns.filter(column => {
return column.columns
visibleColumns = visibleColumns.filter(column => (
column.columns
? column.columns.length
: pivotBy.indexOf(column.id) > -1
? false
: _.getFirstDefined(column.show, true)
})
))
// Find any custom pivot location
const pivotIndex = visibleColumns.findIndex(col => col.pivot)
@ -163,10 +163,10 @@ export default Base =>
}
})
let PivotParentColumn = pivotColumns.reduce(
const PivotParentColumn = pivotColumns.reduce(
(prev, current) =>
prev && prev === current.parentColumn && current.parentColumn,
pivotColumns[0].parentColumn
pivotColumns[0].parentColumn,
)
let PivotGroupHeader = hasHeaderGroups && PivotParentColumn.Header
@ -202,13 +202,13 @@ export default Base =>
headerGroups.push({
...this.props.column,
...column,
columns: columns,
columns,
})
currentSpan = []
}
// Build flast list of allVisibleColumns and HeaderGroups
visibleColumns.forEach((column, i) => {
visibleColumns.forEach(column => {
if (column.columns) {
allVisibleColumns = allVisibleColumns.concat(column.columns)
if (currentSpan.length > 0) {
@ -238,13 +238,18 @@ export default Base =>
})
if (row[subRowsKey]) {
row[subRowsKey] = row[subRowsKey].map((d, i) =>
accessRow(d, i, level + 1)
accessRow(d, i, level + 1),
)
}
return row
}
let resolvedData = data.map((d, i) => accessRow(d, i))
// TODO: Make it possible to fabricate nested rows without pivoting
const aggregatingColumns = allVisibleColumns.filter(
d => !d.expander && d.aggregate,
)
// If pivoting, recursively group the data
const aggregate = rows => {
const aggregationValues = {}
@ -254,11 +259,6 @@ export default Base =>
})
return aggregationValues
}
// TODO: Make it possible to fabricate nested rows without pivoting
const aggregatingColumns = allVisibleColumns.filter(
d => !d.expander && d.aggregate
)
if (pivotBy.length) {
const groupRecursively = (rows, keys, i = 0) => {
// This is the last level, just return the rows
@ -267,20 +267,18 @@ export default Base =>
}
// Group the rows together for this level
let groupedRows = Object.entries(
_.groupBy(rows, keys[i])
).map(([key, value]) => {
return {
[pivotIDKey]: keys[i],
[pivotValKey]: key,
[keys[i]]: key,
[subRowsKey]: value,
[nestingLevelKey]: i,
[groupedByPivotKey]: true,
}
})
_.groupBy(rows, keys[i]),
).map(([key, value]) => ({
[pivotIDKey]: keys[i],
[pivotValKey]: key,
[keys[i]]: key,
[subRowsKey]: value,
[nestingLevelKey]: i,
[groupedByPivotKey]: true,
}))
// Recurse into the subRows
groupedRows = groupedRows.map(rowGroup => {
let subRows = groupRecursively(rowGroup[subRowsKey], keys, i + 1)
const subRows = groupRecursively(rowGroup[subRowsKey], keys, i + 1)
return {
...rowGroup,
[subRowsKey]: subRows,
@ -329,10 +327,10 @@ export default Base =>
resolvedData,
filtered,
defaultFilterMethod,
allVisibleColumns
allVisibleColumns,
),
sorted,
sortMethodsByColumnID
sortMethodsByColumnID,
),
}
}
@ -366,11 +364,10 @@ export default Base =>
// If 'filterAll' is set to true, pass the entire dataset to the filter method
if (column.filterAll) {
return filterMethod(nextFilter, filteredSoFar, column)
} else {
return filteredSoFar.filter(row => {
return filterMethod(nextFilter, row, column)
})
}
return filteredSoFar.filter(row => (
filterMethod(nextFilter, row, column)
))
}, filteredData)
// Apply the filter to the subrows if we are pivoting, and then
@ -386,7 +383,7 @@ export default Base =>
row[this.props.subRowsKey],
filtered,
defaultFilterMethod,
allVisibleColumns
allVisibleColumns,
),
}
})
@ -411,16 +408,16 @@ export default Base =>
sorted.map(sort => {
// Support custom sorting methods for each column
if (sortMethodsByColumnID[sort.id]) {
return (a, b) => {
return sortMethodsByColumnID[sort.id](a[sort.id], b[sort.id], sort.desc)
}
}
return (a, b) => {
return this.props.defaultSortMethod(a[sort.id], b[sort.id], sort.desc)
return (a, b) => (
sortMethodsByColumnID[sort.id](a[sort.id], b[sort.id], sort.desc)
)
}
return (a, b) => (
this.props.defaultSortMethod(a[sort.id], b[sort.id], sort.desc)
)
}),
sorted.map(d => !d.desc),
this.props.indexKey
this.props.indexKey,
)
sortedData.forEach(row => {
@ -430,7 +427,7 @@ export default Base =>
row[this.props.subRowsKey] = this.sortData(
row[this.props.subRowsKey],
sorted,
sortMethodsByColumnID
sortMethodsByColumnID,
)
})
@ -440,7 +437,7 @@ export default Base =>
getMinRows () {
return _.getFirstDefined(
this.props.minRows,
this.getStateOrProp('pageSize')
this.getStateOrProp('pageSize'),
)
}
@ -452,9 +449,9 @@ export default Base =>
if (collapseOnPageChange) {
newState.expanded = {}
}
this.setStateWithData(newState, () => {
this.setStateWithData(newState, () => (
onPageChange && onPageChange(page)
})
))
}
onPageSizeChange (newPageSize) {
@ -470,16 +467,16 @@ export default Base =>
pageSize: newPageSize,
page: newPage,
},
() => {
() => (
onPageSizeChange && onPageSizeChange(newPageSize, newPage)
}
),
)
}
sortColumn (column, additive) {
const { sorted, skipNextSort, defaultSortDesc } = this.getResolvedState()
const firstSortDirection = column.hasOwnProperty('defaultSortDesc')
const firstSortDirection = Object.prototype.hasOwnProperty.call(column, 'defaultSortDesc')
? column.defaultSortDesc
: defaultSortDesc
const secondSortDirection = !firstSortDirection
@ -519,20 +516,18 @@ export default Base =>
newSorted = [existing]
}
}
} else if (additive) {
newSorted.push({
id: column.id,
desc: firstSortDirection,
})
} else {
if (additive) {
newSorted.push({
newSorted = [
{
id: column.id,
desc: firstSortDirection,
})
} else {
newSorted = [
{
id: column.id,
desc: firstSortDirection,
},
]
}
},
]
}
} else {
// Multi-Sort
@ -556,21 +551,19 @@ export default Base =>
if (!additive) {
newSorted = newSorted.slice(existingIndex, column.length)
}
} else {
// New Sort Column
if (additive) {
newSorted = newSorted.concat(
column.map(d => ({
id: d.id,
desc: firstSortDirection,
}))
)
} else {
newSorted = column.map(d => ({
// New Sort Column
} else if (additive) {
newSorted = newSorted.concat(
column.map(d => ({
id: d.id,
desc: firstSortDirection,
}))
}
})),
)
} else {
newSorted = column.map(d => ({
id: d.id,
desc: firstSortDirection,
}))
}
}
@ -582,9 +575,9 @@ export default Base =>
: this.state.page,
sorted: newSorted,
},
() => {
() => (
onSortedChange && onSortedChange(newSorted, column, additive)
}
),
)
}
@ -593,16 +586,14 @@ export default Base =>
const { onFilteredChange } = this.props
// Remove old filter first if it exists
const newFiltering = (filtered || []).filter(x => {
if (x.id !== column.id) {
return true
}
})
const newFiltering = (filtered || []).filter(x => (
x.id !== column.id
))
if (value !== '') {
newFiltering.push({
id: column.id,
value: value,
value,
})
}
@ -610,9 +601,9 @@ export default Base =>
{
filtered: newFiltering,
},
() => {
() => (
onFilteredChange && onFilteredChange(newFiltering, column, value)
}
),
)
}
@ -634,7 +625,7 @@ export default Base =>
currentlyResizing: {
id: column.id,
startX: pageX,
parentWidth: parentWidth,
parentWidth,
},
},
() => {
@ -647,7 +638,7 @@ export default Base =>
document.addEventListener('mouseup', this.resizeColumnEnd)
document.addEventListener('mouseleave', this.resizeColumnEnd)
}
}
},
)
}
@ -667,10 +658,11 @@ export default Base =>
pageX = event.pageX
}
// Set the min size to 10 to account for margin and border or else the group headers don't line up correctly
// Set the min size to 10 to account for margin and border or else the
// group headers don't line up correctly
const newWidth = Math.max(
currentlyResizing.parentWidth + pageX - currentlyResizing.startX,
11
11,
)
newResized.push({
@ -682,15 +674,15 @@ export default Base =>
{
resized: newResized,
},
() => {
() => (
onResizedChange && onResizedChange(newResized, event)
}
),
)
}
resizeColumnEnd (event) {
event.stopPropagation()
let isTouch = event.type === 'touchend' || event.type === 'touchcancel'
const isTouch = event.type === 'touchend' || event.type === 'touchcancel'
if (isTouch) {
document.removeEventListener('touchmove', this.resizeColumnMoving)

View File

@ -4,7 +4,7 @@ import classnames from 'classnames'
// import _ from './utils'
const defaultButton = props => (
<button type='button' {...props} className='-btn'>
<button type="button" {...props} className="-btn">
{props.children}
</button>
)
@ -42,7 +42,7 @@ export default class ReactTablePagination extends Component {
}
applyPage (e) {
e && e.preventDefault()
if (e) { e.preventDefault() }
const page = this.state.page
this.changePage(page === '' ? this.props.page : page)
}
@ -70,9 +70,9 @@ export default class ReactTablePagination extends Component {
className={classnames(className, '-pagination')}
style={this.props.paginationStyle}
>
<div className='-previous'>
<div className="-previous">
<PreviousComponent
onClick={e => {
onClick={() => {
if (!canPrevious) return
this.changePage(page - 1)
}}
@ -81,11 +81,11 @@ export default class ReactTablePagination extends Component {
{this.props.previousText}
</PreviousComponent>
</div>
<div className='-center'>
<span className='-pageInfo'>
<div className="-center">
<span className="-pageInfo">
{this.props.pageText}{' '}
{showPageJump
? <div className='-pageJump'>
? <div className="-pageJump">
<input
type={this.state.page === '' ? 'text' : 'number'}
onChange={e => {
@ -105,31 +105,30 @@ export default class ReactTablePagination extends Component {
}}
/>
</div>
: <span className='-currentPage'>
: <span className="-currentPage">
{page + 1}
</span>}{' '}
{this.props.ofText}{' '}
<span className='-totalPages'>{pages || 1}</span>
<span className="-totalPages">{pages || 1}</span>
</span>
{showPageSizeOptions &&
<span className='select-wrap -pageSizeOptions'>
<span className="select-wrap -pageSizeOptions">
<select
onChange={e => onPageSizeChange(Number(e.target.value))}
value={pageSize}
>
{pageSizeOptions.map((option, i) => {
return (
<option key={i} value={option}>
{option} {this.props.rowsText}
</option>
)
})}
{pageSizeOptions.map((option, i) => (
// eslint-disable-next-line react/no-array-index-key
<option key={i} value={option}>
{option} {this.props.rowsText}
</option>
))}
</select>
</span>}
</div>
<div className='-next'>
<div className="-next">
<NextComponent
onClick={e => {
onClick={() => {
if (!canNext) return
this.changePage(page + 1)
}}

View File

@ -1,4 +1,4 @@
import PropTypes from "prop-types";
import PropTypes from 'prop-types'
export default {
// General
@ -85,37 +85,37 @@ export default {
Cell: PropTypes.oneOfType([
PropTypes.element,
PropTypes.string,
PropTypes.func
PropTypes.func,
]),
Header: PropTypes.oneOfType([
PropTypes.element,
PropTypes.string,
PropTypes.func
PropTypes.func,
]),
Footer: PropTypes.oneOfType([
PropTypes.element,
PropTypes.string,
PropTypes.func
PropTypes.func,
]),
Aggregated: PropTypes.oneOfType([
PropTypes.element,
PropTypes.string,
PropTypes.func
PropTypes.func,
]),
Pivot: PropTypes.oneOfType([
PropTypes.element,
PropTypes.string,
PropTypes.func
PropTypes.func,
]),
PivotValue: PropTypes.oneOfType([
PropTypes.element,
PropTypes.string,
PropTypes.func
PropTypes.func,
]),
Expander: PropTypes.oneOfType([
PropTypes.element,
PropTypes.string,
PropTypes.func
PropTypes.func,
]),
Filter: PropTypes.oneOfType([PropTypes.element, PropTypes.func]),
@ -145,8 +145,8 @@ export default {
getFooterProps: PropTypes.object,
filterMethod: PropTypes.func,
filterAll: PropTypes.bool,
sortMethod: PropTypes.func
})
sortMethod: PropTypes.func,
}),
),
// Global Expander Column Defaults
@ -154,7 +154,7 @@ export default {
sortable: PropTypes.bool,
resizable: PropTypes.bool,
filterable: PropTypes.bool,
width: PropTypes.number
width: PropTypes.number,
}),
pivotDefaults: PropTypes.object,
@ -181,7 +181,8 @@ export default {
ExpanderComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
PivotValueComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
AggregatedComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
PivotComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]), // this is a computed default generated using
// this is a computed default generated using
PivotComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
// the ExpanderComponent and PivotValueComponent at run-time in methods.js
PaginationComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
PreviousComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
@ -189,5 +190,5 @@ export default {
LoadingComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
NoDataComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
ResizerComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
PadRowComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element])
};
PadRowComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
}

View File

@ -30,7 +30,9 @@ function get (obj, path, def) {
let val
try {
val = pathObj.reduce((current, pathPart) => current[pathPart], obj)
} catch (e) {}
} catch (e) {
// continue regardless of error
}
return typeof val !== 'undefined' ? val : def
}
@ -59,7 +61,7 @@ function last (arr) {
function range (n) {
const arr = []
for (let i = 0; i < n; i++) {
for (let i = 0; i < n; i += 1) {
arr.push(n)
}
return arr
@ -67,7 +69,7 @@ function range (n) {
function orderBy (arr, funcs, dirs, indexKey) {
return arr.sort((rowA, rowB) => {
for (let i = 0; i < funcs.length; i++) {
for (let i = 0; i < funcs.length; i += 1) {
const comp = funcs[i]
const desc = dirs[i] === false || dirs[i] === 'desc'
const sortInt = comp(rowA, rowB)
@ -83,8 +85,8 @@ function orderBy (arr, funcs, dirs, indexKey) {
}
function remove (a, b) {
return a.filter(function (o, i) {
var r = b(o)
return a.filter((o, i) => {
const r = b(o)
if (r) {
a.splice(i, 1)
return true
@ -101,7 +103,7 @@ function clone (a) {
return value.toString()
}
return value
})
}),
)
} catch (e) {
return a
@ -109,7 +111,7 @@ function clone (a) {
}
function getFirstDefined (...args) {
for (var i = 0; i < args.length; i++) {
for (let i = 0; i < args.length; i += 1) {
if (typeof args[i] !== 'undefined') {
return args[i]
}
@ -117,9 +119,9 @@ function getFirstDefined (...args) {
}
function sum (arr) {
return arr.reduce((a, b) => {
return a + b
}, 0)
return arr.reduce((a, b) => (
a + b
), 0)
}
function makeTemplateComponent (compClass, displayName) {
@ -146,7 +148,7 @@ function groupBy (xs, key) {
function asPx (value) {
value = Number(value)
return Number.isNaN(value) ? null : value + 'px'
return Number.isNaN(value) ? null : `${value}px`
}
function isArray (a) {
@ -169,7 +171,7 @@ function flattenDeep (arr, newArr = []) {
if (!isArray(arr)) {
newArr.push(arr)
} else {
for (var i = 0; i < arr.length; i++) {
for (let i = 0; i < arr.length; i += 1) {
flattenDeep(arr[i], newArr)
}
}
@ -186,15 +188,16 @@ function splitProps ({ className, style, ...rest }) {
function compactObject (obj) {
const newObj = {}
for (var key in obj) {
Object.keys(obj).map(key => {
if (
obj.hasOwnProperty(key) &&
Object.prototype.hasOwnProperty.call(obj, key) &&
obj[key] !== undefined &&
typeof obj[key] !== 'undefined'
) {
newObj[key] = obj[key]
}
}
return true
})
return newObj
}