Compare commits

..
Author SHA1 Message Date
Aaron SchwartzandGitHub 44db30fe73 Fix source code in FixedHeader example 2017-06-26 10:51:52 -07:00
60 changed files with 3503 additions and 11694 deletions
+72 -1
View File
@@ -1,3 +1,74 @@
module.exports = {
extends: 'react-tools'
parserOptions: {
ecmaVersion: 8,
ecmaFeatures: {
experimentalObjectRestSpread: true,
jsx: true,
node: false
},
sourceType: 'module'
},
extends: ['standard'],
plugins: ['react'],
rules: {
// Nozzle
'jsx-quotes': [2, 'prefer-single'],
'comma-dangle': [2, 'always-multiline'],
// // React
'react/jsx-boolean-value': 2,
'react/jsx-curly-spacing': [2, 'never'],
'react/jsx-equals-spacing': [2, 'never'],
// 'react/jsx-indent': 2,
'react/jsx-indent-props': [2, 2],
'react/jsx-no-duplicate-props': 2,
'react/jsx-no-undef': 2,
'react/jsx-tag-spacing': [
2,
{
closingSlash: 'never',
beforeSelfClosing: 'always',
afterOpening: 'never'
}
],
'react/jsx-uses-react': 2,
'react/jsx-uses-vars': 2,
'react/self-closing-comp': 2,
'react/jsx-no-bind': [
2,
{
allowArrowFunctions: true,
allowBind: false,
ignoreRefs: true
}
],
'react/no-did-update-set-state': 2,
'react/no-unknown-property': 2,
'react/react-in-jsx-scope': 2,
'react/jsx-closing-bracket-location': [2, 'tag-aligned'],
'react/jsx-tag-spacing': [2, { beforeSelfClosing: 'always' }],
'react/jsx-wrap-multilines': 2,
'react/self-closing-comp': 2,
'react/jsx-key': 2,
'react/jsx-no-comment-textnodes': 2,
'react/jsx-no-duplicate-props': 2,
'react/jsx-no-target-blank': 2,
'react/jsx-no-undef': 2,
'react/jsx-uses-react': 2,
'react/jsx-uses-vars': 2,
'react/no-danger-with-children': 2,
'react/no-deprecated': 2,
'react/no-direct-mutation-state': 2,
'react/no-find-dom-node': 2,
'react/no-is-mounted': 2,
'react/no-render-return-value': 2,
'react/no-string-refs': 2,
'react/no-unknown-property': 2,
'react/react-in-jsx-scope': 2,
'react/require-render-return': 2
// 'react/jsx-max-props-per-line': [2, { maximum: 1 }]
}
}
-66
View File
@@ -1,69 +1,3 @@
## 6.7.5
#### Fixes & Optimizations
- Now passes `column` to `getResizerProps` (#667)
- NOTE: `getResizerProps` is now only called if the column is resizable
- Fixes the `className` ordering in defaultProps for ThComponent (#673)
- NOTE: user supplied classNames now come at the end so they can extend the defaults
## 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.
## 6.4.0
##### New Features
- `PadRowComponent` - the content rendered inside of a padding row. Defaults to a react component that renders ` `
+12 -11
View File
@@ -1,14 +1,15 @@
## What version of React-Table are you using?
Your bug may already be fixed in the latest release. Run `yarn upgrade react-table`!
Place your version here...
## Problem Description
include a detailed explanation of the problem here...
## What bug are you experiencing, or what feature are you proposing?
Please include a detailed explanation here...
## Code Snippet(s) or Codepen (http://codepen.io/tannerlinsley/pen/QpeZBa?editors=0010)
## Use https://codesandbox.io/s/X6npLXPRW (by clicking the "Fork" button) to reproduce the issue.
Then paste a link to your newly forked codesandbox here...
## What are the steps to reproduce the issue?
## Steps to Reproduce
1. list the steps
2. to reproduce
3. the issue
2. to reproduce the issue
## System Information
* **Browser & Browser Version:**
* **Node Version:**
* **OS Version:**
* **NPM Version:**
* **Yarn Version:**
+46 -71
View File
@@ -1,12 +1,16 @@
<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 align="center">
<a href="https://github.com/tannerlinsley/react-table" target="\_parent"><img src="https://github.com/tannerlinsley/react-table/raw/master/media/Banner.png" alt="React Table Logo" style="width:450px;"/></a>
<br />
<br />
</div>
# React Table
`react-table` is a **lightweight, fast and extendable datagrid** built for React
<a href="https://travis-ci.org/react-tools/react-table" target="\_parent">
<img alt="" src="https://travis-ci.org/react-tools/react-table.svg?branch=master" />
<a href="https://travis-ci.org/tannerlinsley/react-table" target="\_parent">
<img alt="" src="https://travis-ci.org/tannerlinsley/react-table.svg?branch=master" />
</a>
<a href="https://npmjs.com/package/react-table" target="\_parent">
<img alt="" src="https://img.shields.io/npm/dm/react-table.svg" />
@@ -14,8 +18,8 @@
<a href="https://react-chat-signup.herokuapp.com/" target="\_parent">
<img alt="" src="https://img.shields.io/badge/slack-react--chat-blue.svg" />
</a>
<a href="https://github.com/react-tools/react-table" target="\_parent">
<img alt="" src="https://img.shields.io/github/stars/react-tools/react-table.svg?style=social&label=Star" />
<a href="https://github.com/tannerlinsley/react-table" target="\_parent">
<img alt="" src="https://img.shields.io/github/stars/tannerlinsley/react-table.svg?style=social&label=Star" />
</a>
<a href="https://twitter.com/tannerlinsley" target="\_parent">
<img alt="" src="https://img.shields.io/twitter/follow/tannerlinsley.svg?style=social&label=Follow" />
@@ -24,29 +28,25 @@
<img alt="" src="https://img.shields.io/badge/%24-Donate-brightgreen.svg" />
</a>
<br />
<br />
## Versions
This document refers to version 6.x.x of react-table.
[![Sponsor](https://app.codesponsor.io/embed/zpmS8V9r31sBSCeVzP7Wm6Sr/react-tools/react-table.svg)](https://app.codesponsor.io/link/zpmS8V9r31sBSCeVzP7Wm6Sr/react-tools/react-table)
Previous versions:
[5.x.x Readme](https://github.com/tannerlinsley/react-table/blob/ad7d31cd3978eb45da7c6194dbab93c1e9a8594d/README.md)
## Features
- Lightweight at 11kb (and just 2kb more for styles)
- Fully customizable (JSX, templates, state, styles, callbacks)
- Client-side & Server-side pagination
- Multi-sort
- Filters
- Pivoting & Aggregation
- Lightweight at 7kb (and just 2kb more for styles)
- Fully customizable JSX templating
- Supports both Client-side & Server-side pagination and multi-sorting
- Column Pivoting & Aggregation
- Minimal design & easily themeable
- Fully controllable via optional props and callbacks
- <a href="https://medium.com/@tannerlinsley/why-i-wrote-react-table-and-the-problems-it-has-solved-for-nozzle-others-445c4e93d4a8#.axza4ixba" target="\_parent">"Why I wrote React Table and the problems it has solved for Nozzle.io"</a> by Tanner Linsley
- <a href="https://medium.com/@tannerlinsley/why-i-wrote-react-table-and-the-problems-it-has-solved-for-nozzle-others-445c4e93d4a8#.axza4ixba" target="\_parent">"Why I wrote React Table and the problems it has solved for Nozzle.io</a> by Tanner Linsley
## [Demos and examples](http://react-table.js.org/#/story/simple-table)
## Versions
- This documentation is for version 6 of react-table.
- [View the Changelog](https://github.com/react-tools/react-table/blob/master/CHANGELOG.md)
- Previous versions:
- [5.x.x Readme](https://github.com/react-tools/react-table/blob/ad7d31cd3978eb45da7c6194dbab93c1e9a8594d/README.md)
## Demos and examples
- <a href="http://codepen.io/tannerlinsley/pen/QpeZBa?editors=0010" target="\_blank">Codepen</a>
- <a href="http://react-table.js.org/#/story/simple-table" target="\_parent">Storybook</a>
## Table of Contents
- [Installation](#installation)
@@ -74,11 +74,7 @@
## Installation
1. Install React Table as a dependency
```bash
# Yarn
$ yarn add react-table
# NPM
$ npm install react-table
```
2. Import the `react-table` module
```javascript
@@ -171,7 +167,6 @@ 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,
@@ -183,7 +178,7 @@ These are all of the available props (and their default values) for the main `<R
const id = filter.pivotId || filter.id
return row[id] !== undefined ? String(row[id]).startsWith(filter.value) : true
},
defaultSortMethod: (a, b, desc) => {
defaultSortMethod: (a, b) => {
// force null and undefined to the bottom
a = (a === null || a === undefined) ? -Infinity : a
b = (b === null || b === undefined) ? -Infinity : b
@@ -292,7 +287,6 @@ These are all of the available props (and their default values) for the main `<R
footerClassName: '',
footerStyle: {},
getFooterProps: () => ({}),
filterAll: false,
filterMethod: undefined,
sortMethod: undefined,
defaultSortDesc: undefined,
@@ -313,7 +307,7 @@ These are all of the available props (and their default values) for the main `<R
previousText: 'Previous',
nextText: 'Next',
loadingText: 'Loading...',
noDataText: 'No rows found',
noDataText: 'No rows found',
pageText: 'Page',
ofText: 'of',
rowsText: 'rows',
@@ -343,7 +337,7 @@ Or just define them as props
```
## Columns
`<ReactTable />` requires a `columns` prop, which is an array of objects containing the following properties
`<ReactTable/>` requires a `columns` prop, which is an array of objects containing the following properties
```javascript
[{
@@ -358,7 +352,7 @@ Or just define them as props
Aggregated: JSX | String | Function // Used to render aggregated cells. Defaults to a comma separated list of values.
Pivot: JSX | String | Function | cellInfo => ( // Used to render a pivoted cell
<span>
<Expander /><PivotValue /> // By default, will utilize the the PivotValue and Expander components at run time
<Expander/><PivotValue /> // By default, will utilize the the PivotValue and Expander components at run time
</span>
),
PivotValue: JSX | String | Function // Used to render the value inside of a Pivot cell
@@ -403,11 +397,10 @@ Or just define them as props
getFooterProps: (state, rowInfo, column, instance) => ({}), // A function that returns props to decorate the `td` element of the column's footer
// Filtering
filterMethod: (filter, row || rows, column) => {return true}, // A function returning a boolean that specifies the filtering logic for the column
// 'filter' == an object specifying which filter is being applied. Format: {id: [the filter column's id], value: [the value the user typed in the filter field], pivotId: [if filtering on a pivot column, the pivotId will be set to the pivot column's id and the `id` field will be set to the top level pivoting column]}
// 'row' || 'rows' == the row (or rows, if filterAll is set to true) of data supplied to the table
// 'column' == the column that the filter is on
filterAll: false
filterMethod: (filter, row, column) => {return true}, // A function returning a boolean that specifies the filtering logic for the column
// filter == an object specifying which filter is being applied. Format: {id: [the filter column's id], value: [the value the user typed in the filter field], pivotId: [if filtering on a pivot column, the pivotId will be set to the pivot column's id and the `id` field will be set to the top level pivoting column]}
// row == the row of data supplied to the table
// column == the column that the filter is on
}]
```
@@ -480,7 +473,7 @@ If your data has a field/key with a dot (`.`) you will need to supply a custom a
## Column Header Groups
To group columns with another header column, just nest your columns in a header column. Header columns utilize the same header properties as regular columns.
To group columns with another header column, just nest your columns in a header column. Header columns utilize the same header properties as regular columns.
```javascript
const columns = [{
Header: 'Favorites',
@@ -491,7 +484,7 @@ const columns = [{
}, {
Header: 'Food',
accessor: 'favorites.food'
}, {
} {
Header: 'Actor',
accessor: 'favorites.actor'
}]
@@ -581,8 +574,6 @@ Every single built-in component's props can be dynamically extended using any on
/>
```
If used, **a callback prop must return an valid object**, even if it's an empty one.
These callbacks are executed with each render of the element with four parameters:
1. Table State
2. RowInfo (undefined if not applicable)
@@ -595,21 +586,12 @@ This makes it extremely easy to add, say... a row click callback!
<ReactTable
getTdProps={(state, rowInfo, column, instance) => {
return {
onClick: (e, handleOriginal) => {
onClick: e => {
console.log('A Td Element was clicked!')
console.log('it produced this event:', e)
console.log('It was in this column:', column)
console.log('It was in this row:', rowInfo)
console.log('It was in this table instance:', instance)
// IMPORTANT! React-Table uses onClick internally to trigger
// events like expanding SubComponents and pivots.
// By default a custom 'onClick' handler will override this functionality.
// If you want to fire the original onClick handler, call the
// 'handleOriginal' function.
if (handleOriginal) {
handleOriginal()
}
}
}
}}
@@ -742,7 +724,7 @@ If you want to handle pagination, sorting, and filtering on the server, `react-t
/>
```
For a detailed example, take a peek at our <a href="https://github.com/react-tools/react-table/blob/master/stories/ServerSide.js" target="\_parent">async table mockup</a>
For a detailed example, take a peek at our <a href="https://github.com/tannerlinsley/react-table/blob/master/stories/ServerSide.js" target="\_parent">async table mockup</a>
## Fully Controlled Component
React Table by default works fantastically out of the box, but you can achieve even more control and customization if you choose to maintain the state yourself. It is very easy to do, even if you only want to manage *parts* of the state.
@@ -760,7 +742,7 @@ Here are the props and their corresponding callbacks that control the state of t
id: 'firstName',
desc: true
}]}
expanded={{ // The nested row indexes on the current page that should appear expanded
expandedRows={{ // The nested row indexes on the current page that should appear expanded
1: true,
4: true,
5: {
@@ -768,11 +750,11 @@ Here are the props and their corresponding callbacks that control the state of t
3: true
}
}}
filtered={[{ // the current filters model
filters={[{ // the current filters model
id: 'lastName',
value: 'linsley'
}]}
resized={[{ // the current resized column model
resizing={[{ // the current resized column model
"id": "lastName",
"value": 446.25
}]}
@@ -781,8 +763,8 @@ Here are the props and their corresponding callbacks that control the state of t
onPageChange={(pageIndex) => {...}} // Called when the page index is changed by the user
onPageSizeChange={(pageSize, pageIndex) => {...}} // Called when the pageSize is changed by the user. The resolve page is also sent to maintain approximate position in the data
onSortedChange={(newSorted, column, shiftKey) => {...}} // Called when a sortable column header is clicked with the column itself and if the shiftkey was held. If the column is a pivoted column, `column` will be an array of columns
onExpandedChange={(newExpanded, index, event) => {...}} // Called when an expander is clicked. Use this to manage `expanded`
onFilteredChange={(column, value) => {...}} // Called when a user enters a value into a filter input field or the value passed to the onFiltersChange handler by the Filter option.
onExpandedChange={(newExpanded, index, event) => {...}} // Called when an expander is clicked. Use this to manage `expandedRows`
onFilteredChange={(column, value) => {...}} // Called when a user enters a value into a filter input field or the value passed to the onFiltersChange handler by the filterRender option.
onResizedChange={(newResized, event) => {...}} // Called when a user clicks on a resizing component (the right edge of a column header)
/>
```
@@ -834,9 +816,6 @@ 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.
@@ -845,9 +824,9 @@ To override the sorting algorithm for a single column, use the `sortMethod` colu
Supply a function that implements the native javascript [`Array.sort`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) interface. This is React Table's default sorting algorithm:
- `a` the first value to compare
- `b` the second value to compare
- `desc` true if sort is descending, false if ascending
- `dir` the
```javascript
defaultSortMethod = (a, b, desc) => {
defaultSortMethod = (a, b) => {
// force null and undefined to the bottom
a = (a === null || a === undefined) ? -Infinity : a
b = (b === null || b === undefined) ? -Infinity : b
@@ -875,11 +854,7 @@ By default the table tries to filter by checking if the row's value starts with
If you want to override a particular column's filtering method, you can set the `filterMethod` option on a column.
By default, `filterMethod` is passed a single row of data at a time, and you are responsible for returning `true` or `false`, indicating whether it should be shown.
Alternatively, you can set `filterAll` to `true`, and `filterMethod` will be passed the entire array of rows to be filtered, and you will then be responsible for returning the new filtered array. This is extremely handy when you need to utilize a utility like fuzzy matching that requires the entire array of items.
To completely override the filter that is shown, you can set the `Filter` column option. Using this option you can specify the JSX that is shown. The option is passed an `onChange` method which must be called with the the value that you want to pass to the `filterMethod` option whenever the filter has changed.
To completely override the filter that is shown, you can set the `Filter` column option. Using this option you can specify the JSX that is shown. The option is passed an `onChange` method which must be called with the the value that you wan't to pass to the `filterMethod` option whenever the filter has changed.
See <a href="http://react-table.js.org/#/story/custom-filtering" target="\_parent">Custom Filtering</a> demo for examples.
@@ -894,7 +869,7 @@ Object.assign(ReactTableDefaults, {
TbodyComponent: component,
TrGroupComponent: component,
TrComponent: component,
ThComponent: component,
ThComponent: component
TdComponent: component,
TfootComponent: component,
ExpanderComponent: component,
@@ -918,7 +893,7 @@ Object.assign(ReactTableDefaults, {
/>
```
If you choose to change the core components React-Table uses to render, you must make sure your replacement components consume and utilize all of the supplied and inherited props that are needed for that component to function properly. We would suggest investigating <a href="https://github.com/react-tools/react-table/blob/master/src/index.js" target="\_parent">the source</a> for the component you wish to replace.
If you choose to change the core components React-Table uses to render, you must make sure your replacement components consume and utilize all of the supplied and inherited props that are needed for that component to function properly. We would suggest investigating <a href="https://github.com/tannerlinsley/react-table/blob/master/src/index.js" target="\_parent">the source</a> for the component you wish to replace.
## Contributing
@@ -930,7 +905,7 @@ If you would like to help develop a suggested feature follow these steps:
- Auto-build files as you edit with `$ yarn run watch`
- Implement your changes to files in the `src/` directory
- Run the <a href="https://github.com/tannerlinsley/react-story">React Story</a> locally with `$ yarn run docs`
- View changes as you edit `docs/src`
- View changes as you edit `docs/src`,
- Submit PR for review
#### Scripts
-77
View File
@@ -1,77 +0,0 @@
module.exports = {
parserOptions: {
ecmaVersion: 8,
ecmaFeatures: {
experimentalObjectRestSpread: true,
jsx: true,
node: false,
classes: true
},
sourceType: 'module'
},
parser: 'babel-eslint',
extends: ['standard'],
plugins: ['react'],
rules: {
// Nozzle
'jsx-quotes': [2, 'prefer-single'],
'comma-dangle': [2, 'always-multiline'],
// // React
'react/jsx-boolean-value': 2,
'react/jsx-curly-spacing': [2, 'never'],
'react/jsx-equals-spacing': [2, 'never'],
// 'react/jsx-indent': 2,
'react/jsx-indent-props': [2, 2],
'react/jsx-no-duplicate-props': 2,
'react/jsx-no-undef': 2,
'react/jsx-tag-spacing': [
2,
{
closingSlash: 'never',
beforeSelfClosing: 'always',
afterOpening: 'never'
}
],
'react/jsx-uses-react': 2,
'react/jsx-uses-vars': 2,
'react/self-closing-comp': 2,
'react/jsx-no-bind': [
2,
{
allowArrowFunctions: true,
allowBind: false,
ignoreRefs: true
}
],
'react/no-did-update-set-state': 2,
'react/no-unknown-property': 2,
'react/react-in-jsx-scope': 2,
'react/jsx-closing-bracket-location': [0, 'tag-aligned'],
'react/jsx-tag-spacing': [2, { beforeSelfClosing: 'always' }],
'react/jsx-wrap-multilines': 2,
'react/self-closing-comp': 2,
'react/jsx-key': 2,
'react/jsx-no-comment-textnodes': 2,
'react/jsx-no-duplicate-props': 2,
'react/jsx-no-target-blank': 2,
'react/jsx-no-undef': 2,
'react/jsx-uses-react': 2,
'react/jsx-uses-vars': 2,
'react/no-danger-with-children': 2,
'react/no-deprecated': 2,
'react/no-direct-mutation-state': 2,
'react/no-find-dom-node': 2,
'react/no-is-mounted': 2,
'react/no-render-return-value': 2,
'react/no-string-refs': 2,
'react/no-unknown-property': 2,
'react/react-in-jsx-scope': 2,
'react/require-render-return': 2
// 'react/jsx-max-props-per-line': [2, { maximum: 1 }]
}
}
-1
View File
@@ -1 +0,0 @@
react-table.js.org
+3 -31
View File
@@ -3,35 +3,10 @@
"version": "0.1.0",
"private": true,
"devDependencies": {
"autoprefixer": "^6.7.0",
"babel-cli": "6.14.0",
"babel-eslint": "6.1.2",
"babel-preset-es2015": "6.14.0",
"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",
"postcss-cli": "^2.6.0",
"react": "^15.4.2",
"react-dom": "^15.4.2",
"react-json-tree": "^0.10.9",
"rimraf": "^2.6.1",
"standard": "^10.0.2",
"stylus": "^0.54.5"
"react-scripts": "0.9.5",
"standard": "^10.0.2"
},
"dependencies": {
"eslint-config-react-tools": "^1.0.10",
"github-markdown-css": "^2.6.0",
"marked": "^0.3.6",
"namor": "^1.0.1",
@@ -39,10 +14,7 @@
"react": "^15.5.4",
"react-dom": "^15.5.4",
"react-json-tree": "^0.10.9",
"react-script": "^2.0.5",
"react-scripts": "^0.9.5",
"react-story": "^0.0.10",
"shortid": "^2.2.8"
"react-story": "^0.0.10"
},
"scripts": {
"start": "react-scripts start",
File diff suppressed because it is too large Load Diff
+71 -77
View File
@@ -1,115 +1,109 @@
/* eslint-disable */
import React from 'react'
//
import ReactStory, { defaultProps } from 'react-story'
import CodeSandbox from './CodeSandbox.js'
import './stories/utils/prism.css'
import '../../react-table.css'
import Readme from './stories/Readme.js'
import HOCReadme from './stories/HOCReadme.js'
// import Test from './stories/test.js'
// import Tester from './examples/expander';
const stories = [
{ name: 'Readme', component: Readme },
{ name: 'HOC Readme', component: HOCReadme },
// { name: 'Tester', component: Test },
{ name: 'Simple Table', component: CodeSandbox('X6npLXPRW') },
{
name: 'Cell Renderers & Custom Components',
component: CodeSandbox('OyRL04Z4Y'),
},
{ name: 'Default Sorting', component: CodeSandbox('gLwmmjzA3') },
{
name: 'Custom Sorting',
component: CodeSandbox('VGx67J35'),
},
{ name: 'Custom Column Widths', component: CodeSandbox('o2OORXNXN') },
{ name: 'Custom Component Props', component: CodeSandbox('nZW3L0wp4') },
{ name: 'Server-side Data', component: CodeSandbox('wjrn8wy3R') },
{ name: 'Sub Components', component: CodeSandbox('n2gqAxl7') },
{ name: 'Pivoting & Aggregation', component: CodeSandbox('oNY9z8xN') },
{
name: 'Pivoting & Aggregation w/ Sub Components',
component: CodeSandbox('p0kEVBgQ'),
},
{
name: '100k Rows w/ Pivoting & Sub Components',
component: CodeSandbox('DRmKj0XyK'),
},
{ name: 'Pivoting Options', component: CodeSandbox('kZKmNBK6r') },
{ name: 'Functional Rendering', component: CodeSandbox('VPZ0Bzv8X') },
{
name: 'Custom Expander Position',
component: CodeSandbox('1jj2XrPEV'),
},
{ name: 'Custom "No Data" Text', component: CodeSandbox('RgRpRDv80') },
{ name: 'Footers', component: CodeSandbox('KOqQXn3p8') },
{ name: 'Custom Filtering', component: CodeSandbox('5Eyxxxyx') },
{ name: 'Controlled Component', component: CodeSandbox('r7XEZRK2') },
{ name: 'Editable Table', component: CodeSandbox('n5r19gzQP') },
{
name: 'Fixed Header w/ Vertical Scroll',
component: CodeSandbox('7LY0gjA8O'),
},
{
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') },
]
import Simple from './stories/Simple.js'
import CellRenderers from './stories/CellRenderers.js'
import DefaultSorting from './stories/DefaultSorting.js'
import CustomSorting from './stories/CustomSorting.js'
import CustomWidths from './stories/CustomWidths.js'
import CustomComponentProps from './stories/CustomComponentProps.js'
import ServerSide from './stories/ServerSide.js'
import SubComponents from './stories/SubComponents.js'
import Pivoting from './stories/Pivoting.js'
import PivotingSubComponents from './stories/PivotingSubComponents.js'
import OneHundredKRows from './stories/OneHundredKRows.js'
import FunctionalRendering from './stories/FunctionalRendering.js'
import CustomExpanderPosition from './stories/CustomExpanderPosition.js'
import NoDataText from './stories/NoDataText.js'
import Footers from './stories/Footers.js'
import Filtering from './stories/Filtering.js'
import ControlledTable from './stories/ControlledTable.js'
import PivotingOptions from './stories/PivotingOptions.js'
import EditableTable from './stories/EditableTable.js'
import FixedHeader from './stories/FixedHeader.js'
import MultiplePagers from './stories/MultiplePagers';
export default class App extends React.Component {
render () {
render() {
return (
<ReactStory
style={{
display: 'block',
width: '100%',
height: '100%',
height: '100%'
}}
pathPrefix='story/'
StoryWrapper={props =>
pathPrefix="story/"
StoryWrapper={props => (
<defaultProps.StoryWrapper
css={{
padding: 0,
display: 'flex',
flexDirection: 'column',
padding: 0
}}
>
<a
href='//github.com/react-tools/react-table'
href="//github.com/tannerlinsley/react-table"
style={{
display: 'block',
textAlign: 'center',
borderBottom: 'solid 3px #cccccc',
borderBottom: 'solid 3px #cccccc'
}}
>
<img
src='https://github.com/react-tools/media/raw/master/logo-react-table.png'
alt='React Table Logo'
src="//npmcdn.com/react-table/media/Banner.png"
alt="React Table Logo"
style={{
width: '150px',
padding: '10px',
width: '100px'
}}
/>
</a>
<div
{...props}
style={{
flex: '1 0 auto',
position: 'relative',
padding: '10px'
}}
/>
</defaultProps.StoryWrapper>}
stories={stories}
</defaultProps.StoryWrapper>
)}
stories={[
{ name: 'Readme', component: Readme },
{ name: 'Simple Table', component: Simple },
{
name: 'Cell Renderers & Custom Components',
component: CellRenderers
},
{ name: 'Default Sorting', component: DefaultSorting },
{ name: 'Custom Sorting', component: CustomSorting },
{ name: 'Custom Column Widths', component: CustomWidths },
{ name: 'Custom Component Props', component: CustomComponentProps },
{ name: 'Server-side Data', component: ServerSide },
{ name: 'Sub Components', component: SubComponents },
{ name: 'Pivoting & Aggregation', component: Pivoting },
{
name: 'Pivoting & Aggregation w/ Sub Components',
component: PivotingSubComponents
},
{
name: '100k Rows w/ Pivoting & Sub Components',
component: OneHundredKRows
},
{ name: 'Pivoting Options', component: PivotingOptions },
{ name: 'Functional Rendering', component: FunctionalRendering },
{
name: 'Custom Expander Position',
component: CustomExpanderPosition
},
{ name: 'Custom "No Data" Text', component: NoDataText },
{ name: 'Footers', component: Footers },
{ name: 'Custom Filtering', component: Filtering },
{ name: 'Controlled Component', component: ControlledTable },
{ name: 'Editable Table', component: EditableTable },
{ name: 'Fixed Header w/ Vertical Scroll', component: FixedHeader },
{ name: 'Multiple Pagers (Top and Bottom)', component: MultiplePagers}
]}
/>
)
}
-22
View File
@@ -1,22 +0,0 @@
import React from 'react'
export default id => () => {
return (
<iframe
src={`https://codesandbox.io/embed/${id}?autoresize=1&hidenavigation=1&view=${global.innerWidth <
1000
? 'preview'
: 'split'}`}
style={{
position: 'absolute',
top: 0,
left: 0,
width: `100%`,
height: `100%`,
border: 0,
overflow: `hidden`,
}}
sandbox='allow-modals allow-forms allow-popups allow-scripts allow-same-origin'
/>
)
}
-88
View File
@@ -1,88 +0,0 @@
import React from 'react';
export default (Component) => {
const wrapper = class RTCheckboxTable extends React.Component {
// we only need a Component so we can get the 'ref' - pure components can't get a 'ref'
rowSelector = (row) =>
{
if(!row || !row.hasOwnProperty(this.props.keyField)) return null;
const checked = this.props.isSelected(row[this.props.keyField]);
return (
<input
type='checkbox'
checked={checked}
onClick={(e)=>{
const { shiftKey } = e;
e.stopPropagation();
this.props.toggleSelection(row[this.props.keyField],shiftKey,row);
}}
onChange={()=>{}}
value=''
/>
);
}
headSelector = (row) =>
{
const checked = this.props.selectAll;
return (
<input
type='checkbox'
checked={checked}
onClick={(e)=>{
e.stopPropagation();
this.props.toggleAll();
}}
onChange={()=>{}}
value=''
/>
);
}
// this is so we can expose the underlying ReactTable to get at the sortedData for selectAll
getWrappedInstance = ()=>this.wrappedInstance
render()
{
const { columns:originalCols, isSelected, toggleSelection, toggleAll, keyField, selectAll, ...rest } = this.props;
const { rowSelector, headSelector, } = this;
const select = {
id: '_selector',
accessor: ()=>'x', // this value is not important
Header: headSelector,
Cell: (ci) => { return rowSelector(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 = 'RTCheckboxTable';
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.') },
}
return wrapper;
}
-160
View File
@@ -1,160 +0,0 @@
import React from 'react';
import shortid from 'shortid';
import ReactTable from '../../../../lib/index'
import '../../../../react-table.css'
import checkboxTableHOC from './checkboxHOC';
const CheckboxTable = checkboxTableHOC(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,
};
}
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
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.checkboxTable.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)=>{
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);
}
render(){
const { toggleSelection, toggleAll, isSelected, logSelection } = this;
const { data, columns, selectAll } = this.state;
const extraProps =
{
selectAll,
isSelected,
toggleAll,
toggleSelection,
}
return (
<div style={{ padding: '10px'}}>
<h1>react-table - Checkbox Table</h1>
<button onClick={logSelection}>Log Selection to Console</button>
{` (${this.state.selection.length}) selected`}
{
data?
<CheckboxTable
data={data}
columns={columns}
ref={(r)=>this.checkboxTable = r}
className="-striped -highlight"
{...extraProps}
/>
:null
}
</div>
);
}
}
// export default treeTableHOC(ComponentTest);
export default ComponentTest;
-61
View File
@@ -1,61 +0,0 @@
import React from 'react'
export default class ComponentTest extends React.component {
render () {
return <div>Bozo</div>
}
}
// import ReactTable from '../../../../lib/index'
// import '../../../../react-table.css'
//
// console.log('ReactTable:',ReactTable)
//
// 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}
// />
// )
// }
// }
-11
View File
@@ -1,11 +0,0 @@
/* eslint-disable */
import TreeTable from './treetable'
import SelectTable from './selecttable'
import SelectTreeTable from './selecttreetable'
export {
TreeTable,
SelectTable,
SelectTreeTable,
}
-174
View File
@@ -1,174 +0,0 @@
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;
-216
View File
@@ -1,216 +0,0 @@
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;
-80
View File
@@ -1,80 +0,0 @@
import React from 'react';
import ReactTable from '../../../../lib/index'
import '../../../../react-table.css'
import treeTableHOC from '../../../../lib/hoc/treeTable'
async function getData()
{
const result = await ( await fetch('/au_500_tree.json') ).json();
return result;
}
function getColumns(data,pivotBy)
{
const columns = [];
const sample = data[0];
for(let key in sample)
{
columns.push({
accessor: key,
Header: key,
})
}
return columns;
}
export class ComponentTest extends React.Component {
constructor(props) {
super(props);
this.state =
{
data: null,
columns: null,
pivotBy: null, // ["firstName", "lastName"],
};
}
componentDidMount()
{
getData().then((data)=>{
// console.log('cwm data:',data);
const pivotBy = ['state','post','city'];
const columns = getColumns(data,pivotBy);
// console.log('cwm cols:',columns);
this.setState({data,columns,pivotBy});
});
}
showState = ()=>
{
console.log('state:',this.reactTable.getResolvedState());
}
render(){
const { data, columns, pivotBy } = this.state;
const extraProps =
{
data,
columns,
pivotBy,
}
const TreeTable = treeTableHOC(ReactTable);
return (
<div style={{ padding: '10px'}}>
<h1>react-table - Tree Table</h1>
{
data?
<TreeTable
ref={(r)=>this.reactTable=r}
className="-striped -highlight"
defaultPageSize={5}
{...extraProps}
/>
:null
}
</div>
);
}
}
export default ComponentTest;
@@ -1,58 +0,0 @@
import React from 'react';
export default (Component) => {
const wrapper = (componentProps) => {
const 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 = `${componentProps.treeTableIndent*ri.level}px`;
cell.props.style.backgroundColor = '#DDD';
cell.props.style.borderBottom = '1px solid rgba(128,128,128,0.2)';
return <div {...rest}>{cell}</div>;
}
return <Component.defaultProps.TrComponent {...rest} />;
}
const getTrProps = (state,ri,ci,instance) => {
return {ri};
}
const { columns, ...rest } = componentProps;
const extra = {
columns: columns.map((col)=>{
let column = col;
if(rest.pivotBy && rest.pivotBy.includes(col.accessor))
{
column = {
accessor: col.accessor,
width: `${componentProps.treeTableIndent}px`,
show: false,
Header: '',
}
}
return column;
}),
TrComponent,
getTrProps,
};
return (
<Component {...rest} {...extra} />
)
}
wrapper.displayName = 'RTTreeTable';
wrapper.defaultProps =
{
treeTableRowBackground: '#EEE',
treeTableIndent: 10,
}
return wrapper;
}
-34
View File
@@ -1,34 +0,0 @@
import namor from "namor";
const range = len => {
const arr = [];
for (let i = 0; i < len; i++) {
arr.push(i);
}
return arr;
};
const newPerson = () => {
const statusChance = Math.random();
return {
firstName: namor.generate({ words: 1, numbers: 0 }),
lastName: namor.generate({ words: 1, numbers: 0 }),
age: Math.floor(Math.random() * 30),
visits: Math.floor(Math.random() * 100),
progress: Math.floor(Math.random() * 100),
status:
statusChance > 0.66
? "relationship"
: statusChance > 0.33 ? "complicated" : "single"
};
};
export function makeData(len = 5553) {
return range(len).map(d => {
return {
...newPerson(),
children: range(10).map(newPerson)
};
});
}
+109
View File
@@ -0,0 +1,109 @@
/* eslint-disable import/no-webpack-loader-syntax */
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import ReactTable from '../../../lib/index'
class Story extends React.PureComponent {
render () {
const data = _.map(_.range(5553), d => {
const statusChance = Math.random()
return {
firstName: namor.generate({ words: 1, numbers: 0 }),
lastName: namor.generate({ words: 1, numbers: 0 }),
progress: Math.floor(Math.random() * 100),
status: statusChance > 0.66 ? 'relationship'
: statusChance > 0.33 ? 'complicated'
: 'single'
}
})
const columns = [{
Header: 'Name',
columns: [{
Header: 'First Name',
accessor: 'firstName'
}, {
Header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
Header: 'Info',
columns: [{
Header: 'Profile Progress',
accessor: 'progress',
Cell: row => (
<div
style={{
width: '100%',
height: '100%',
backgroundColor: '#dadada',
borderRadius: '2px'
}}
>
<div
style={{
width: `${row.value}%`,
height: '100%',
backgroundColor: row.value > 66 ? '#85cc00'
: row.value > 33 ? '#ffbf00'
: '#ff2e00',
borderRadius: '2px',
transition: 'all .2s ease-out'
}}
/>
</div>
)
}, {
Header: 'Status',
accessor: 'status',
Cell: row => (
<span>
<span style={{
color: row.value === 'relationship' ? '#ff2e00'
: row.value === 'complicated' ? '#ffbf00'
: '#57d500',
transition: 'all .3s ease'
}}>
&#x25cf;
</span> {
row.value === 'relationship' ? 'In a relationship'
: row.value === 'complicated' ? `It's complicated`
: 'Single'
}
</span>
)
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
</div>
)
}
}
// Source Code
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw!./CellRenderers')
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
+89
View File
@@ -0,0 +1,89 @@
/* eslint-disable import/no-webpack-loader-syntax */
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import ReactTable from '../../../lib/index'
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numbers: 0 }),
lastName: namor.generate({ words: 1, numbers: 0 }),
age: Math.floor(Math.random() * 30)
}
})
const columns = [{
Header: 'Name',
columns: [{
Header: 'First Name',
accessor: 'firstName'
}, {
Header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
Header: 'Info',
columns: [{
Header: 'Age',
accessor: 'age'
}]
}]
class Story extends React.PureComponent {
constructor () {
super()
this.state = {
sorted: [],
page: 0,
pageSize: 10,
expanded: {},
resized: [],
filtered: []
}
}
render () {
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
pivotBy={['lastName']}
filterable
// Controlled Props
sorted={this.state.sorted}
page={this.state.page}
pageSize={this.state.pageSize}
expanded={this.state.expanded}
resized={this.state.resized}
filtered={this.state.filtered}
// Callbacks
onSortedChange={sorted => this.setState({sorted})}
onPageChange={page => this.setState({page})}
onPageSizeChange={(pageSize, page) => this.setState({page, pageSize})}
onExpandedChange={expanded => this.setState({expanded})}
onResizedChange={resized => this.setState({resized})}
onFilteredChange={filtered => this.setState({filtered})}
/>
</div>
<br />
<pre><code><strong>this.state ===</strong> {JSON.stringify(this.state, null, 2)}</code></pre>
<br />
</div>
)
}
}
// Source Code
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw!./ControlledTable')
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
+76
View File
@@ -0,0 +1,76 @@
/* eslint-disable import/no-webpack-loader-syntax */
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import ReactTable from '../../../lib/index'
class Story extends React.PureComponent {
render () {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numbers: 0 }),
lastName: namor.generate({ words: 1, numbers: 0 }),
age: Math.floor(Math.random() * 30)
}
})
const columns = [{
Header: 'Name',
columns: [{
Header: 'First Name',
accessor: 'firstName'
}, {
Header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
Header: 'Info',
columns: [{
Header: 'Age',
accessor: 'age'
}]
}]
return (
<div>
<strong>Hey!</strong> Open your console! :)
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
getTdProps={(state, rowInfo, column, instance) => {
return {
onMouseEnter: e => console.log('Cell - onMouseEnter', {
state,
rowInfo,
column,
instance,
event: e
})
}
}}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
</div>
)
}
}
// Source Code
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw!./CustomComponentProps')
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
@@ -0,0 +1,81 @@
/* eslint-disable import/no-webpack-loader-syntax */
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import ReactTable from '../../../lib/index'
class Story extends React.PureComponent {
render () {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({words: 1, numbers: 0}),
lastName: namor.generate({words: 1, numbers: 0}),
age: Math.floor(Math.random() * 30)
}
})
const columns = [{
Header: 'Name',
columns: [{
Header: 'First Name',
accessor: 'firstName',
Footer: () => <div style={{textAlign: 'center'}}>First Name</div>
}, {
Header: 'Last Name',
accessor: 'lastName',
Footer: () => <div style={{textAlign: 'center'}}>Last Name</div>
}]
}, {
Header: 'Info',
columns: [{
Header: 'Age',
accessor: 'age',
Footer: () => <div style={{textAlign: 'center'}}>Age</div>
}]
}, {
Header: 'Expand',
columns: [{
expander: true,
Header: () => (<strong>More</strong>),
width: 65,
Expander: ({isExpanded, ...rest}) => (
<div>
{isExpanded ? <span>&#x2299;</span> : <span>&#x2295;</span>}
</div>
),
style: {cursor: 'pointer', fontSize: 25, padding: '0', textAlign: 'center', userSelect: 'none'},
Footer: () => <span>&hearts;</span>
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
SubComponent={() => <span>Hello</span>}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
</div>
)
}
}
// Source Code
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw!./CustomExpanderPosition')
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
+78
View File
@@ -0,0 +1,78 @@
/* eslint-disable import/no-webpack-loader-syntax */
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import ReactTable from '../../../lib/index'
class Story extends React.PureComponent {
render () {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numbers: 0 }),
lastName: namor.generate({ words: 1, numbers: 0 }),
age: Math.floor(Math.random() * 30)
}
})
const columns = [{
Header: 'Name',
columns: [{
Header: 'First Name (Sorted by Length, A-Z)',
accessor: 'firstName',
sortMethod: (a, b) => {
if (a.length === b.length) {
return a > b ? 1 : -1
}
return a.length > b.length ? 1 : -1
}
}, {
Header: 'Last Name (Sorted in reverse, A-Z)',
id: 'lastName',
accessor: d => d.lastName,
sortMethod: (a, b) => {
if (a === b) {
return 0
}
const aReverse = a.split('').reverse().join('')
const bReverse = b.split('').reverse().join('')
return aReverse > bReverse ? 1 : -1
}
}]
}, {
Header: 'Info',
columns: [{
Header: 'Age',
accessor: 'age'
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
</div>
)
}
}
// Source Code
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw!./CustomSorting')
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
+67
View File
@@ -0,0 +1,67 @@
/* eslint-disable import/no-webpack-loader-syntax */
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import ReactTable from '../../../lib/index'
class Story extends React.PureComponent {
render () {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numbers: 0 }),
lastName: namor.generate({ words: 1, numbers: 0 }),
age: Math.floor(Math.random() * 30)
}
})
const columns = [{
Header: 'Name',
columns: [{
Header: 'First Name',
accessor: 'firstName',
maxWidth: 200
}, {
Header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName,
width: 300
}]
}, {
Header: 'Info',
columns: [{
Header: 'Age',
accessor: 'age',
minWidth: 400
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
</div>
)
}
}
// Source Code
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw!./CustomWidths')
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
+68
View File
@@ -0,0 +1,68 @@
/* eslint-disable import/no-webpack-loader-syntax */
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import ReactTable from '../../../lib/index'
class Story extends React.PureComponent {
render () {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numbers: 0 }),
lastName: namor.generate({ words: 1, numbers: 0 }),
age: Math.floor(Math.random() * 30)
}
})
const columns = [{
Header: 'Name',
columns: [{
Header: 'First Name',
accessor: 'firstName'
}, {
Header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
Header: 'Info',
columns: [{
Header: 'Age',
accessor: 'age'
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
defaultSorted={[{
id: 'age',
desc: true
}]}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
</div>
)
}
}
// Source Code
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw!./DefaultSorting')
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
+70
View File
@@ -0,0 +1,70 @@
/* eslint-disable import/no-webpack-loader-syntax */
import React from 'react'
import ReactTable from '../../../lib/index'
class Story extends React.PureComponent {
constructor (props, context) {
super(props, context)
this.renderEditable = this.renderEditable.bind(this)
this.state = {
data: [
{ firstName: 'Lucy', lastName: 'Marks' },
{ firstName: 'Bejamin', lastName: 'Pike' }
]
}
this.columns = [
{
Header: 'First Name',
accessor: 'firstName',
Cell: this.renderEditable
},
{
Header: 'Last Name',
accessor: 'lastName',
Cell: this.renderEditable
},
{
Header: 'Full Name',
id: 'full',
accessor: d => d.firstName + ' ' + d.lastName
}
]
}
renderEditable (cellInfo) {
return (<div style={{ backgroundColor: '#fafafa' }} contentEditable suppressContentEditableWarning onBlur={(e) => {
const data = [...this.state.data]
data[cellInfo.index][cellInfo.column.id] = e.target.textContent
this.setState({data: data})
}}>{this.state.data[cellInfo.index][cellInfo.column.id]}</div>)
}
render () {
return (
<div className='table-wrap' style={{marginBottom: '20px'}}>
<p>First two columns are editable just by clicking into them using the <code>contentEditable</code> attribute. Last column (Full Name) is computed from the first two.</p>
<ReactTable
data={this.state.data}
columns={this.columns}
defaultPageSize={2}
showPageSizeOptions={false}
showPagination={false}
/>
</div>
)
}
}
// Source Code
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw!./EditableTable')
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
+194
View File
@@ -0,0 +1,194 @@
/* eslint-disable import/no-webpack-loader-syntax */
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../../../lib/index'
class Story extends React.PureComponent {
constructor (props) {
super(props)
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({words: 1, numbers: 0}),
lastName: namor.generate({words: 1, numbers: 0}),
age: Math.floor(Math.random() * 30)
}
})
this.state = {
tableOptions: {
loading: false,
showPagination: true,
showPageSizeOptions: true,
showPageJump: true,
collapseOnSortingChange: true,
collapseOnPageChange: true,
collapseOnDataChange: true,
freezeWhenExpanded: false,
filterable: true,
sortable: true,
resizable: true
},
data: data
}
this.setTableOption = this.setTableOption.bind(this)
}
render () {
const columns = [{
Header: 'Name',
columns: [{
Header: 'First Name',
accessor: 'firstName',
filterMethod: (filter, row) => (row[filter.id].startsWith(filter.value) && row[filter.id].endsWith(filter.value))
}, {
Header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName,
filterMethod: (filter, row) => (row[filter.id].includes(filter.value))
}]
}, {
Header: 'Info',
columns: [{
Header: 'Age',
accessor: 'age'
}, {
Header: 'Over 21',
accessor: 'age',
id: 'over',
Cell: ({value}) => (value >= 21 ? 'Yes' : 'No'),
filterMethod: (filter, row) => {
if (filter.value === 'all') {
return true
}
if (filter.value === 'true') {
return row[filter.id] >= 21
}
return row[filter.id] < 21
},
Filter: ({filter, onChange}) => (
<select
onChange={event => onChange(event.target.value)}
style={{width: '100%'}}
value={filter ? filter.value : 'all'}
>
<option value='all' />
<option value='true'>Can Drink</option>
<option value='false'>Can't Drink</option>
</select>
)
}
]
}]
return (
<div>
<div>
<h1>Table Options</h1>
<table>
<tbody>
{
Object.keys(this.state.tableOptions).map(optionKey => {
const optionValue = this.state.tableOptions[optionKey]
return (
<tr key={optionKey}>
<td>{optionKey}</td>
<td style={{paddingLeft: 10, paddingTop: 5}}>
<input type='checkbox'
name={optionKey}
checked={optionValue}
onChange={this.setTableOption}
/>
</td>
</tr>
)
})
}
</tbody>
</table>
</div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={this.state.data}
columns={columns}
defaultPageSize={10}
defaultFilterMethod={(filter, row) => (String(row[filter.id]) === filter.value)}
{...this.state.tableOptions}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>You can put any component you want here, even another React Table!</em>
<br />
<br />
<ReactTable
data={this.state.data}
columns={columns}
defaultPageSize={3}
showPagination={false}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>It even has access to the row data: </em>
<CodeHighlight>{() => JSON.stringify(row, null, 2)}</CodeHighlight>
</div>
)
}}
/>
</div>
)
}}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
<div>
<h1>Custom Filters In This Example</h1>
<p>The default filter for all columns of a table if it is not specified in the configuration is set to match
on values that start with the filter text. Example: age.startsWith("2").</p>
<p>This example overrides the default filter behavior by setting
the <strong>defaultFilterMethod</strong> table option to match on values that are exactly equal to the
filter text. Example: age == "23")</p>
<p>Each column can also be customized with the column <strong>filterMethod</strong> option:</p>
<p>In this example the firstName column filters on the value starting with and ending with the filter
value.</p>
<p>In this example the lastName column filters on the value including the filter value anywhere in its
text.</p>
<p>To completely override the filter that is shown, you can set the <strong>Filter</strong> column
option. Using this option you can specify the JSX that is shown. The option is passed
an <strong>onChange</strong> method that must be called with the value that you wan't to
pass to the <strong>filterMethod</strong> option whenever the filter has changed.</p>
</div>
</div>
)
}
setTableOption (event) {
const target = event.target
const value = target.type === 'checkbox' ? target.checked : target.value
const name = target.name
this.setState({
tableOptions: {
...this.state.tableOptions,
[name]: value
}
})
}
}
// Source Code
const source = require('!raw!./Filtering')
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
+81
View File
@@ -0,0 +1,81 @@
/* eslint-disable import/no-webpack-loader-syntax */
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import ReactTable from '../../../lib/index'
class Story extends React.PureComponent {
render() {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numbers: 0 }),
lastName: namor.generate({ words: 1, numbers: 0 }),
age: Math.floor(Math.random() * 30),
children: _.map(_.range(10), d => {
return {
firstName: namor.generate({ words: 1, numbers: 0 }),
lastName: namor.generate({ words: 1, numbers: 0 }),
age: Math.floor(Math.random() * 30)
}
})
}
})
const columns = [
{
Header: 'Name',
columns: [
{
Header: 'First Name',
accessor: 'firstName'
},
{
Header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}
]
},
{
Header: 'Info',
columns: [
{
Header: 'Age',
accessor: 'age'
}
]
}
]
return (
<div>
<div className="table-wrap">
<ReactTable
className="-striped -highlight"
data={data}
columns={columns}
defaultPageSize={20}
style={{
height: '400px' // This will force the table body to overflow and scroll, since there is not enough room
}}
/>
</div>
<div style={{ textAlign: 'center' }}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
</div>
)
}
}
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw!./FixedHeader')
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
+92
View File
@@ -0,0 +1,92 @@
/* eslint-disable import/no-webpack-loader-syntax */
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import ReactTable from '../../../lib/index'
class Story extends React.PureComponent {
render () {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numbers: 0 }),
lastName: namor.generate({ words: 1, numbers: 0 }),
age: Math.floor(Math.random() * 30)
}
})
const columns = [{
Header: 'Name',
columns: [{
Header: 'First Name',
accessor: 'firstName',
Footer: (
<span><strong>Popular:</strong> {
_.first(
_.reduce(
_.map(
_.groupBy(
data, d => d.firstName
)
),
(a, b) => a.length > b.length ? a : b
)
).firstName}
</span>
)
}, {
Header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName,
Footer: (
<span><strong>Longest:</strong> {
_.reduce(
_.map(
_.groupBy(
data, d => d.lastName
),
(d, key) => key
),
(a, b) => a.length > b.length ? a : b
)}
</span>
)
}]
}, {
Header: 'Info',
columns: [{
Header: 'Age',
accessor: 'age',
Footer: <span><strong>Average:</strong> {_.round(_.mean(_.map(data, d => d.age)))}</span>
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
</div>
)
}
}
// Source Code
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw!./Footers')
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
+137
View File
@@ -0,0 +1,137 @@
/* eslint-disable import/no-webpack-loader-syntax */
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import JSONTree from 'react-json-tree'
import ReactTable from '../../../lib/index'
const JSONtheme = {
scheme: 'monokai',
author: 'wimer hazenberg (http://www.monokai.nl)',
base00: '#272822',
base01: '#383830',
base02: '#49483e',
base03: '#75715e',
base04: '#a59f85',
base05: '#f8f8f2',
base06: '#f5f4f1',
base07: '#f9f8f5',
base08: '#f92672',
base09: '#fd971f',
base0A: '#f4bf75',
base0B: '#a6e22e',
base0C: '#a1efe4',
base0D: '#66d9ef',
base0E: '#ae81ff',
base0F: '#cc6633'
}
class Story extends React.PureComponent {
render () {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numbers: 0 }),
lastName: namor.generate({ words: 1, numbers: 0 }),
age: Math.floor(Math.random() * 30)
}
})
const columns = [{
Header: 'Name',
columns: [{
Header: 'First Name',
accessor: 'firstName',
Footer: 'Footer'
}, {
Header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName,
Footer: 'Footer'
}]
}, {
Header: 'Info',
columns: [{
Header: 'Age',
accessor: 'age',
Footer: 'Footer'
}]
}]
return (
<div>
<strong>Functional rendering</strong> simply means that you have all of the building blocks to render your own React Table however you'd like.
<br />
<br />
<br />
<br />
<strong>Decorating the standard table output</strong>
<br />
<br />
<div className='table-wrap'>
<ReactTable
data={data}
columns={columns}
>
{(state, makeTable, instance) => {
return (
<div style={{
background: '#ffcf00',
borderRadius: '5px',
overflow: 'hidden',
padding: '5px'
}}>
<pre><code>state.allVisibleColumns === {JSON.stringify(state.allVisibleColumns, null, 4)}</code></pre>
{makeTable()}
</div>
)
}}
</ReactTable>
</div>
<br />
<br />
<strong>Need more control? This is the entire table state and component instance at your disposal!</strong>
<br />
<br />
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
>
{(state, StandardTable, instance) => {
return (
<div>
<JSONTree
data={Object.assign({}, state, {children: 'function () {...}'})}
theme={JSONtheme}
invertTheme
/>
</div>
)
}}
</ReactTable>
</div>
<br />
</div>
)
}
}
// Source Code
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw!./FunctionalRendering')
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
-23
View File
@@ -1,23 +0,0 @@
/* 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()
}
}
+73
View File
@@ -0,0 +1,73 @@
/* eslint-disable import/no-webpack-loader-syntax */
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import ReactTable from '../../../lib/index'
class Story extends React.PureComponent {
render () {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numbers: 0 }),
lastName: namor.generate({ words: 1, numbers: 0 }),
age: Math.floor(Math.random() * 30),
children: _.map(_.range(10), d => {
return {
firstName: namor.generate({ words: 1, numbers: 0 }),
lastName: namor.generate({ words: 1, numbers: 0 }),
age: Math.floor(Math.random() * 30)
}
})
}
})
const columns = [{
Header: 'Name',
columns: [{
Header: 'First Name',
accessor: 'firstName'
}, {
Header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
Header: 'Info',
columns: [{
Header: 'Age',
accessor: 'age'
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
showPagination
showPaginationTop
showPaginationBottom
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
</div>
)
}
}
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw!./MultiplePagers')
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
+57
View File
@@ -0,0 +1,57 @@
/* eslint-disable import/no-webpack-loader-syntax */
import React from 'react'
import ReactTable from '../../../lib/index'
class Story extends React.PureComponent {
render () {
const columns = [{
Header: 'Name',
columns: [{
Header: 'First Name',
accessor: 'firstName'
}, {
Header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
Header: 'Info',
columns: [{
Header: 'Age',
accessor: 'age'
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={[]}
noDataText='Oh Noes!'
// noDataText={() => 'Oh Noes!'} // Supports functions
// noDataText={() => <span>Oh Noes!</span>} // Supports JSX / React Components
columns={columns}
defaultPageSize={10}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
</div>
)
}
}
// Source Code
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw!./NoDataText')
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
+97
View File
@@ -0,0 +1,97 @@
/* eslint-disable import/no-webpack-loader-syntax */
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import ReactTable from '../../../lib/index'
class Story extends React.PureComponent {
render () {
const data = _.map(_.range(100000), d => {
return {
firstName: namor.generate({ words: 1, numbers: 0 }),
lastName: namor.generate({ words: 1, numbers: 0 }),
age: Math.floor(Math.random() * 30),
visits: Math.floor(Math.random() * 100)
}
})
const columns = [{
Header: 'Name',
columns: [{
Header: 'First Name',
accessor: 'firstName'
}, {
Header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
Header: 'Info',
columns: [{
Header: 'Age',
accessor: 'age',
aggregate: vals => _.round(_.mean(vals)),
Aggregated: row => {
return <span>{row.value} (avg)</span>
}
}, {
Header: 'Visits',
accessor: 'visits',
aggregate: vals => _.sum(vals)
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
data={data}
columns={columns}
className='-striped -highlight'
defaultPageSize={10}
pivotBy={['firstName', 'lastName']}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>You can put any component you want here, even another React Table!</em>
<br />
<br />
<ReactTable
data={data}
columns={columns}
defaultPageSize={3}
showPagination={false}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>It even has access to the row data: </em>
<CodeHighlight>{() => JSON.stringify(row, null, 2)}</CodeHighlight>
</div>
)
}}
/>
</div>
)
}}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
</div>
)
}
}
// Source Code
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw!./OneHundredKRows')
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
+74
View File
@@ -0,0 +1,74 @@
/* eslint-disable import/no-webpack-loader-syntax */
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import ReactTable from '../../../lib/index'
class Story extends React.PureComponent {
render () {
const data = _.map(_.range(1000), d => {
return {
firstName: namor.generate({ words: 1, numbers: 0 }),
lastName: namor.generate({ words: 1, numbers: 0 }),
age: Math.floor(Math.random() * 30),
visits: Math.floor(Math.random() * 100)
}
})
const columns = [{
Header: 'Name',
columns: [{
Header: 'First Name',
accessor: 'firstName'
}, {
Header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
Header: 'Info',
columns: [{
Header: 'Age',
accessor: 'age',
aggregate: vals => _.round(_.mean(vals)),
Aggregated: row => {
return <span>{row.value} (avg)</span>
}
}, {
Header: 'Visits',
accessor: 'visits',
aggregate: vals => _.sum(vals)
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
data={data}
columns={columns}
className='-striped -highlight'
defaultPageSize={10}
pivotBy={['firstName', 'lastName']}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
</div>
)
}
}
// Source Code
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw!./Pivoting')
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
+132
View File
@@ -0,0 +1,132 @@
/* eslint-disable import/no-webpack-loader-syntax */
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import ReactTable from '../../../lib/index'
class Story extends React.PureComponent {
render () {
const data = _.map(_.range(1000), d => {
return {
firstName: namor.generate({words: 1, numbers: 0}),
lastName: namor.generate({words: 1, numbers: 0}),
age: Math.floor(Math.random() * 30),
visits: Math.floor(Math.random() * 100)
}
})
const columns = [{
Header: 'Name',
columns: [{
Header: 'First Name',
accessor: 'firstName',
PivotValue: ({value}) => <span style={{color: 'darkred'}}>{value}</span>
}, {
Header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName,
PivotValue: ({value}) => <span style={{color: 'darkblue'}}>{value}</span>,
Footer: () => <div style={{textAlign: 'center'}}><strong>Pivot Column Footer</strong></div>
}]
}, {
Header: 'Info',
columns: [{
Header: 'Age',
accessor: 'age',
aggregate: vals => {
return _.round(_.mean(vals))
},
Aggregated: row => <span>{row.value} (avg)</span>
}, {
Header: 'Visits',
accessor: 'visits',
aggregate: vals => _.sum(vals),
filterable: false
}]
}, {
pivot: true,
Header: () => <strong>Overridden Pivot Column Header Group</strong>
}, {
expander: true
}]
const subtableColumns = [{
Header: 'Name',
columns: [{
Header: 'First Name',
accessor: 'firstName'
}, {
Header: 'Last Name',
id: 'lastName'
}]
}, {
Header: 'Info',
columns: [{
Header: 'Age',
accessor: 'age'
}, {
Header: 'Visits',
accessor: 'visits'
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
data={data}
columns={columns}
defaultPageSize={10}
className='-striped -highlight'
pivotBy={['firstName', 'lastName']}
defaultSorted={[{id: 'firstName', desc: false}, {id: 'lastName', desc: true}]}
collapseOnSortingChange={false}
filterable
ExpanderComponent={({isExpanded, ...rest}) => (
isExpanded ? <span> &#10136; </span> : <span> &#10137; </span>
)}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>You can put any component you want here, even another React Table!</em>
<br />
<br />
<ReactTable
data={data}
columns={subtableColumns}
defaultPageSize={3}
showPagination={false}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>It even has access to the row data: </em>
<CodeHighlight>{() => JSON.stringify(row, null, 2)}</CodeHighlight>
</div>
)
}}
/>
</div>
)
}}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
</div>
)
}
}
// Source Code
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw!./PivotingOptions')
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
+100
View File
@@ -0,0 +1,100 @@
/* eslint-disable import/no-webpack-loader-syntax */
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import ReactTable from '../../../lib/index'
class Story extends React.PureComponent {
render () {
const data = _.map(_.range(1000), d => {
return {
firstName: namor.generate({ words: 1, numbers: 0 }),
lastName: namor.generate({ words: 1, numbers: 0 }),
age: Math.floor(Math.random() * 30),
visits: Math.floor(Math.random() * 100)
}
})
const columns = [{
Header: 'Name',
columns: [{
Header: 'First Name',
accessor: 'firstName'
}, {
Header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
Header: 'Info',
columns: [{
Header: 'Age',
accessor: 'age',
aggregate: vals => _.round(_.mean(vals)),
Aggregated: row => {
return <span>{row.value} (avg)</span>
},
filterMethod: (filter, row) => (filter.value === `${row[filter.id]} (avg)`)
}, {
Header: 'Visits',
accessor: 'visits',
aggregate: vals => _.sum(vals),
filterable: false
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
data={data}
columns={columns}
defaultPageSize={10}
className='-striped -highlight'
pivotBy={['firstName', 'lastName']}
filterable
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>You can put any component you want here, even another React Table!</em>
<br />
<br />
<ReactTable
data={data}
columns={columns}
defaultPageSize={3}
showPagination={false}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>It even has access to the row data: </em>
<CodeHighlight>{() => JSON.stringify(row, null, 2)}</CodeHighlight>
</div>
)
}}
/>
</div>
)
}}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
</div>
)
}
}
// Source Code
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw!./PivotingSubComponents')
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
+7 -10
View File
@@ -4,20 +4,17 @@ import marked from 'marked'
//
import Readme from '!raw!../../../README.md'
import 'github-markdown-css/github-markdown.css'
import './utils/prism.js'
export default class Story extends React.Component {
render () {
render() {
return (
<div style={{ padding: '10px' }}>
<span
className='markdown-body'
dangerouslySetInnerHTML={{ __html: marked(Readme) }}
/>
</div>
<span
className="markdown-body"
dangerouslySetInnerHTML={{ __html: marked(Readme) }}
/>
)
}
componentDidMount () {
global.Prism && global.Prism.highlightAll()
componentDidMount() {
global.Prism.highlightAll()
}
}
+121
View File
@@ -0,0 +1,121 @@
/* eslint-disable import/no-webpack-loader-syntax */
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import ReactTable from '../../../lib/index'
const rawData = _.map(_.range(3424), d => {
return {
firstName: namor.generate({ words: 1, numbers: 0 }),
lastName: namor.generate({ words: 1, numbers: 0 }),
age: Math.floor(Math.random() * 30)
}
})
// Now let's mock the server. It's job is simple: use the table model to sort and return the page data
const requestData = (pageSize, page, sorted, filtered) => {
return new Promise((resolve, reject) => {
// On the server, you'll likely use SQL or noSQL or some other query language to do this.
// For this mock, we'll just use lodash
let filteredData = rawData
if (filtered.length) {
filteredData = filtered.reduce(
(filteredSoFar, nextFilter) => {
return filteredSoFar.filter(
(row) => {
return (row[nextFilter.id] + '').includes(nextFilter.value)
})
}
, filteredData)
}
const sortedData = _.orderBy(filteredData, sorted.map(sort => {
return row => {
if (row[sort.id] === null || row[sort.id] === undefined) {
return -Infinity
}
return typeof row[sort.id] === 'string' ? row[sort.id].toLowerCase() : row[sort.id]
}
}), sorted.map(d => d.desc ? 'desc' : 'asc'))
// Be sure to send back the rows to be displayed and any other pertinent information, like how many pages there are total.
const res = {
rows: sortedData.slice(pageSize * page, (pageSize * page) + pageSize),
pages: Math.ceil(filteredData.length / pageSize)
}
// Here we'll simulate a server response with 500ms of delay.
setTimeout(() => resolve(res), 500)
})
}
class Story extends React.PureComponent {
constructor () {
super()
this.state = {
data: [],
pages: null,
loading: true
}
this.fetchData = this.fetchData.bind(this)
}
fetchData (state, instance) {
// Whenever the table model changes, or the user sorts or changes pages, this method gets called and passed the current table model.
// You can set the `loading` prop of the table to true to use the built-in one or show you're own loading bar if you want.
this.setState({loading: true})
// Request the data however you want. Here, we'll use our mocked service we created earlier
requestData(state.pageSize, state.page, state.sorted, state.filtered)
.then((res) => {
// Now just get the rows of data to your React Table (and update anything else like total pages or loading)
this.setState({
data: res.rows,
pages: res.pages,
loading: false
})
})
}
render () {
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
columns={[{
Header: 'First Name',
accessor: 'firstName'
}, {
Header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}, {
Header: 'Age',
accessor: 'age'
}]}
manual // Forces table not to paginate or sort automatically, so we can handle it server-side
defaultPageSize={10}
filterable
data={this.state.data} // Set the rows to be displayed
pages={this.state.pages} // Display the total number of pages
loading={this.state.loading} // Display the loading overlay when we need it
onFetchData={this.fetchData} // Request new data when things change
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
</div>
)
}
}
// Source Code
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw!./ServerSide')
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
+77
View File
@@ -0,0 +1,77 @@
/* eslint-disable import/no-webpack-loader-syntax */
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import ReactTable from '../../../lib/index'
class Story extends React.PureComponent {
render() {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numbers: 0 }),
lastName: namor.generate({ words: 1, numbers: 0 }),
age: Math.floor(Math.random() * 30),
children: _.map(_.range(10), d => {
return {
firstName: namor.generate({ words: 1, numbers: 0 }),
lastName: namor.generate({ words: 1, numbers: 0 }),
age: Math.floor(Math.random() * 30)
}
})
}
})
const columns = [
{
Header: 'Name',
columns: [
{
Header: 'First Name',
accessor: 'firstName'
},
{
Header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}
]
},
{
Header: 'Info',
columns: [
{
Header: 'Age',
accessor: 'age'
}
]
}
]
return (
<div>
<div className="table-wrap">
<ReactTable
className="-striped -highlight"
data={data}
columns={columns}
defaultPageSize={10}
/>
</div>
<div style={{ textAlign: 'center' }}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
</div>
)
}
}
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw!./Simple')
export default () =>
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
+146
View File
@@ -0,0 +1,146 @@
/* eslint-disable import/no-webpack-loader-syntax */
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import ReactTable from '../../../lib/index'
class Story extends React.PureComponent {
constructor (props) {
super(props)
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({words: 1, numbers: 0}),
lastName: namor.generate({words: 1, numbers: 0}),
age: Math.floor(Math.random() * 30)
}
})
this.state = {
tableOptions: {
loading: false,
showPagination: true,
showPageSizeOptions: true,
showPageJump: true,
collapseOnSortingChange: true,
collapseOnPageChange: true,
collapseOnDataChange: true,
freezeWhenExpanded: false,
filterable: false,
sortable: true,
resizable: true
},
data: data
}
this.setTableOption = this.setTableOption.bind(this)
}
render () {
const columns = [{
Header: 'Name',
columns: [{
Header: 'First Name',
accessor: 'firstName'
}, {
Header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
Header: 'Info',
columns: [{
Header: 'Age',
accessor: 'age'
}]
}]
return (
<div>
<div>
<h1>Table Options</h1>
<table>
<tbody>
{
Object.keys(this.state.tableOptions).map(optionKey => {
const optionValue = this.state.tableOptions[optionKey]
return (
<tr key={optionKey}>
<td>{optionKey}</td>
<td style={{paddingLeft: 10, paddingTop: 5}}>
<input type='checkbox'
name={optionKey}
checked={optionValue}
onChange={this.setTableOption}
/>
</td>
</tr>
)
})
}
</tbody>
</table>
</div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={this.state.data}
columns={columns}
defaultPageSize={10}
{...this.state.tableOptions}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>You can put any component you want here, even another React Table!</em>
<br />
<br />
<ReactTable
data={this.state.data}
columns={columns}
defaultPageSize={3}
showPagination={false}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>It even has access to the row data: </em>
<CodeHighlight>{() => JSON.stringify(row, null, 2)}</CodeHighlight>
</div>
)
}}
/>
</div>
)
}}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
</div>
)
}
setTableOption (event) {
const target = event.target
const value = target.type === 'checkbox' ? target.checked : target.value
const name = target.name
this.setState({
tableOptions: {
...this.state.tableOptions,
[name]: value
}
})
}
}
// Source Code
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw!./SubComponents')
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
+78
View File
@@ -0,0 +1,78 @@
/* eslint-disable import/no-webpack-loader-syntax */
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import ReactTable from '../../../lib/index'
class Story extends React.PureComponent {
render () {
const data = _.map(_.range(5553), d => {
const children = _.map(_.range(10), d => {
const grandChildren = _.map(_.range(10), d => {
return {
age: Math.floor(Math.random() * 30)
}
})
return {
firstName: namor.generate({ words: 1, numbers: 0 }),
age: Math.floor(Math.random() * 30),
children: grandChildren
}
})
return {
lastName: namor.generate({ words: 1, numbers: 0 }),
firstName: children.map(d => d.firstName),
age: Math.floor(Math.random() * 30),
children
}
})
const columns = [{
Header: 'Name',
columns: [{
Header: 'First Name',
accessor: 'firstName',
expander: true
}, {
Header: 'Last Name',
accessor: 'lastName'
}]
}, {
Header: 'Info',
columns: [{
Header: 'Age',
accessor: 'age'
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
subRowsKey='children'
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
</div>
)
}
}
// Source Code
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw!./SubRows')
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
@@ -0,0 +1,21 @@
import React from 'react'
import '../utils/prism'
export default class CodeHighlight extends React.Component {
render () {
const { language, children } = this.props
return (
<pre>
<code className={'language-' + (language || 'jsx')}>
{children()}
</code>
</pre>
)
}
componentDidMount () {
window.Prism.highlightAll()
}
componentDidUpdate () {
window.Prism.highlightAll()
}
}
-31
View File
@@ -1,31 +0,0 @@
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' },
]
export default class Story extends React.Component {
render () {
return (
<div>
Test
<ReactTable
data={data}
columns={columns}
/>
</div>
)
}
}
File diff suppressed because one or more lines are too long
+414 -1932
View File
File diff suppressed because it is too large Load Diff
+21 -17
View File
@@ -1,12 +1,12 @@
{
"name": "react-table",
"version": "6.7.5",
"version": "6.4.0",
"description": "A fast, lightweight, opinionated table and datagrid built on React",
"license": "MIT",
"homepage": "https://github.com/react-tools/react-table#readme",
"homepage": "https://github.com/tannerlinsley/react-table#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/react-tools/react-table.git"
"url": "git+https://github.com/tannerlinsley/react-table.git"
},
"keywords": [
"react",
@@ -29,19 +29,20 @@
"watch": "npm-run-all --parallel watch:*",
"watch:node": "onchange 'src/**/*.js' -i -- npm run build:node",
"watch:css": "onchange 'src/**/*.styl' -i -- npm run build:css",
"test": "eslint src",
"test": "standard",
"umd": "rimraf react-table.js && webpack --config umd.webpack.js",
"build": "npm-run-all build:*",
"prepublishOnly": "npm run build && npm run umd",
"prepublish": "npm run build && npm run umd",
"postpublish": "git push --tags",
"docs": "yarn watch & cd docs && yarn && yarn start",
"docs:build": "yarn build && cd docs && yarn && yarn build"
"docs:build": "yarn build && cd docs && yarn && yarn run build"
},
"dependencies": {
"classnames": "^2.2.5"
"classnames": "^2.2.5",
"react-json-tree": "^0.10.9"
},
"peerDependencies": {
"react": "^15.x.x || ^16.x.x"
"react": "^15.x.x"
},
"devDependencies": {
"autoprefixer": "^6.7.0",
@@ -50,25 +51,28 @@
"babel-preset-es2015": "6.14.0",
"babel-preset-react": "6.11.1",
"babel-preset-stage-2": "6.13.0",
"eslint": "^4.1.1",
"eslint-config-react-tools": "^1.0.10",
"eslint-plugin-class-property": "^1.0.6",
"eslint-plugin-import": "^2.7.0",
"eslint-plugin-jsx-a11y": "^6.0.2",
"eslint-plugin-react": "^7.4.0",
"match-sorter": "^1.8.0",
"npm-run-all": "^3.1.1",
"onchange": "^3.0.2",
"postcss-cli": "^2.6.0",
"prop-types": "^15.6.0",
"react": "^15.4.2",
"react-dom": "^15.4.2",
"react-json-tree": "^0.10.9",
"rimraf": "^2.6.1",
"standard": "^10.0.2",
"stylus": "^0.54.5",
"webpack": "^2.5.1"
},
"standard": {
"parser": "babel-eslint",
"ignore": [
"node_modules",
"dist",
"lib",
"example",
"react-table.js",
"stories",
"docs"
]
},
"babel": {
"presets": [
"es2015",
+38 -55
View File
@@ -22,7 +22,6 @@ export default {
collapseOnDataChange: true,
freezeWhenExpanded: false,
sortable: true,
multiSort: true,
resizable: true,
filterable: false,
defaultSortDesc: false,
@@ -30,15 +29,13 @@ 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) => {
defaultSortMethod: (a, b) => {
// force null and undefined to the bottom
a = a === null || a === undefined ? '' : a
b = b === null || b === undefined ? '' : b
@@ -52,8 +49,7 @@ 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
},
@@ -149,7 +145,6 @@ export default {
footerStyle: {},
getFooterProps: emptyObj,
filterMethod: undefined,
filterAll: false,
sortMethod: undefined,
},
@@ -175,78 +170,66 @@ export default {
rowsText: 'rows',
// Components
TableComponent: _.makeTemplateComponent('rt-table', 'Table'),
TheadComponent: _.makeTemplateComponent('rt-thead', 'Thead'),
TbodyComponent: _.makeTemplateComponent('rt-tbody', 'Tbody'),
TrGroupComponent: _.makeTemplateComponent('rt-tr-group', 'TrGroup'),
TrComponent: _.makeTemplateComponent('rt-tr', 'Tr'),
ThComponent: ({ toggleSort, className, children, ...rest }) => (
<div
className={classnames('rt-th', className)}
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 }) => (
TableComponent: _.makeTemplateComponent('rt-table'),
TheadComponent: _.makeTemplateComponent('rt-thead'),
TbodyComponent: _.makeTemplateComponent('rt-tbody'),
TrGroupComponent: _.makeTemplateComponent('rt-tr-group'),
TrComponent: _.makeTemplateComponent('rt-tr'),
ThComponent: ({ toggleSort, className, children, ...rest }) => {
return (
<div
className={classnames(className, 'rt-th')}
onClick={e => {
toggleSort && toggleSort(e)
}}
{...rest}
>
{children}
</div>
)
},
TdComponent: _.makeTemplateComponent('rt-td'),
TfootComponent: _.makeTemplateComponent('rt-tfoot'),
FilterComponent: ({ filter, onChange }) =>
<input
type="text"
type='text'
style={{
width: '100%',
}}
value={filter ? filter.value : ''}
onChange={event => onChange(event.target.value)}
/>
),
ExpanderComponent: ({ isExpanded }) => (
/>,
ExpanderComponent: ({ isExpanded }) =>
<div className={classnames('rt-expander', isExpanded && '-open')}>
&bull;
</div>
),
PivotValueComponent: ({ subRows, value }) => (
<span>
{value} {subRows && `(${subRows.length})`}
</span>
),
</div>,
PivotValueComponent: ({ subRows, value }) =>
<span>{value} {subRows && `(${subRows.length})`}</span>,
AggregatedComponent: ({ subRows, column }) => {
const previewValues = subRows
.filter(d => typeof d[column.id] !== 'undefined')
.map((row, i) => (
// eslint-disable-next-line react/no-array-index-key
.map((row, i) =>
<span key={i}>
{row[column.id]}
{i < subRows.length - 1 ? ', ' : ''}
{row[column.id]}{i < subRows.length - 1 ? ', ' : ''}
</span>
))
return (
<span>
{previewValues}
</span>
)
)
return <span>{previewValues}</span>
},
PivotComponent: undefined, // this is a computed default generated using
// the ExpanderComponent and PivotValueComponent at run-time in methods.js
PaginationComponent: Pagination,
PreviousComponent: undefined,
NextComponent: undefined,
LoadingComponent: ({ className, loading, loadingText, ...rest }) => (
LoadingComponent: ({ className, loading, loadingText, ...rest }) =>
<div
className={classnames('-loading', { '-active': loading }, className)}
{...rest}
>
<div className="-loading-inner">
<div className='-loading-inner'>
{loadingText}
</div>
</div>
),
NoDataComponent: _.makeTemplateComponent('rt-noData', 'NoData'),
ResizerComponent: _.makeTemplateComponent('rt-resizer', 'Resizer'),
</div>,
NoDataComponent: _.makeTemplateComponent('rt-noData'),
ResizerComponent: _.makeTemplateComponent('rt-resizer'),
PadRowComponent: () => <span>&nbsp;</span>,
}
-122
View File
@@ -1,122 +0,0 @@
<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.
-111
View File
@@ -1,111 +0,0 @@
/* 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;
}
-80
View File
@@ -1,80 +0,0 @@
/* 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;
}
+347 -365
View File
File diff suppressed because it is too large Load Diff
+35 -21
View File
@@ -2,15 +2,6 @@ $easeOutQuad = cubic-bezier(0.250, 0.460, 0.450, 0.940)
$easeOutBack = cubic-bezier(0.175, 0.885, 0.320, 1.275)
$expandSize = 7px
input-select-style()
border: 1px solid rgba(0,0,0,0.1)
background: white
padding: 5px 7px
font-size: inherit
border-radius: 3px
font-weight: normal
outline:none
.ReactTable
position:relative
display: flex
@@ -19,7 +10,7 @@ input-select-style()
*
box-sizing: border-box
.rt-table
flex: auto 1
flex: 1
display: flex
flex-direction: column
align-items: stretch
@@ -30,6 +21,7 @@ input-select-style()
.rt-thead
flex: 1 0 auto
display: flex
// overflow-y: scroll
flex-direction: column
-webkit-user-select: none;
-moz-user-select: none;
@@ -43,10 +35,6 @@ input-select-style()
&.-filters
border-bottom: 1px solid alpha(black, 0.05)
input
select
input-select-style();
.rt-th
border-right: 1px solid alpha(black, 0.02)
@@ -181,7 +169,6 @@ input-select-style()
z-index: 10
.rt-tfoot
flex: 1 0 auto
display: flex
flex-direction: column
box-shadow: 0 0px 15px 0px alpha(black, .15)
@@ -209,10 +196,6 @@ input-select-style()
box-shadow: 0 0px 15px 0px alpha(black, .1)
border-top: 2px solid alpha(black, .1)
input
select
input-select-style()
.-btn
appearance:none
display:block
@@ -287,7 +270,7 @@ input-select-style()
bottom:0
background: alpha(white, .8)
transition: all .3s ease
z-index: -1
z-index: 2
opacity: 0
pointer-events: none
@@ -305,11 +288,42 @@ input-select-style()
&.-active
opacity: 1
z-index: 2
pointer-events: all
> div
transform: translateY(50%)
input
select
border: 1px solid rgba(0,0,0,0.1)
background: white
padding: 5px 7px
font-size: inherit
border-radius: 3px
font-weight: normal
outline:none
input:not([type="checkbox"]):not([type="radio"])
select
appearance: none
&::-ms-expand
display: none
.select-wrap
position:relative
display:inline-block
select
padding: 5px 15px 5px 7px
min-width:100px
&:after
content: ''
position: absolute
right: 8px
top: 50%
transform: translate(0, -50%)
border-color: #999 transparent transparent
border-style: solid
border-width: 5px 5px 2.5px
.rt-resizing
.rt-th
.rt-td
+6 -22
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 (let i = 0; i < keys.length; i += 1) {
for (var i = 0; i < keys.length; i++) {
if (newResolvedState.expanded[keys[i]]) {
newResolvedState.frozen = true
break
@@ -88,8 +88,7 @@ export default Base =>
this.props.collapseOnSortingChange) ||
oldState.filtered !== newResolvedState.filtered ||
oldState.showFilters !== newResolvedState.showFilters ||
(oldState.sortedData &&
!newResolvedState.frozen &&
(!newResolvedState.frozen &&
oldState.resolvedData !== newResolvedState.resolvedData &&
this.props.collapseOnDataChange)
) {
@@ -99,36 +98,21 @@ export default Base =>
Object.assign(newResolvedState, this.getSortedData(newResolvedState))
}
// Set page to 0 if filters change
if (oldState.filtered !== newResolvedState.filtered) {
newResolvedState.page = 0
}
// Calculate pageSize all the time
if (newResolvedState.sortedData) {
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, () => {
if (cb) { cb() }
if (
oldState.page !== newResolvedState.page ||
oldState.pageSize !== newResolvedState.pageSize ||
oldState.sorted !== newResolvedState.sorted ||
oldState.filtered !== newResolvedState.filtered
) {
this.fireFetchData()
}
})
return this.setState(newResolvedState, cb)
}
}
+162 -174
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) {
@@ -55,7 +55,7 @@ export default Base =>
columnsWithExpander = [expanderColumn, ...columnsWithExpander]
}
const makeDecoratedColumn = (column, parentColumn) => {
const makeDecoratedColumn = column => {
let dcol
if (column.expander) {
dcol = {
@@ -70,16 +70,6 @@ export default Base =>
}
}
// Ensure minWidth is not greater than maxWidth if set
if (dcol.maxWidth < dcol.minWidth) {
dcol.minWidth = dcol.maxWidth
}
if (parentColumn) {
dcol.parentColumn = parentColumn
}
// First check for string accessor
if (typeof dcol.accessor === 'string') {
dcol.id = dcol.id || dcol.accessor
const accessorString = dcol.accessor
@@ -87,52 +77,55 @@ export default Base =>
return dcol
}
// Fall back to functional accessor (but require an ID)
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 = () => undefined
dcol.accessor = d => undefined
}
// Ensure minWidth is not greater than maxWidth if set
if (dcol.maxWidth < dcol.minWidth) {
dcol.minWidth = dcol.maxWidth
}
return dcol
}
const allDecoratedColumns = []
// Decorate the columns
const decorateAndAddToAll = (column, parentColumn) => {
const decoratedColumn = makeDecoratedColumn(column, parentColumn)
const decorateAndAddToAll = col => {
const decoratedColumn = makeDecoratedColumn(col)
allDecoratedColumns.push(decoratedColumn)
return decoratedColumn
}
const decoratedColumns = columnsWithExpander.map(column => {
let allDecoratedColumns = []
const decoratedColumns = columnsWithExpander.map((column, i) => {
if (column.columns) {
return {
...column,
columns: column.columns.map(d => decorateAndAddToAll(d, column)),
columns: column.columns.map(decorateAndAddToAll),
}
} 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 => {
visibleColumns = visibleColumns.map((column, i) => {
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 +134,13 @@ export default Base =>
return column
})
visibleColumns = visibleColumns.filter(column => (
column.columns
visibleColumns = visibleColumns.filter(column => {
return 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,17 +156,8 @@ export default Base =>
}
})
const PivotParentColumn = pivotColumns.reduce(
(prev, current) =>
prev && prev === current.parentColumn && current.parentColumn,
pivotColumns[0].parentColumn,
)
let PivotGroupHeader = hasHeaderGroups && PivotParentColumn.Header
PivotGroupHeader = PivotGroupHeader || (() => <strong>Pivoted</strong>)
let pivotColumnGroup = {
Header: PivotGroupHeader,
header: () => <strong>Group</strong>,
columns: pivotColumns.map(col => ({
...this.props.pivotDefaults,
...col,
@@ -202,13 +186,13 @@ export default Base =>
headerGroups.push({
...this.props.column,
...column,
columns,
columns: columns,
})
currentSpan = []
}
// Build flast list of allVisibleColumns and HeaderGroups
visibleColumns.forEach(column => {
visibleColumns.forEach((column, i) => {
if (column.columns) {
allVisibleColumns = allVisibleColumns.concat(column.columns)
if (currentSpan.length > 0) {
@@ -238,18 +222,13 @@ 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 = {}
@@ -259,6 +238,11 @@ 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,18 +251,20 @@ export default Base =>
}
// Group the rows together for this level
let groupedRows = Object.entries(
_.groupBy(rows, keys[i]),
).map(([key, value]) => ({
[pivotIDKey]: keys[i],
[pivotValKey]: key,
[keys[i]]: key,
[subRowsKey]: value,
[nestingLevelKey]: i,
[groupedByPivotKey]: true,
}))
_.groupBy(rows, keys[i])
).map(([key, value]) => {
return {
[pivotIDKey]: keys[i],
[pivotValKey]: key,
[keys[i]]: key,
[subRowsKey]: value,
[nestingLevelKey]: i,
[groupedByPivotKey]: true,
}
})
// Recurse into the subRows
groupedRows = groupedRows.map(rowGroup => {
const subRows = groupRecursively(rowGroup[subRowsKey], keys, i + 1)
let subRows = groupRecursively(rowGroup[subRowsKey], keys, i + 1)
return {
...rowGroup,
[subRowsKey]: subRows,
@@ -323,15 +309,15 @@ export default Base =>
sortedData: manual
? resolvedData
: this.sortData(
this.filterData(
resolvedData,
filtered,
defaultFilterMethod,
allVisibleColumns,
this.filterData(
resolvedData,
filtered,
defaultFilterMethod,
allVisibleColumns
),
sorted,
sortMethodsByColumnID
),
sorted,
sortMethodsByColumnID,
),
}
}
@@ -352,22 +338,20 @@ export default Base =>
if (filtered.length) {
filteredData = filtered.reduce((filteredSoFar, nextFilter) => {
const column = allVisibleColumns.find(x => x.id === nextFilter.id)
return filteredSoFar.filter(row => {
let column
// Don't filter hidden columns or columns that have had their filters disabled
if (!column || column.filterable === false) {
return filteredSoFar
}
column = allVisibleColumns.find(x => x.id === nextFilter.id)
const filterMethod = column.filterMethod || defaultFilterMethod
// Don't filter hidden columns or columns that have had their filters disabled
if (!column || column.filterable === false) {
return true
}
// If 'filterAll' is set to true, pass the entire dataset to the filter method
if (column.filterAll) {
return filterMethod(nextFilter, filteredSoFar, column)
}
return filteredSoFar.filter(row => (
filterMethod(nextFilter, row, column)
))
const filterMethod = column.filterMethod || defaultFilterMethod
return filterMethod(nextFilter, row, column)
})
}, filteredData)
// Apply the filter to the subrows if we are pivoting, and then
@@ -383,7 +367,7 @@ export default Base =>
row[this.props.subRowsKey],
filtered,
defaultFilterMethod,
allVisibleColumns,
allVisibleColumns
),
}
})
@@ -408,16 +392,16 @@ export default Base =>
sorted.map(sort => {
// Support custom sorting methods for each column
if (sortMethodsByColumnID[sort.id]) {
return (a, b) => (
sortMethodsByColumnID[sort.id](a[sort.id], b[sort.id], sort.desc)
)
return (a, b) => {
return sortMethodsByColumnID[sort.id](a[sort.id], b[sort.id])
}
}
return (a, b) => {
return this.props.defaultSortMethod(a[sort.id], b[sort.id])
}
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 => {
@@ -427,7 +411,7 @@ export default Base =>
row[this.props.subRowsKey] = this.sortData(
row[this.props.subRowsKey],
sorted,
sortMethodsByColumnID,
sortMethodsByColumnID
)
})
@@ -437,7 +421,7 @@ export default Base =>
getMinRows () {
return _.getFirstDefined(
this.props.minRows,
this.getStateOrProp('pageSize'),
this.getStateOrProp('pageSize')
)
}
@@ -449,9 +433,10 @@ export default Base =>
if (collapseOnPageChange) {
newState.expanded = {}
}
this.setStateWithData(newState, () => (
this.setStateWithData(newState, () => {
onPageChange && onPageChange(page)
))
this.fireFetchData()
})
}
onPageSizeChange (newPageSize) {
@@ -467,16 +452,17 @@ export default Base =>
pageSize: newPageSize,
page: newPage,
},
() => (
() => {
onPageSizeChange && onPageSizeChange(newPageSize, newPage)
),
this.fireFetchData()
}
)
}
sortColumn (column, additive) {
const { sorted, skipNextSort, defaultSortDesc } = this.getResolvedState()
const firstSortDirection = Object.prototype.hasOwnProperty.call(column, 'defaultSortDesc')
const firstSortDirection = column.hasOwnProperty('defaultSortDesc')
? column.defaultSortDesc
: defaultSortDesc
const secondSortDirection = !firstSortDirection
@@ -516,18 +502,20 @@ export default Base =>
newSorted = [existing]
}
}
} else if (additive) {
newSorted.push({
id: column.id,
desc: firstSortDirection,
})
} else {
newSorted = [
{
if (additive) {
newSorted.push({
id: column.id,
desc: firstSortDirection,
},
]
})
} else {
newSorted = [
{
id: column.id,
desc: firstSortDirection,
},
]
}
}
} else {
// Multi-Sort
@@ -551,33 +539,35 @@ export default Base =>
if (!additive) {
newSorted = newSorted.slice(existingIndex, column.length)
}
// New Sort Column
} else if (additive) {
newSorted = newSorted.concat(
column.map(d => ({
} else {
// New Sort Column
if (additive) {
newSorted = newSorted.concat(
column.map(d => ({
id: d.id,
desc: firstSortDirection,
}))
)
} else {
newSorted = column.map(d => ({
id: d.id,
desc: firstSortDirection,
})),
)
} else {
newSorted = column.map(d => ({
id: d.id,
desc: firstSortDirection,
}))
}))
}
}
}
this.setStateWithData(
{
page:
(!sorted.length && newSorted.length) || !additive
? 0
: this.state.page,
page: (!sorted.length && newSorted.length) || !additive
? 0
: this.state.page,
sorted: newSorted,
},
() => (
() => {
onSortedChange && onSortedChange(newSorted, column, additive)
),
this.fireFetchData()
}
)
}
@@ -586,14 +576,16 @@ export default Base =>
const { onFilteredChange } = this.props
// Remove old filter first if it exists
const newFiltering = (filtered || []).filter(x => (
x.id !== column.id
))
const newFiltering = (filtered || []).filter(x => {
if (x.id !== column.id) {
return true
}
})
if (value !== '') {
newFiltering.push({
id: column.id,
value,
value: value,
})
}
@@ -601,14 +593,14 @@ export default Base =>
{
filtered: newFiltering,
},
() => (
() => {
onFilteredChange && onFilteredChange(newFiltering, column, value)
),
this.fireFetchData()
}
)
}
resizeColumnStart (event, column, isTouch) {
event.stopPropagation()
resizeColumnStart (column, event, isTouch) {
const parentWidth = event.target.parentElement.getBoundingClientRect()
.width
@@ -619,13 +611,12 @@ export default Base =>
pageX = event.pageX
}
this.trapEvents = true
this.setStateWithData(
{
currentlyResizing: {
id: column.id,
startX: pageX,
parentWidth,
parentWidth: parentWidth,
},
},
() => {
@@ -638,51 +629,12 @@ export default Base =>
document.addEventListener('mouseup', this.resizeColumnEnd)
document.addEventListener('mouseleave', this.resizeColumnEnd)
}
},
)
}
resizeColumnMoving (event) {
event.stopPropagation()
const { onResizedChange } = this.props
const { resized, currentlyResizing } = this.getResolvedState()
// Delete old value
const newResized = resized.filter(x => x.id !== currentlyResizing.id)
let pageX
if (event.type === 'touchmove') {
pageX = event.changedTouches[0].pageX
} else if (event.type === 'mousemove') {
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
const newWidth = Math.max(
currentlyResizing.parentWidth + pageX - currentlyResizing.startX,
11,
)
newResized.push({
id: currentlyResizing.id,
value: newWidth,
})
this.setStateWithData(
{
resized: newResized,
},
() => (
onResizedChange && onResizedChange(newResized, event)
),
}
)
}
resizeColumnEnd (event) {
event.stopPropagation()
const isTouch = event.type === 'touchend' || event.type === 'touchcancel'
let isTouch = event.type === 'touchend' || event.type === 'touchcancel'
if (isTouch) {
document.removeEventListener('touchmove', this.resizeColumnMoving)
@@ -706,4 +658,40 @@ export default Base =>
})
}
}
resizeColumnMoving (event) {
const { onResizedChange } = this.props
const { resized, currentlyResizing } = this.getResolvedState()
// Delete old value
const newResized = resized.filter(x => x.id !== currentlyResizing.id)
let pageX
if (event.type === 'touchmove') {
pageX = event.changedTouches[0].pageX
} else if (event.type === 'mousemove') {
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
const newWidth = Math.max(
currentlyResizing.parentWidth + pageX - currentlyResizing.startX,
11
)
newResized.push({
id: currentlyResizing.id,
value: newWidth,
})
this.setStateWithData(
{
resized: newResized,
},
() => {
onResizedChange && onResizedChange(newResized, event)
}
)
}
}
+39 -43
View File
@@ -3,11 +3,8 @@ import classnames from 'classnames'
//
// import _ from './utils'
const defaultButton = props => (
<button type="button" {...props} className="-btn">
{props.children}
</button>
)
const defaultButton = props =>
<button type='button' {...props} className='-btn'>{props.children}</button>
export default class ReactTablePagination extends Component {
constructor (props) {
@@ -42,7 +39,7 @@ export default class ReactTablePagination extends Component {
}
applyPage (e) {
if (e) { e.preventDefault() }
e && e.preventDefault()
const page = this.state.page
this.changePage(page === '' ? this.props.page : page)
}
@@ -70,9 +67,9 @@ export default class ReactTablePagination extends Component {
className={classnames(className, '-pagination')}
style={this.props.paginationStyle}
>
<div className="-previous">
<div className='-previous'>
<PreviousComponent
onClick={() => {
onClick={e => {
if (!canPrevious) return
this.changePage(page - 1)
}}
@@ -81,54 +78,53 @@ 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">
<input
type={this.state.page === '' ? 'text' : 'number'}
onChange={e => {
const val = e.target.value
const page = val - 1
if (val === '') {
return this.setState({ page: val })
}
this.setState({ page: this.getSafePage(page) })
}}
value={this.state.page === '' ? '' : this.state.page + 1}
onBlur={this.applyPage}
onKeyPress={e => {
if (e.which === 13 || e.keyCode === 13) {
this.applyPage()
}
}}
/>
</div>
: <span className="-currentPage">
{page + 1}
</span>}{' '}
? <div className='-pageJump'>
<input
type={this.state.page === '' ? 'text' : 'number'}
onChange={e => {
const val = e.target.value
const page = val - 1
if (val === '') {
return this.setState({ page: val })
}
this.setState({ page: this.getSafePage(page) })
}}
value={this.state.page === '' ? '' : this.state.page + 1}
onBlur={this.applyPage}
onKeyPress={e => {
if (e.which === 13 || e.keyCode === 13) {
this.applyPage()
}
}}
/>
</div>
: <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) => (
// eslint-disable-next-line react/no-array-index-key
<option key={i} value={option}>
{option} {this.props.rowsText}
</option>
))}
{pageSizeOptions.map((option, i) => {
return (
<option key={i} value={option}>
{option} {this.props.rowsText}
</option>
)
})}
</select>
</span>}
</div>
<div className="-next">
<div className='-next'>
<NextComponent
onClick={() => {
onClick={e => {
if (!canNext) return
this.changePage(page + 1)
}}
-194
View File
@@ -1,194 +0,0 @@
import PropTypes from 'prop-types'
export default {
// General
data: PropTypes.array,
loading: PropTypes.bool,
showPagination: PropTypes.bool,
showPaginationTop: PropTypes.bool,
showPaginationBottom: PropTypes.bool,
showPageSizeOptions: PropTypes.bool,
pageSizeOptions: PropTypes.array,
defaultPageSize: PropTypes.number,
showPageJump: PropTypes.bool,
collapseOnSortingChange: PropTypes.bool,
collapseOnPageChange: PropTypes.bool,
collapseOnDataChange: PropTypes.bool,
freezeWhenExpanded: PropTypes.bool,
sortable: PropTypes.bool,
resizable: PropTypes.bool,
filterable: PropTypes.bool,
defaultSortDesc: PropTypes.bool,
defaultSorted: PropTypes.array,
defaultFiltered: PropTypes.array,
defaultResized: PropTypes.array,
defaultExpanded: PropTypes.object,
defaultFilterMethod: PropTypes.func,
defaultSortMethod: PropTypes.func,
// Controlled State Callbacks
onPageChange: PropTypes.func,
onPageSizeChange: PropTypes.func,
onSortedChange: PropTypes.func,
onFilteredChange: PropTypes.func,
onResizedChange: PropTypes.func,
onExpandedChange: PropTypes.func,
// Pivoting
pivotBy: PropTypes.array,
// Key Constants
pivotValKey: PropTypes.string,
pivotIDKey: PropTypes.string,
subRowsKey: PropTypes.string,
aggregatedKey: PropTypes.string,
nestingLevelKey: PropTypes.string,
originalKey: PropTypes.string,
indexKey: PropTypes.string,
groupedByPivotKey: PropTypes.string,
// Server-side Callbacks
onFetchData: PropTypes.func,
// Classes
className: PropTypes.string,
style: PropTypes.object,
// Component decorators
getProps: PropTypes.func,
getTableProps: PropTypes.func,
getTheadGroupProps: PropTypes.func,
getTheadGroupTrProps: PropTypes.func,
getTheadGroupThProps: PropTypes.func,
getTheadProps: PropTypes.func,
getTheadTrProps: PropTypes.func,
getTheadThProps: PropTypes.func,
getTheadFilterProps: PropTypes.func,
getTheadFilterTrProps: PropTypes.func,
getTheadFilterThProps: PropTypes.func,
getTbodyProps: PropTypes.func,
getTrGroupProps: PropTypes.func,
getTrProps: PropTypes.func,
getTdProps: PropTypes.func,
getTfootProps: PropTypes.func,
getTfootTrProps: PropTypes.func,
getTfootTdProps: PropTypes.func,
getPaginationProps: PropTypes.func,
getLoadingProps: PropTypes.func,
getNoDataProps: PropTypes.func,
getResizerProps: PropTypes.func,
// Global Column Defaults
columns: PropTypes.arrayOf(
PropTypes.shape({
// Renderers
Cell: PropTypes.oneOfType([
PropTypes.element,
PropTypes.string,
PropTypes.func,
]),
Header: PropTypes.oneOfType([
PropTypes.element,
PropTypes.string,
PropTypes.func,
]),
Footer: PropTypes.oneOfType([
PropTypes.element,
PropTypes.string,
PropTypes.func,
]),
Aggregated: PropTypes.oneOfType([
PropTypes.element,
PropTypes.string,
PropTypes.func,
]),
Pivot: PropTypes.oneOfType([
PropTypes.element,
PropTypes.string,
PropTypes.func,
]),
PivotValue: PropTypes.oneOfType([
PropTypes.element,
PropTypes.string,
PropTypes.func,
]),
Expander: PropTypes.oneOfType([
PropTypes.element,
PropTypes.string,
PropTypes.func,
]),
Filter: PropTypes.oneOfType([PropTypes.element, PropTypes.func]),
// All Columns
sortable: PropTypes.bool, // use table default
resizable: PropTypes.bool, // use table default
filterable: PropTypes.bool, // use table default
show: PropTypes.bool,
minWidth: PropTypes.number,
// Cells only
className: PropTypes.string,
style: PropTypes.object,
getProps: PropTypes.func,
// Pivot only
aggregate: PropTypes.func,
// Headers only
headerClassName: PropTypes.string,
headerStyle: PropTypes.object,
getHeaderProps: PropTypes.func,
// Footers only
footerClassName: PropTypes.string,
footerStyle: PropTypes.object,
getFooterProps: PropTypes.object,
filterMethod: PropTypes.func,
filterAll: PropTypes.bool,
sortMethod: PropTypes.func,
}),
),
// Global Expander Column Defaults
expanderDefaults: PropTypes.shape({
sortable: PropTypes.bool,
resizable: PropTypes.bool,
filterable: PropTypes.bool,
width: PropTypes.number,
}),
pivotDefaults: PropTypes.object,
// Text
previousText: PropTypes.node,
nextText: PropTypes.node,
loadingText: PropTypes.node,
noDataText: PropTypes.node,
pageText: PropTypes.node,
ofText: PropTypes.node,
rowsText: PropTypes.node,
// Components
TableComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
TheadComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
TbodyComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
TrGroupComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
TrComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
ThComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
TdComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
TfootComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
FilterComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
ExpanderComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
PivotValueComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
AggregatedComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
// 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]),
NextComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
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]),
}
+24 -41
View File
@@ -19,7 +19,6 @@ export default {
compactObject,
isSortingDesc,
normalizeComponent,
asPx,
}
function get (obj, path, def) {
@@ -30,9 +29,7 @@ function get (obj, path, def) {
let val
try {
val = pathObj.reduce((current, pathPart) => current[pathPart], obj)
} catch (e) {
// continue regardless of error
}
} catch (e) {}
return typeof val !== 'undefined' ? val : def
}
@@ -61,7 +58,7 @@ function last (arr) {
function range (n) {
const arr = []
for (let i = 0; i < n; i += 1) {
for (let i = 0; i < n; i++) {
arr.push(n)
}
return arr
@@ -69,7 +66,7 @@ function range (n) {
function orderBy (arr, funcs, dirs, indexKey) {
return arr.sort((rowA, rowB) => {
for (let i = 0; i < funcs.length; i += 1) {
for (let i = 0; i < funcs.length; i++) {
const comp = funcs[i]
const desc = dirs[i] === false || dirs[i] === 'desc'
const sortInt = comp(rowA, rowB)
@@ -85,8 +82,8 @@ function orderBy (arr, funcs, dirs, indexKey) {
}
function remove (a, b) {
return a.filter((o, i) => {
const r = b(o)
return a.filter(function (o, i) {
var r = b(o)
if (r) {
a.splice(i, 1)
return true
@@ -103,7 +100,7 @@ function clone (a) {
return value.toString()
}
return value
}),
})
)
} catch (e) {
return a
@@ -111,7 +108,7 @@ function clone (a) {
}
function getFirstDefined (...args) {
for (let i = 0; i < args.length; i += 1) {
for (var i = 0; i < args.length; i++) {
if (typeof args[i] !== 'undefined') {
return args[i]
}
@@ -119,22 +116,16 @@ function getFirstDefined (...args) {
}
function sum (arr) {
return arr.reduce((a, b) => (
a + b
), 0)
return arr.reduce((a, b) => {
return a + b
}, 0)
}
function makeTemplateComponent (compClass, displayName) {
if (!displayName) {
throw new Error('No displayName found for template component:', compClass)
}
const cmp = ({ children, className, ...rest }) => (
function makeTemplateComponent (compClass) {
return ({ children, className, ...rest }) =>
<div className={classnames(compClass, className)} {...rest}>
{children}
</div>
)
cmp.displayName = displayName
return cmp
}
function groupBy (xs, key) {
@@ -146,11 +137,6 @@ function groupBy (xs, key) {
}, {})
}
function asPx (value) {
value = Number(value)
return Number.isNaN(value) ? null : `${value}px`
}
function isArray (a) {
return Array.isArray(a)
}
@@ -162,8 +148,8 @@ function isArray (a) {
function makePathArray (obj) {
return flattenDeep(obj)
.join('.')
.replace(/\[/g, '.')
.replace(/\]/g, '')
.replace('[', '.')
.replace(']', '')
.split('.')
}
@@ -171,7 +157,7 @@ function flattenDeep (arr, newArr = []) {
if (!isArray(arr)) {
newArr.push(arr)
} else {
for (let i = 0; i < arr.length; i += 1) {
for (var i = 0; i < arr.length; i++) {
flattenDeep(arr[i], newArr)
}
}
@@ -182,23 +168,20 @@ function splitProps ({ className, style, ...rest }) {
return {
className,
style,
rest: rest || {},
rest,
}
}
function compactObject (obj) {
const newObj = {}
if (obj) {
Object.keys(obj).map(key => {
if (
Object.prototype.hasOwnProperty.call(obj, key) &&
obj[key] !== undefined &&
typeof obj[key] !== 'undefined'
) {
newObj[key] = obj[key]
}
return true
})
for (var key in obj) {
if (
obj.hasOwnProperty(key) &&
obj[key] !== undefined &&
typeof obj[key] !== 'undefined'
) {
newObj[key] = obj[key]
}
}
return newObj
}
+88 -711
View File
File diff suppressed because it is too large Load Diff