mirror of
https://github.com/gosticks/react-table.git
synced 2026-08-19 16:30:21 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a9ebf09da |
@@ -1 +0,0 @@
|
||||
* text=auto
|
||||
@@ -1,46 +0,0 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
|
||||
---
|
||||
|
||||
# Using v6?
|
||||
|
||||
v6 is now considered feature complete to its current abilities and limitations. We are not actively working to fix any issues for v6 any more. We will, however, merge any non-breaking pull requests submitted to fix anything in v6.
|
||||
|
||||
# Using v7?
|
||||
|
||||
Thanks for using the alpha version of React Table v7! We're very excited about it.
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Codesandbox!**
|
||||
Use a new [react-table codesandbox](https://codesandbox.io/s/m5lxzzpz69) to reproduce the issue.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Desktop (please complete the following information):**
|
||||
- OS: [e.g. iOS]
|
||||
- Browser [e.g. chrome, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Smartphone (please complete the following information):**
|
||||
- Device: [e.g. iPhone6]
|
||||
- OS: [e.g. iOS8.1]
|
||||
- Browser [e.g. stock browser, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
@@ -1,9 +0,0 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
|
||||
---
|
||||
|
||||
# STOP
|
||||
|
||||
We do not track feature requests through Github. Please use the [Spectrum React Table Forum](https://spectrum.chat/react-table) to talk about new ideas and features.
|
||||
@@ -1,11 +0,0 @@
|
||||
---
|
||||
name: Questions, Support & Help
|
||||
about: Looking for help? Need a question answered?
|
||||
|
||||
---
|
||||
|
||||
# STOP
|
||||
|
||||
We do not use Github to track general support. Please use our public support forum at https://spectrum.chat/react-table.
|
||||
|
||||
NOTE: If a support/help/question issue is opened, it will be closed immediately and be redirected to the forum. Thanks for helping us keep our issues clean and productive!
|
||||
@@ -8,4 +8,3 @@ react-table.css
|
||||
*.log
|
||||
.idea
|
||||
.DS_Store
|
||||
.history
|
||||
|
||||
@@ -1,15 +1,3 @@
|
||||
## 6.8.6
|
||||
|
||||
#### Fixes & Optimizations
|
||||
|
||||
* Since `resolveData` is now capable of materializing data on it's own, the `data` prop is no longer required as a prop-type.
|
||||
|
||||
## 6.8.4
|
||||
|
||||
#### Fixes & Optimizations
|
||||
|
||||
* Only run `resolveData` prop when `data` prop has changed, not any others.
|
||||
|
||||
## 6.8.3
|
||||
|
||||
#### Fixes & Optimizations
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
## 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...
|
||||
|
||||
## What bug are you experiencing, or what feature are you proposing?
|
||||
|
||||
Please include a detailed explanation here...
|
||||
|
||||
## 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?
|
||||
|
||||
1. list the steps
|
||||
2. to reproduce
|
||||
3. the issue
|
||||
@@ -0,0 +1,77 @@
|
||||
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 }]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
react-table.js.org
|
||||
+1628
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"name": "new",
|
||||
"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"
|
||||
},
|
||||
"dependencies": {
|
||||
"eslint-config-react-tools": "^1.0.10",
|
||||
"github-markdown-css": "^2.6.0",
|
||||
"marked": "^0.3.6",
|
||||
"namor": "^1.0.1",
|
||||
"raw-loader": "^0.5.1",
|
||||
"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"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test --env=jsdom",
|
||||
"eject": "react-scripts eject"
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
@@ -0,0 +1,31 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tag above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React Table - A lightweight, fast and extendable datagrid built for React</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start`.
|
||||
To create a production bundle, use `npm run build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
/* 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") }
|
||||
];
|
||||
|
||||
export default class App extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<ReactStory
|
||||
style={{
|
||||
display: "block",
|
||||
width: "100%",
|
||||
height: "100%"
|
||||
}}
|
||||
pathPrefix="story/"
|
||||
StoryWrapper={props => (
|
||||
<defaultProps.StoryWrapper
|
||||
css={{
|
||||
padding: 0,
|
||||
display: "flex",
|
||||
flexDirection: "column"
|
||||
}}
|
||||
>
|
||||
<a
|
||||
href="//github.com/react-tools/react-table"
|
||||
style={{
|
||||
display: "block",
|
||||
textAlign: "center",
|
||||
borderBottom: "solid 3px #cccccc"
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src="https://github.com/react-tools/media/raw/master/logo-react-table.png"
|
||||
alt="React Table Logo"
|
||||
style={{
|
||||
width: "150px",
|
||||
padding: "10px"
|
||||
}}
|
||||
/>
|
||||
</a>
|
||||
<div
|
||||
{...props}
|
||||
style={{
|
||||
flex: "1 0 auto",
|
||||
position: "relative"
|
||||
}}
|
||||
/>
|
||||
</defaultProps.StoryWrapper>
|
||||
)}
|
||||
stories={stories}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
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"
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,94 @@
|
||||
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;
|
||||
};
|
||||
@@ -0,0 +1,148 @@
|
||||
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;
|
||||
@@ -0,0 +1,60 @@
|
||||
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' : ''}`}>
|
||||
// •
|
||||
// </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}
|
||||
// />
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
@@ -0,0 +1,7 @@
|
||||
/* eslint-disable */
|
||||
|
||||
import TreeTable from "./treetable";
|
||||
import SelectTable from "./selecttable";
|
||||
import SelectTreeTable from "./selecttreetable";
|
||||
|
||||
export { TreeTable, SelectTable, SelectTreeTable };
|
||||
@@ -0,0 +1,173 @@
|
||||
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;
|
||||
@@ -0,0 +1,238 @@
|
||||
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;
|
||||
@@ -0,0 +1,70 @@
|
||||
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;
|
||||
@@ -0,0 +1,53 @@
|
||||
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;
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
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)
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
html,
|
||||
body,
|
||||
#root {
|
||||
height: 100%;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
//
|
||||
import "./index.css";
|
||||
import App from "./App.js";
|
||||
|
||||
ReactDOM.render(<App />, document.getElementById("root"));
|
||||
@@ -0,0 +1,23 @@
|
||||
/* eslint-disable */
|
||||
import React from "react";
|
||||
import marked from "marked";
|
||||
//
|
||||
import HOCReadme from "!raw!../../../src/hoc/README.md";
|
||||
import "github-markdown-css/github-markdown.css";
|
||||
import "./utils/prism.js";
|
||||
|
||||
export default class HOCStory extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div style={{ padding: "10px" }}>
|
||||
<span
|
||||
className="markdown-body"
|
||||
dangerouslySetInnerHTML={{ __html: marked(HOCReadme) }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
componentDidMount() {
|
||||
global.Prism && global.Prism.highlightAll();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/* eslint-disable import/no-webpack-loader-syntax */
|
||||
import React from "react";
|
||||
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() {
|
||||
return (
|
||||
<div style={{ padding: "10px" }}>
|
||||
<span
|
||||
className="markdown-body"
|
||||
dangerouslySetInnerHTML={{ __html: marked(Readme) }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
componentDidMount() {
|
||||
global.Prism && global.Prism.highlightAll();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
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>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/* http://prismjs.com/download.html?themes=prism&languages=markup+css+clike+javascript */
|
||||
/**
|
||||
* prism.js default theme for JavaScript, CSS and HTML
|
||||
* Based on dabblet (http://dabblet.com)
|
||||
* @author Lea Verou
|
||||
*/
|
||||
|
||||
code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
color: black;
|
||||
background: none;
|
||||
text-shadow: 0 1px white;
|
||||
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
|
||||
text-align: left;
|
||||
white-space: pre;
|
||||
word-spacing: normal;
|
||||
word-break: normal;
|
||||
word-wrap: normal;
|
||||
line-height: 1.5;
|
||||
|
||||
-moz-tab-size: 4;
|
||||
-o-tab-size: 4;
|
||||
tab-size: 4;
|
||||
|
||||
-webkit-hyphens: none;
|
||||
-moz-hyphens: none;
|
||||
-ms-hyphens: none;
|
||||
hyphens: none;
|
||||
}
|
||||
|
||||
pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection,
|
||||
code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection {
|
||||
text-shadow: none;
|
||||
background: #b3d4fc;
|
||||
}
|
||||
|
||||
pre[class*="language-"]::selection, pre[class*="language-"] ::selection,
|
||||
code[class*="language-"]::selection, code[class*="language-"] ::selection {
|
||||
text-shadow: none;
|
||||
background: #b3d4fc;
|
||||
}
|
||||
|
||||
@media print {
|
||||
code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
text-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Code blocks */
|
||||
pre[class*="language-"] {
|
||||
padding: 1em;
|
||||
margin: .5em 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
:not(pre) > code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
background: #f5f2f0;
|
||||
}
|
||||
|
||||
/* Inline code */
|
||||
:not(pre) > code[class*="language-"] {
|
||||
padding: .1em;
|
||||
border-radius: .3em;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.token.comment,
|
||||
.token.prolog,
|
||||
.token.doctype,
|
||||
.token.cdata {
|
||||
color: slategray;
|
||||
}
|
||||
|
||||
.token.punctuation {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.namespace {
|
||||
opacity: .7;
|
||||
}
|
||||
|
||||
.token.property,
|
||||
.token.tag,
|
||||
.token.boolean,
|
||||
.token.number,
|
||||
.token.constant,
|
||||
.token.symbol,
|
||||
.token.deleted {
|
||||
color: #905;
|
||||
}
|
||||
|
||||
.token.selector,
|
||||
.token.attr-name,
|
||||
.token.string,
|
||||
.token.char,
|
||||
.token.builtin,
|
||||
.token.inserted {
|
||||
color: #690;
|
||||
}
|
||||
|
||||
.token.operator,
|
||||
.token.entity,
|
||||
.token.url,
|
||||
.language-css .token.string,
|
||||
.style .token.string {
|
||||
color: #a67f59;
|
||||
background: hsla(0, 0%, 100%, .5);
|
||||
}
|
||||
|
||||
.token.atrule,
|
||||
.token.attr-value,
|
||||
.token.keyword {
|
||||
color: #07a;
|
||||
}
|
||||
|
||||
.token.function {
|
||||
color: #DD4A68;
|
||||
}
|
||||
|
||||
.token.regex,
|
||||
.token.important,
|
||||
.token.variable {
|
||||
color: #e90;
|
||||
}
|
||||
|
||||
.token.important,
|
||||
.token.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
.token.italic {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.token.entity {
|
||||
cursor: help;
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
+7301
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 152 KiB |
Generated
-8348
File diff suppressed because it is too large
Load Diff
+107
-40
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "react-table",
|
||||
"version": "7.0.0-alpha.1",
|
||||
"version": "6.8.6",
|
||||
"description": "A fast, lightweight, opinionated table and datagrid built on React",
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/tannerlinsley/react-table#readme",
|
||||
"homepage": "https://github.com/react-tools/react-table#readme",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/tannerlinsley/react-table.git"
|
||||
"url": "git+https://github.com/react-tools/react-table.git"
|
||||
},
|
||||
"keywords": [
|
||||
"react",
|
||||
@@ -14,18 +14,8 @@
|
||||
"react-table",
|
||||
"datagrid"
|
||||
],
|
||||
"main": "dist/index.js",
|
||||
"_module": "dist/index.es.js",
|
||||
"_jsnext:main": "dist/index.es.js",
|
||||
"scripts": {
|
||||
"test": "cross-env CI=1 react-scripts test --env=jsdom",
|
||||
"test:watch": "react-scripts test --env=jsdom",
|
||||
"build": "rollup -c",
|
||||
"start": "rollup -c -w",
|
||||
"prepare": "yarn build",
|
||||
"release": "yarn publish",
|
||||
"releaseNext": "yarn publish --tag next"
|
||||
},
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
"files": [
|
||||
"src/",
|
||||
"es/",
|
||||
@@ -35,33 +25,110 @@
|
||||
"react-table.css",
|
||||
"media/*.png"
|
||||
],
|
||||
"scripts": {
|
||||
"build:cjs": "babel src --out-dir lib --source-maps inline",
|
||||
"build:es": "BABEL_ENV=es babel src --out-dir es --source-maps inline",
|
||||
"build:umd": "BABEL_ENV=umd rollup -c",
|
||||
"build:umd-min": "BABEL_ENV=umd NODE_ENV=production rollup -c",
|
||||
"build:css": "rimraf react-table.css && stylus src/index.styl --compress -o react-table.css && yarn css:autoprefix",
|
||||
"css:autoprefix": "postcss --use autoprefixer react-table.css -r",
|
||||
"watch": "npm-run-all --parallel watch:*",
|
||||
"watch:js": "onchange 'src/**/*.js' -i -- yarn build:cjs",
|
||||
"watch:css": "onchange 'src/**/*.styl' -i -- yarn build:css",
|
||||
"test": "eslint src",
|
||||
"build": "npm-run-all build:*",
|
||||
"prepublish": "yarn build",
|
||||
"postpublish": "git push --tags",
|
||||
"docs": "yarn watch & cd docs && yarn && yarn start",
|
||||
"docs:build": "yarn build && cd docs && yarn && yarn build"
|
||||
},
|
||||
"dependencies": {
|
||||
"classnames": "^2.2.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"prop-types": "^15.5.0",
|
||||
"react": "^16.7.0-alpha.0 || ^16.8.x",
|
||||
"react-dom": "^16.7.0-alpha.0 || ^16.8.x"
|
||||
"react": "^15.x.x || ^16.x.x"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/plugin-proposal-class-properties": "^7.2.1",
|
||||
"@babel/preset-env": "^7.2.0",
|
||||
"@babel/preset-react": "^7.0.0",
|
||||
"@babel/runtime": "^7.2.0",
|
||||
"@svgr/rollup": "^4.1.0",
|
||||
"babel-core": "7.0.0-bridge.0",
|
||||
"babel-eslint": "^10.0.1",
|
||||
"cross-env": "^5.1.4",
|
||||
"eslint": "^5.10.0",
|
||||
"eslint-config-standard": "^12.0.0",
|
||||
"eslint-config-standard-react": "^7.0.2",
|
||||
"eslint-plugin-import": "^2.13.0",
|
||||
"eslint-plugin-node": "^8.0.0",
|
||||
"eslint-plugin-promise": "^4.0.0",
|
||||
"eslint-plugin-react": "^7.10.0",
|
||||
"eslint-plugin-standard": "^4.0.0",
|
||||
"rollup": "^0.68.0",
|
||||
"rollup-plugin-babel": "^4.1.0",
|
||||
"rollup-plugin-commonjs": "^9.1.3",
|
||||
"rollup-plugin-node-resolve": "^4.0.0",
|
||||
"rollup-plugin-peer-deps-external": "^2.2.0",
|
||||
"rollup-plugin-uglify": "^6.0.2"
|
||||
"autoprefixer": "^6.7.0",
|
||||
"babel-cli": "6.14.0",
|
||||
"babel-eslint": "6.1.2",
|
||||
"babel-plugin-external-helpers": "^6.22.0",
|
||||
"babel-plugin-transform-class-properties": "^6.24.1",
|
||||
"babel-plugin-transform-object-rest-spread": "^6.26.0",
|
||||
"babel-preset-env": "^1.6.1",
|
||||
"babel-preset-react": "^6.24.1",
|
||||
"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": "^4.1.2",
|
||||
"onchange": "^3.0.2",
|
||||
"postcss-cli": "^2.6.0",
|
||||
"prop-types": "^15.6.0",
|
||||
"react": "^16.3.2",
|
||||
"react-dom": "^16.3.2",
|
||||
"react-json-tree": "^0.10.9",
|
||||
"rimraf": "^2.6.1",
|
||||
"rollup": "^0.55.3",
|
||||
"rollup-plugin-babel": "^3.0.3",
|
||||
"rollup-plugin-commonjs": "^8.3.0",
|
||||
"rollup-plugin-node-resolve": "^3.0.2",
|
||||
"rollup-plugin-replace": "^2.0.0",
|
||||
"rollup-plugin-uglify": "^3.0.0",
|
||||
"standard": "^10.0.2",
|
||||
"stylus": "^0.54.5"
|
||||
},
|
||||
"babel": {
|
||||
"env": {
|
||||
"development": {
|
||||
"presets": [
|
||||
[
|
||||
"env",
|
||||
{
|
||||
"modules": "commonjs"
|
||||
}
|
||||
],
|
||||
"react"
|
||||
],
|
||||
"plugins": [
|
||||
"transform-object-rest-spread",
|
||||
"transform-class-properties"
|
||||
]
|
||||
},
|
||||
"es": {
|
||||
"presets": [
|
||||
[
|
||||
"env",
|
||||
{
|
||||
"modules": false
|
||||
}
|
||||
],
|
||||
"react"
|
||||
],
|
||||
"plugins": [
|
||||
"transform-object-rest-spread",
|
||||
"transform-class-properties"
|
||||
]
|
||||
},
|
||||
"umd": {
|
||||
"presets": [
|
||||
[
|
||||
"env",
|
||||
{
|
||||
"modules": false
|
||||
}
|
||||
],
|
||||
"react"
|
||||
],
|
||||
"plugins": [
|
||||
"transform-object-rest-spread",
|
||||
"transform-class-properties",
|
||||
"external-helpers"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
export function sum (values, rows) {
|
||||
return values.reduce((sum, next) => sum + next, 0)
|
||||
}
|
||||
|
||||
export function average (values, rows) {
|
||||
return Math.round((sum(values, rows) / values.length) * 100) / 100
|
||||
}
|
||||
@@ -0,0 +1,264 @@
|
||||
import React from 'react'
|
||||
import classnames from 'classnames'
|
||||
//
|
||||
import _ from './utils'
|
||||
import Pagination from './pagination'
|
||||
|
||||
const emptyObj = () => ({})
|
||||
|
||||
export default {
|
||||
// General
|
||||
data: [],
|
||||
resolveData: data => data,
|
||||
loading: false,
|
||||
showPagination: true,
|
||||
showPaginationTop: false,
|
||||
showPaginationBottom: true,
|
||||
showPageSizeOptions: true,
|
||||
pageSizeOptions: [5, 10, 20, 25, 50, 100],
|
||||
defaultPageSize: 20,
|
||||
showPageJump: true,
|
||||
collapseOnSortingChange: true,
|
||||
collapseOnPageChange: true,
|
||||
collapseOnDataChange: true,
|
||||
freezeWhenExpanded: false,
|
||||
sortable: true,
|
||||
multiSort: true,
|
||||
resizable: true,
|
||||
filterable: false,
|
||||
defaultSortDesc: false,
|
||||
defaultSorted: [],
|
||||
defaultFiltered: [],
|
||||
defaultResized: [],
|
||||
defaultExpanded: {},
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
defaultFilterMethod: (filter, row, column) => {
|
||||
const id = filter.pivotId || filter.id
|
||||
return row[id] !== undefined ? String(row[id]).startsWith(filter.value) : true
|
||||
},
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
defaultSortMethod: (a, b, desc) => {
|
||||
// force null and undefined to the bottom
|
||||
a = a === null || a === undefined ? '' : a
|
||||
b = b === null || b === undefined ? '' : b
|
||||
// force any string values to lowercase
|
||||
a = typeof a === 'string' ? a.toLowerCase() : a
|
||||
b = typeof b === 'string' ? b.toLowerCase() : b
|
||||
// Return either 1 or -1 to indicate a sort priority
|
||||
if (a > b) {
|
||||
return 1
|
||||
}
|
||||
if (a < b) {
|
||||
return -1
|
||||
}
|
||||
// returning 0, undefined or any falsey value will use subsequent sorts or
|
||||
// the index as a tiebreaker
|
||||
return 0
|
||||
},
|
||||
|
||||
// Controlled State Props
|
||||
// page: undefined,
|
||||
// pageSize: undefined,
|
||||
// sorted: [],
|
||||
// filtered: [],
|
||||
// resized: [],
|
||||
// expanded: {},
|
||||
|
||||
// Controlled State Callbacks
|
||||
onPageChange: undefined,
|
||||
onPageSizeChange: undefined,
|
||||
onSortedChange: undefined,
|
||||
onFilteredChange: undefined,
|
||||
onResizedChange: undefined,
|
||||
onExpandedChange: undefined,
|
||||
|
||||
// Pivoting
|
||||
pivotBy: undefined,
|
||||
|
||||
// Key Constants
|
||||
pivotValKey: '_pivotVal',
|
||||
pivotIDKey: '_pivotID',
|
||||
subRowsKey: '_subRows',
|
||||
aggregatedKey: '_aggregated',
|
||||
nestingLevelKey: '_nestingLevel',
|
||||
originalKey: '_original',
|
||||
indexKey: '_index',
|
||||
groupedByPivotKey: '_groupedByPivot',
|
||||
|
||||
// Server-side Callbacks
|
||||
onFetchData: () => null,
|
||||
|
||||
// Classes
|
||||
className: '',
|
||||
style: {},
|
||||
|
||||
// Component decorators
|
||||
getProps: emptyObj,
|
||||
getTableProps: emptyObj,
|
||||
getTheadGroupProps: emptyObj,
|
||||
getTheadGroupTrProps: emptyObj,
|
||||
getTheadGroupThProps: emptyObj,
|
||||
getTheadProps: emptyObj,
|
||||
getTheadTrProps: emptyObj,
|
||||
getTheadThProps: emptyObj,
|
||||
getTheadFilterProps: emptyObj,
|
||||
getTheadFilterTrProps: emptyObj,
|
||||
getTheadFilterThProps: emptyObj,
|
||||
getTbodyProps: emptyObj,
|
||||
getTrGroupProps: emptyObj,
|
||||
getTrProps: emptyObj,
|
||||
getTdProps: emptyObj,
|
||||
getTfootProps: emptyObj,
|
||||
getTfootTrProps: emptyObj,
|
||||
getTfootTdProps: emptyObj,
|
||||
getPaginationProps: emptyObj,
|
||||
getLoadingProps: emptyObj,
|
||||
getNoDataProps: emptyObj,
|
||||
getResizerProps: emptyObj,
|
||||
|
||||
// Global Column Defaults
|
||||
column: {
|
||||
// Renderers
|
||||
Cell: undefined,
|
||||
Header: undefined,
|
||||
Footer: undefined,
|
||||
Aggregated: undefined,
|
||||
Pivot: undefined,
|
||||
PivotValue: undefined,
|
||||
Expander: undefined,
|
||||
Filter: undefined,
|
||||
// All Columns
|
||||
sortable: undefined, // use table default
|
||||
resizable: undefined, // use table default
|
||||
filterable: undefined, // use table default
|
||||
show: true,
|
||||
minWidth: 100,
|
||||
// Cells only
|
||||
className: '',
|
||||
style: {},
|
||||
getProps: emptyObj,
|
||||
// Pivot only
|
||||
aggregate: undefined,
|
||||
// Headers only
|
||||
headerClassName: '',
|
||||
headerStyle: {},
|
||||
getHeaderProps: emptyObj,
|
||||
// Footers only
|
||||
footerClassName: '',
|
||||
footerStyle: {},
|
||||
getFooterProps: emptyObj,
|
||||
filterMethod: undefined,
|
||||
filterAll: false,
|
||||
sortMethod: undefined,
|
||||
},
|
||||
|
||||
// Global Expander Column Defaults
|
||||
expanderDefaults: {
|
||||
sortable: false,
|
||||
resizable: false,
|
||||
filterable: false,
|
||||
width: 35,
|
||||
},
|
||||
|
||||
pivotDefaults: {
|
||||
// extend the defaults for pivoted columns here
|
||||
},
|
||||
|
||||
// Text
|
||||
previousText: 'Previous',
|
||||
nextText: 'Next',
|
||||
loadingText: 'Loading...',
|
||||
noDataText: 'No rows found',
|
||||
pageText: 'Page',
|
||||
ofText: 'of',
|
||||
rowsText: 'rows',
|
||||
|
||||
// Components
|
||||
TableComponent: ({ children, className, ...rest }) => (
|
||||
<div
|
||||
className={classnames('rt-table', className)}
|
||||
role="grid"
|
||||
// tabIndex='0'
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
),
|
||||
TheadComponent: _.makeTemplateComponent('rt-thead', 'Thead'),
|
||||
TbodyComponent: _.makeTemplateComponent('rt-tbody', 'Tbody'),
|
||||
TrGroupComponent: ({ children, className, ...rest }) => (
|
||||
<div className={classnames('rt-tr-group', className)} role="rowgroup" {...rest}>
|
||||
{children}
|
||||
</div>
|
||||
),
|
||||
TrComponent: ({ children, className, ...rest }) => (
|
||||
<div className={classnames('rt-tr', className)} role="row" {...rest}>
|
||||
{children}
|
||||
</div>
|
||||
),
|
||||
ThComponent: ({
|
||||
toggleSort, className, children, ...rest
|
||||
}) => (
|
||||
// eslint-disable-next-line jsx-a11y/click-events-have-key-events
|
||||
<div
|
||||
className={classnames('rt-th', className)}
|
||||
onClick={e => toggleSort && toggleSort(e)}
|
||||
role="columnheader"
|
||||
tabIndex="-1" // Resolves eslint issues without implementing keyboard navigation incorrectly
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
),
|
||||
TdComponent: ({
|
||||
toggleSort, className, children, ...rest
|
||||
}) => (
|
||||
<div className={classnames('rt-td', className)} role="gridcell" {...rest}>
|
||||
{children}
|
||||
</div>
|
||||
),
|
||||
TfootComponent: _.makeTemplateComponent('rt-tfoot', 'Tfoot'),
|
||||
FilterComponent: ({ filter, onChange }) => (
|
||||
<input
|
||||
type="text"
|
||||
style={{
|
||||
width: '100%',
|
||||
}}
|
||||
value={filter ? filter.value : ''}
|
||||
onChange={event => onChange(event.target.value)}
|
||||
/>
|
||||
),
|
||||
ExpanderComponent: ({ isExpanded }) => (
|
||||
<div className={classnames('rt-expander', isExpanded && '-open')}>•</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
|
||||
<span key={i}>
|
||||
{row[column.id]}
|
||||
{i < subRows.length - 1 ? ', ' : ''}
|
||||
</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
|
||||
}) => (
|
||||
<div className={classnames('-loading', { '-active': loading }, className)} {...rest}>
|
||||
<div className="-loading-inner">{loadingText}</div>
|
||||
</div>
|
||||
),
|
||||
NoDataComponent: _.makeTemplateComponent('rt-noData', 'NoData'),
|
||||
ResizerComponent: _.makeTemplateComponent('rt-resizer', 'Resizer'),
|
||||
PadRowComponent: () => <span> </span>,
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
<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
|
||||
|
||||
**Note:** The select field defaults to the accessor `_id` property in order to render the select field for that particular row. If your objects have different
|
||||
unique ID fields, make sure to tell React Table that by passing it the `keyField` property.
|
||||
|
||||
```Javascript
|
||||
<ReactTable keyField='id' />
|
||||
```
|
||||
|
||||
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.
|
||||
@@ -0,0 +1,115 @@
|
||||
/* 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,
|
||||
selectWidth,
|
||||
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: selectWidth || 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
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/* 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
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
import { useMemo } from 'react'
|
||||
|
||||
export default function useAccessedRows ({
|
||||
debug, data, columns, subRowsKey,
|
||||
}) {
|
||||
return useMemo(
|
||||
() => {
|
||||
if (debug) console.info('getAccessedRows')
|
||||
|
||||
// Access the row's data
|
||||
const accessRow = (data, i, depth = 0) => {
|
||||
// Keep the original reference around
|
||||
const original = data
|
||||
|
||||
// Process any subRows
|
||||
const subRows = data[subRowsKey]
|
||||
? data[subRowsKey].map((d, i) => accessRow(d, i, depth + 1))
|
||||
: undefined
|
||||
|
||||
const row = {
|
||||
original,
|
||||
index: i,
|
||||
subRows,
|
||||
depth,
|
||||
}
|
||||
|
||||
// Create the cells and values
|
||||
row.values = {}
|
||||
columns.forEach(column => {
|
||||
row.values[column.id] = column.accessor ? column.accessor(data) : undefined
|
||||
})
|
||||
|
||||
return row
|
||||
}
|
||||
|
||||
// Use the resolved data
|
||||
return data.map((d, i) => accessRow(d, i))
|
||||
},
|
||||
[data, columns]
|
||||
)
|
||||
}
|
||||
@@ -1,201 +0,0 @@
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import { getFirstDefined, getBy } from '../utils'
|
||||
|
||||
export default function useColumns ({
|
||||
debug,
|
||||
groupBy,
|
||||
userColumns,
|
||||
disableSorting,
|
||||
disableGrouping,
|
||||
disableFilters,
|
||||
}) {
|
||||
return useMemo(
|
||||
() => {
|
||||
if (debug) console.info('getColumns')
|
||||
|
||||
// Decorate All the columns
|
||||
const columnTree = decorateColumnTree(userColumns)
|
||||
|
||||
// Get the flat list of all columns
|
||||
let columns = flattenBy(columnTree, 'columns')
|
||||
|
||||
columns = [
|
||||
...groupBy.map(g => columns.find(col => col.id === g)),
|
||||
...columns.filter(col => !groupBy.includes(col.id)),
|
||||
]
|
||||
|
||||
// Get headerGroups
|
||||
const headerGroups = makeHeaderGroups(columns, findMaxDepth(columnTree))
|
||||
const headers = flattenBy(headerGroups, 'headers')
|
||||
|
||||
return {
|
||||
columns,
|
||||
headerGroups,
|
||||
headers,
|
||||
}
|
||||
},
|
||||
[groupBy, userColumns]
|
||||
)
|
||||
|
||||
// Find the depth of the columns
|
||||
function findMaxDepth (columns, depth = 0) {
|
||||
return columns.reduce((prev, curr) => {
|
||||
if (curr.columns) {
|
||||
return Math.max(prev, findMaxDepth(curr.columns, depth + 1))
|
||||
}
|
||||
return depth
|
||||
}, 0)
|
||||
}
|
||||
|
||||
function decorateColumn (column, parent) {
|
||||
// First check for string accessor
|
||||
let {
|
||||
id, accessor, Header, canSortBy, canGroupBy, canFilter,
|
||||
} = column
|
||||
|
||||
if (typeof accessor === 'string') {
|
||||
id = id || accessor
|
||||
const accessorString = accessor
|
||||
accessor = row => getBy(row, accessorString)
|
||||
}
|
||||
|
||||
const grouped = groupBy.includes(id)
|
||||
|
||||
canSortBy = accessor
|
||||
? getFirstDefined(canSortBy, disableSorting === true ? false : undefined, true)
|
||||
: false
|
||||
canGroupBy = accessor
|
||||
? getFirstDefined(canGroupBy, disableGrouping === true ? false : undefined, true)
|
||||
: false
|
||||
canFilter = accessor
|
||||
? getFirstDefined(canFilter, disableFilters === true ? false : undefined, true)
|
||||
: false
|
||||
|
||||
if (!id && typeof Header === 'string') {
|
||||
id = Header
|
||||
}
|
||||
|
||||
if (!id) {
|
||||
// Accessor, but no column id? This is bad.
|
||||
console.error(column)
|
||||
throw new Error('A column id is required!')
|
||||
}
|
||||
|
||||
column = {
|
||||
Header: '',
|
||||
Cell: cell => cell.value,
|
||||
show: true,
|
||||
...column,
|
||||
grouped,
|
||||
canSortBy,
|
||||
canGroupBy,
|
||||
canFilter,
|
||||
id,
|
||||
accessor,
|
||||
parent,
|
||||
}
|
||||
|
||||
column.Aggregated = column.Aggregated || column.Cell
|
||||
|
||||
return column
|
||||
}
|
||||
|
||||
// Build the visible columns, headers and flat column list
|
||||
function decorateColumnTree (columns, parent, depth = 0) {
|
||||
return columns.map(column => {
|
||||
column = decorateColumn(column, parent)
|
||||
if (column.columns) {
|
||||
column.columns = decorateColumnTree(column.columns, column, depth + 1)
|
||||
}
|
||||
return column
|
||||
})
|
||||
}
|
||||
|
||||
function flattenBy (columns, childKey) {
|
||||
const flatColumns = []
|
||||
|
||||
const recurse = columns => {
|
||||
columns.forEach(d => {
|
||||
if (!d[childKey]) {
|
||||
flatColumns.push(d)
|
||||
} else {
|
||||
recurse(d[childKey])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
recurse(columns)
|
||||
|
||||
return flatColumns
|
||||
}
|
||||
|
||||
// Build the header groups from the bottom up
|
||||
function makeHeaderGroups (columns, maxDepth) {
|
||||
const headerGroups = []
|
||||
|
||||
const removeChildColumns = column => {
|
||||
delete column.columns
|
||||
if (column.parent) {
|
||||
removeChildColumns(column.parent)
|
||||
}
|
||||
}
|
||||
columns.forEach(removeChildColumns)
|
||||
|
||||
const buildGroup = (columns, depth = 0) => {
|
||||
const headerGroup = {
|
||||
headers: [],
|
||||
}
|
||||
|
||||
const parentColumns = []
|
||||
|
||||
const hasParents = columns.some(col => col.parent)
|
||||
|
||||
columns.forEach(column => {
|
||||
const isFirst = !parentColumns.length
|
||||
let latestParentColumn = [...parentColumns].reverse()[0]
|
||||
|
||||
// If the column has a parent, add it if necessary
|
||||
if (column.parent) {
|
||||
if (isFirst || latestParentColumn.originalID !== column.parent.id) {
|
||||
parentColumns.push({
|
||||
...column.parent,
|
||||
originalID: column.parent.id,
|
||||
id: [column.parent.id, parentColumns.length].join('_'),
|
||||
})
|
||||
}
|
||||
} else if (hasParents) {
|
||||
// If other columns have parents, add a place holder if necessary
|
||||
const placeholderColumn = decorateColumn({
|
||||
originalID: [column.id, 'placeholder', maxDepth - depth].join('_'),
|
||||
id: [column.id, 'placeholder', maxDepth - depth, parentColumns.length].join('_'),
|
||||
})
|
||||
if (isFirst || latestParentColumn.originalID !== placeholderColumn.originalID) {
|
||||
parentColumns.push(placeholderColumn)
|
||||
}
|
||||
}
|
||||
|
||||
// Establish the new columns[] relationship on the parent
|
||||
if (column.parent || hasParents) {
|
||||
latestParentColumn = [...parentColumns].reverse()[0]
|
||||
latestParentColumn.columns = latestParentColumn.columns || []
|
||||
if (!latestParentColumn.columns.includes(column)) {
|
||||
latestParentColumn.columns.push(column)
|
||||
}
|
||||
}
|
||||
|
||||
headerGroup.headers.push(column)
|
||||
})
|
||||
|
||||
headerGroups.push(headerGroup)
|
||||
|
||||
if (parentColumns.length) {
|
||||
buildGroup(parentColumns)
|
||||
}
|
||||
}
|
||||
|
||||
buildGroup(columns)
|
||||
|
||||
return headerGroups.reverse()
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
const mergeStateAndProps = (state, defaults, props) => {
|
||||
Object.keys(props).forEach(key => {
|
||||
if (typeof props[key] !== 'undefined') {
|
||||
state[key] = props[key]
|
||||
}
|
||||
})
|
||||
|
||||
Object.keys(defaults).forEach(key => {
|
||||
if (typeof state[key] === 'undefined') {
|
||||
state[key] = defaults[key]
|
||||
}
|
||||
})
|
||||
|
||||
return state
|
||||
}
|
||||
|
||||
export default function useControlledState ([userState, userSetState], defaults, props) {
|
||||
const state = mergeStateAndProps(userState, defaults, props)
|
||||
|
||||
const setState = (updater, type) =>
|
||||
userSetState(old => updater(mergeStateAndProps(old, defaults, props)), type)
|
||||
|
||||
return [state, setState]
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
import { useMemo, useEffect } from 'react'
|
||||
|
||||
import { getBy } from '../utils'
|
||||
|
||||
export default function useExpandedRows ({
|
||||
debug,
|
||||
expanded,
|
||||
expandedKey,
|
||||
columns,
|
||||
rows,
|
||||
setState,
|
||||
actions,
|
||||
}) {
|
||||
return useMemo(
|
||||
() => {
|
||||
if (debug) console.info('getExpandedRows')
|
||||
|
||||
const expandedRows = []
|
||||
|
||||
// Here we do some mutation, but it's the last stage in the
|
||||
// immutable process so this is safe
|
||||
const handleRow = (row, index, depth = 0, parentPath = []) => {
|
||||
// Compute some final state for the row
|
||||
const path = [...parentPath, index]
|
||||
|
||||
row.path = path
|
||||
row.depth = depth
|
||||
|
||||
row.isExpanded = (row.original && row.original[expandedKey]) || getBy(expanded, path)
|
||||
|
||||
row.cells = columns.map(column => {
|
||||
const cell = {
|
||||
column,
|
||||
row,
|
||||
state: null,
|
||||
value: row.values[column.id],
|
||||
}
|
||||
|
||||
return cell
|
||||
})
|
||||
|
||||
expandedRows.push(row)
|
||||
|
||||
if (row.isExpanded && row.subRows && row.subRows.length) {
|
||||
row.subRows.forEach((row, i) => handleRow(row, i, depth + 1, path))
|
||||
}
|
||||
}
|
||||
|
||||
rows.forEach((row, i) => handleRow(row, i))
|
||||
|
||||
return expandedRows
|
||||
},
|
||||
[rows, expanded, columns]
|
||||
)
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
import { useMemo } from 'react'
|
||||
|
||||
export default function useFilteredRows ({
|
||||
debug,
|
||||
filters,
|
||||
rows,
|
||||
columns,
|
||||
filterFn,
|
||||
manualFilters,
|
||||
}) {
|
||||
return useMemo(
|
||||
() => {
|
||||
if (manualFilters || !Object.keys(filters).length) {
|
||||
return rows
|
||||
}
|
||||
|
||||
if (debug) console.info('getFilteredRows')
|
||||
|
||||
// Filters top level and nested rows
|
||||
const filterRows = rows => {
|
||||
let filteredRows = rows
|
||||
|
||||
filteredRows = Object.entries(filters).reduce((filteredSoFar, [columnID, filterValue]) => {
|
||||
// Find the filters column
|
||||
const column = columns.find(d => d.id === columnID)
|
||||
|
||||
// Don't filter hidden columns or columns that have had their filters disabled
|
||||
if (!column || column.filterable === false) {
|
||||
return filteredSoFar
|
||||
}
|
||||
|
||||
const filterMethod = column.filterMethod || filterFn
|
||||
|
||||
// If 'filterAll' is set to true, pass the entire dataset to the filter method
|
||||
if (column.filterAll) {
|
||||
return filterMethod(filteredSoFar, columnID, filterValue, column)
|
||||
}
|
||||
return filteredSoFar.filter(row => filterMethod(row, columnID, filterValue, column))
|
||||
}, rows)
|
||||
|
||||
// Apply the filter to any subRows
|
||||
filteredRows = filteredRows.map(row => {
|
||||
if (!row.subRows) {
|
||||
return row
|
||||
}
|
||||
return {
|
||||
...row,
|
||||
subRows: filterRows(row.subRows),
|
||||
}
|
||||
})
|
||||
|
||||
// then filter any rows without subcolumns because it would be strange to show
|
||||
filteredRows = filteredRows.filter(row => {
|
||||
if (!row.subRows) {
|
||||
return true
|
||||
}
|
||||
return row.subRows.length > 0
|
||||
})
|
||||
|
||||
return filteredRows
|
||||
}
|
||||
|
||||
return filterRows(rows)
|
||||
},
|
||||
[rows, filters, manualFilters]
|
||||
)
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import * as aggregations from '../aggregations'
|
||||
|
||||
export default function useGroupedRows ({
|
||||
debug,
|
||||
groupBy,
|
||||
rows,
|
||||
columns,
|
||||
groupByFn,
|
||||
manualGroupBy,
|
||||
userAggregations,
|
||||
}) {
|
||||
return useMemo(
|
||||
() => {
|
||||
if (manualGroupBy || !groupBy.length) {
|
||||
return rows
|
||||
}
|
||||
if (debug) console.info('getGroupedRows')
|
||||
// Find the columns that can or are aggregating
|
||||
|
||||
// Uses each column to aggregate rows into a single value
|
||||
const aggregateRowsToValues = rows => {
|
||||
const values = {}
|
||||
columns.forEach(column => {
|
||||
const columnValues = rows.map(d => d.values[column.id])
|
||||
const aggregate =
|
||||
userAggregations[column.aggregate] || aggregations[column.aggregate] || column.aggregate
|
||||
if (typeof aggregate === 'function') {
|
||||
values[column.id] = aggregate(columnValues, rows)
|
||||
} else if (aggregate) {
|
||||
throw new Error(
|
||||
`Invalid aggregate "${aggregate}" passed to column with ID: "${column.id}"`
|
||||
)
|
||||
} else {
|
||||
values[column.id] = columnValues[0]
|
||||
}
|
||||
})
|
||||
return values
|
||||
}
|
||||
|
||||
// Recursively group the data
|
||||
const groupRecursively = (rows, groupBy, depth = 0) => {
|
||||
// This is the last level, just return the rows
|
||||
if (depth >= groupBy.length) {
|
||||
return rows
|
||||
}
|
||||
|
||||
// Group the rows together for this level
|
||||
const groupedRows = Object.entries(groupByFn(rows, groupBy[depth])).map(
|
||||
([groupByVal, subRows], index) => {
|
||||
// Recurse to sub rows before aggregation
|
||||
subRows = groupRecursively(subRows, groupBy, depth + 1)
|
||||
|
||||
const values = aggregateRowsToValues(subRows)
|
||||
|
||||
const row = {
|
||||
groupByID: groupBy[depth],
|
||||
groupByVal,
|
||||
values,
|
||||
subRows,
|
||||
depth,
|
||||
index,
|
||||
}
|
||||
return row
|
||||
}
|
||||
)
|
||||
|
||||
return groupedRows
|
||||
}
|
||||
|
||||
// Assign the new data
|
||||
return groupRecursively(rows, groupBy)
|
||||
},
|
||||
[rows, groupBy, columns, manualGroupBy]
|
||||
)
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
import { useMemo } from 'react'
|
||||
|
||||
export default function useSortedRows ({
|
||||
debug,
|
||||
sortBy,
|
||||
rows,
|
||||
columns,
|
||||
orderByFn,
|
||||
sortByFn,
|
||||
manualSorting,
|
||||
}) {
|
||||
return useMemo(
|
||||
() => {
|
||||
if (manualSorting || !sortBy.length) {
|
||||
return rows
|
||||
}
|
||||
if (debug) console.info('getSortedRows')
|
||||
|
||||
const sortMethodsByColumnID = {}
|
||||
|
||||
columns
|
||||
.filter(col => col.sortMethod)
|
||||
.forEach(col => {
|
||||
sortMethodsByColumnID[col.id] = col.sortMethod
|
||||
})
|
||||
|
||||
const sortData = rows => {
|
||||
// Use the orderByFn to compose multiple sortBy's together.
|
||||
// This will also perform a stable sorting using the row index
|
||||
// if needed.
|
||||
const sortedData = orderByFn(
|
||||
rows,
|
||||
sortBy.map(sort => {
|
||||
// Support custom sorting methods for each column
|
||||
const columnSortBy = sortMethodsByColumnID[sort.id]
|
||||
|
||||
// Return the correct sortFn
|
||||
return (a, b) =>
|
||||
(columnSortBy || sortByFn)(a.values[sort.id], b.values[sort.id], sort.desc)
|
||||
}),
|
||||
// Map the directions
|
||||
sortBy.map(d => !d.desc)
|
||||
)
|
||||
|
||||
// TODO: this should be optimized. Not good to loop again
|
||||
sortedData.forEach(row => {
|
||||
if (!row.subRows) {
|
||||
return
|
||||
}
|
||||
row.subRows = sortData(row.subRows)
|
||||
})
|
||||
|
||||
return sortedData
|
||||
}
|
||||
|
||||
return sortData(rows)
|
||||
},
|
||||
[rows, columns, sortBy, manualSorting]
|
||||
)
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
import { getBy, setBy, getFirstDefined } from '../utils'
|
||||
|
||||
export default function useTableMethods ({
|
||||
debug,
|
||||
setState,
|
||||
actions,
|
||||
groupBy,
|
||||
columns,
|
||||
defaultSortDesc,
|
||||
filters,
|
||||
}) {
|
||||
const toggleExpandedByPath = (path, set) =>
|
||||
setState(old => {
|
||||
const { expanded } = old
|
||||
const existing = getBy(expanded, path)
|
||||
set = getFirstDefined(set, !existing)
|
||||
return {
|
||||
...old,
|
||||
expanded: setBy(expanded, path, set),
|
||||
}
|
||||
}, actions.toggleExpanded)
|
||||
|
||||
// Updates sorting based on a columnID, desc flag and multi flag
|
||||
const toggleSortByID = (columnID, desc, multi) =>
|
||||
setState(old => {
|
||||
const { sortBy } = old
|
||||
|
||||
// Find the column for this columnID
|
||||
const column = columns.find(d => d.id === columnID)
|
||||
const resolvedDefaultSortDesc = getFirstDefined(column.defaultSortDesc, defaultSortDesc)
|
||||
|
||||
// Find any existing sortBy for this column
|
||||
const existingSortBy = sortBy.find(d => d.id === columnID)
|
||||
const hasDescDefined = typeof desc !== 'undefined' && desc !== null
|
||||
|
||||
let newSortBy = []
|
||||
|
||||
// What should we do with this filter?
|
||||
let action
|
||||
|
||||
if (!multi) {
|
||||
if (sortBy.length <= 1 && existingSortBy) {
|
||||
if (existingSortBy.desc) {
|
||||
action = 'remove'
|
||||
} else {
|
||||
action = 'toggle'
|
||||
}
|
||||
} else {
|
||||
action = 'replace'
|
||||
}
|
||||
} else if (!existingSortBy) {
|
||||
action = 'add'
|
||||
} else if (hasDescDefined) {
|
||||
action = 'set'
|
||||
} else {
|
||||
action = 'toggle'
|
||||
}
|
||||
|
||||
if (action === 'replace') {
|
||||
newSortBy = [
|
||||
{
|
||||
id: columnID,
|
||||
desc: hasDescDefined ? desc : resolvedDefaultSortDesc,
|
||||
},
|
||||
]
|
||||
} else if (action === 'add') {
|
||||
newSortBy = [
|
||||
...sortBy,
|
||||
{
|
||||
id: columnID,
|
||||
desc: hasDescDefined ? desc : resolvedDefaultSortDesc,
|
||||
},
|
||||
]
|
||||
} else if (action === 'set') {
|
||||
newSortBy = sortBy.map(d => {
|
||||
if (d.id === columnID) {
|
||||
return {
|
||||
...d,
|
||||
desc,
|
||||
}
|
||||
}
|
||||
return d
|
||||
})
|
||||
} else if (action === 'toggle') {
|
||||
newSortBy = sortBy.map(d => {
|
||||
if (d.id === columnID) {
|
||||
return {
|
||||
...d,
|
||||
desc: !existingSortBy.desc,
|
||||
}
|
||||
}
|
||||
return d
|
||||
})
|
||||
} else if (action === 'remove') {
|
||||
newSortBy = []
|
||||
}
|
||||
|
||||
return {
|
||||
...old,
|
||||
sortBy: newSortBy,
|
||||
}
|
||||
}, actions.sortByChange)
|
||||
|
||||
const toggleGroupBy = (id, toggle) =>
|
||||
setState(old => {
|
||||
const resolvedToggle = typeof set !== 'undefined' ? toggle : !groupBy.includes(id)
|
||||
if (resolvedToggle) {
|
||||
return {
|
||||
...old,
|
||||
groupBy: [...groupBy, id],
|
||||
}
|
||||
}
|
||||
return {
|
||||
...old,
|
||||
groupBy: groupBy.filter(d => d !== id),
|
||||
}
|
||||
}, actions.toggleGroupBy)
|
||||
|
||||
const setFilter = (id, val) =>
|
||||
setState(old => {
|
||||
if (typeof val === 'undefined') {
|
||||
const { [id]: prev, ...rest } = filters
|
||||
return {
|
||||
...old,
|
||||
filters: {
|
||||
...rest,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
...old,
|
||||
filters: {
|
||||
...filters,
|
||||
[id]: val,
|
||||
},
|
||||
}
|
||||
}, actions.setFilter)
|
||||
|
||||
const setAllFilters = filters =>
|
||||
setState(
|
||||
old => ({
|
||||
...old,
|
||||
filters,
|
||||
}),
|
||||
actions.setAllFilters
|
||||
)
|
||||
|
||||
return {
|
||||
toggleExpandedByPath,
|
||||
toggleSortByID,
|
||||
toggleGroupBy,
|
||||
setFilter,
|
||||
setAllFilters,
|
||||
}
|
||||
}
|
||||
Executable → Regular
+862
-9
@@ -1,11 +1,864 @@
|
||||
import useReactTable, { actions as mainActions } from './useReactTable'
|
||||
import usePagination, { actions as paginationActions } from './usePagination'
|
||||
import useFlexLayout, { actions as flexLayoutActions } from './useFlexLayout'
|
||||
import React, { Component } from 'react'
|
||||
import classnames from 'classnames'
|
||||
//
|
||||
import _ from './utils'
|
||||
import Lifecycle from './lifecycle'
|
||||
import Methods from './methods'
|
||||
import defaultProps from './defaultProps'
|
||||
import propTypes from './propTypes'
|
||||
|
||||
const actions = {
|
||||
...mainActions,
|
||||
...paginationActions,
|
||||
...flexLayoutActions,
|
||||
export const ReactTableDefaults = defaultProps
|
||||
|
||||
export default class ReactTable extends Methods(Lifecycle(Component)) {
|
||||
static propTypes = propTypes
|
||||
static defaultProps = defaultProps
|
||||
|
||||
constructor (props) {
|
||||
super()
|
||||
|
||||
this.getResolvedState = this.getResolvedState.bind(this)
|
||||
this.getDataModel = this.getDataModel.bind(this)
|
||||
this.getSortedData = this.getSortedData.bind(this)
|
||||
this.fireFetchData = this.fireFetchData.bind(this)
|
||||
this.getPropOrState = this.getPropOrState.bind(this)
|
||||
this.getStateOrProp = this.getStateOrProp.bind(this)
|
||||
this.filterData = this.filterData.bind(this)
|
||||
this.sortData = this.sortData.bind(this)
|
||||
this.getMinRows = this.getMinRows.bind(this)
|
||||
this.onPageChange = this.onPageChange.bind(this)
|
||||
this.onPageSizeChange = this.onPageSizeChange.bind(this)
|
||||
this.sortColumn = this.sortColumn.bind(this)
|
||||
this.filterColumn = this.filterColumn.bind(this)
|
||||
this.resizeColumnStart = this.resizeColumnStart.bind(this)
|
||||
this.resizeColumnEnd = this.resizeColumnEnd.bind(this)
|
||||
this.resizeColumnMoving = this.resizeColumnMoving.bind(this)
|
||||
|
||||
this.state = {
|
||||
page: 0,
|
||||
pageSize: props.defaultPageSize,
|
||||
sorted: props.defaultSorted,
|
||||
expanded: props.defaultExpanded,
|
||||
filtered: props.defaultFiltered,
|
||||
resized: props.defaultResized,
|
||||
currentlyResizing: false,
|
||||
skipNextSort: false,
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
const resolvedState = this.getResolvedState()
|
||||
const {
|
||||
children,
|
||||
className,
|
||||
style,
|
||||
getProps,
|
||||
getTableProps,
|
||||
getTheadGroupProps,
|
||||
getTheadGroupTrProps,
|
||||
getTheadGroupThProps,
|
||||
getTheadProps,
|
||||
getTheadTrProps,
|
||||
getTheadThProps,
|
||||
getTheadFilterProps,
|
||||
getTheadFilterTrProps,
|
||||
getTheadFilterThProps,
|
||||
getTbodyProps,
|
||||
getTrGroupProps,
|
||||
getTrProps,
|
||||
getTdProps,
|
||||
getTfootProps,
|
||||
getTfootTrProps,
|
||||
getTfootTdProps,
|
||||
getPaginationProps,
|
||||
getLoadingProps,
|
||||
getNoDataProps,
|
||||
getResizerProps,
|
||||
showPagination,
|
||||
showPaginationTop,
|
||||
showPaginationBottom,
|
||||
manual,
|
||||
loadingText,
|
||||
noDataText,
|
||||
sortable,
|
||||
multiSort,
|
||||
resizable,
|
||||
filterable,
|
||||
// Pivoting State
|
||||
pivotIDKey,
|
||||
pivotValKey,
|
||||
pivotBy,
|
||||
subRowsKey,
|
||||
aggregatedKey,
|
||||
originalKey,
|
||||
indexKey,
|
||||
groupedByPivotKey,
|
||||
// State
|
||||
loading,
|
||||
pageSize,
|
||||
page,
|
||||
sorted,
|
||||
filtered,
|
||||
resized,
|
||||
expanded,
|
||||
pages,
|
||||
onExpandedChange,
|
||||
// Components
|
||||
TableComponent,
|
||||
TheadComponent,
|
||||
TbodyComponent,
|
||||
TrGroupComponent,
|
||||
TrComponent,
|
||||
ThComponent,
|
||||
TdComponent,
|
||||
TfootComponent,
|
||||
PaginationComponent,
|
||||
LoadingComponent,
|
||||
SubComponent,
|
||||
NoDataComponent,
|
||||
ResizerComponent,
|
||||
ExpanderComponent,
|
||||
PivotValueComponent,
|
||||
PivotComponent,
|
||||
AggregatedComponent,
|
||||
FilterComponent,
|
||||
PadRowComponent,
|
||||
// Data model
|
||||
resolvedData,
|
||||
allVisibleColumns,
|
||||
headerGroups,
|
||||
hasHeaderGroups,
|
||||
// Sorted Data
|
||||
sortedData,
|
||||
currentlyResizing,
|
||||
} = resolvedState
|
||||
|
||||
// Pagination
|
||||
const startRow = pageSize * page
|
||||
const endRow = startRow + pageSize
|
||||
let pageRows = manual ? resolvedData : sortedData.slice(startRow, endRow)
|
||||
const minRows = this.getMinRows()
|
||||
const padRows = _.range(Math.max(minRows - pageRows.length, 0))
|
||||
|
||||
const hasColumnFooter = allVisibleColumns.some(d => d.Footer)
|
||||
const hasFilters = filterable || allVisibleColumns.some(d => d.filterable)
|
||||
|
||||
const recurseRowsViewIndex = (rows, path = [], index = -1) => [
|
||||
rows.map((row, i) => {
|
||||
index += 1
|
||||
const rowWithViewIndex = {
|
||||
...row,
|
||||
_viewIndex: index,
|
||||
}
|
||||
const newPath = path.concat([i])
|
||||
if (rowWithViewIndex[subRowsKey] && _.get(expanded, newPath)) {
|
||||
[rowWithViewIndex[subRowsKey], index] = recurseRowsViewIndex(
|
||||
rowWithViewIndex[subRowsKey],
|
||||
newPath,
|
||||
index
|
||||
)
|
||||
}
|
||||
return rowWithViewIndex
|
||||
}),
|
||||
index,
|
||||
];
|
||||
[pageRows] = recurseRowsViewIndex(pageRows)
|
||||
|
||||
const canPrevious = page > 0
|
||||
const canNext = page + 1 < pages
|
||||
|
||||
const rowMinWidth = _.sum(
|
||||
allVisibleColumns.map(d => {
|
||||
const resizedColumn = resized.find(x => x.id === d.id) || {}
|
||||
return _.getFirstDefined(resizedColumn.value, d.width, d.minWidth)
|
||||
})
|
||||
)
|
||||
|
||||
let rowIndex = -1
|
||||
|
||||
const finalState = {
|
||||
...resolvedState,
|
||||
startRow,
|
||||
endRow,
|
||||
pageRows,
|
||||
minRows,
|
||||
padRows,
|
||||
hasColumnFooter,
|
||||
canPrevious,
|
||||
canNext,
|
||||
rowMinWidth,
|
||||
}
|
||||
|
||||
const rootProps = _.splitProps(getProps(finalState, undefined, undefined, this))
|
||||
const tableProps = _.splitProps(getTableProps(finalState, undefined, undefined, this))
|
||||
const tBodyProps = _.splitProps(getTbodyProps(finalState, undefined, undefined, this))
|
||||
const loadingProps = getLoadingProps(finalState, undefined, undefined, this)
|
||||
const noDataProps = getNoDataProps(finalState, undefined, undefined, this)
|
||||
|
||||
// Visual Components
|
||||
|
||||
const makeHeaderGroup = (column, i) => {
|
||||
const resizedValue = col => (resized.find(x => x.id === col.id) || {}).value
|
||||
const flex = _.sum(
|
||||
column.columns.map(col => (col.width || resizedValue(col) ? 0 : col.minWidth))
|
||||
)
|
||||
const width = _.sum(
|
||||
column.columns.map(col => _.getFirstDefined(resizedValue(col), col.width, col.minWidth))
|
||||
)
|
||||
const maxWidth = _.sum(
|
||||
column.columns.map(col => _.getFirstDefined(resizedValue(col), col.width, col.maxWidth))
|
||||
)
|
||||
|
||||
const theadGroupThProps = _.splitProps(
|
||||
getTheadGroupThProps(finalState, undefined, column, this)
|
||||
)
|
||||
const columnHeaderProps = _.splitProps(
|
||||
column.getHeaderProps(finalState, undefined, column, this)
|
||||
)
|
||||
|
||||
const classes = [
|
||||
column.headerClassName,
|
||||
theadGroupThProps.className,
|
||||
columnHeaderProps.className,
|
||||
]
|
||||
|
||||
const styles = {
|
||||
...column.headerStyle,
|
||||
...theadGroupThProps.style,
|
||||
...columnHeaderProps.style,
|
||||
}
|
||||
|
||||
const rest = {
|
||||
...theadGroupThProps.rest,
|
||||
...columnHeaderProps.rest,
|
||||
}
|
||||
|
||||
const flexStyles = {
|
||||
flex: `${flex} 0 auto`,
|
||||
width: _.asPx(width),
|
||||
maxWidth: _.asPx(maxWidth),
|
||||
}
|
||||
|
||||
return (
|
||||
<ThComponent
|
||||
key={`${i}-${column.id}`}
|
||||
className={classnames(classes)}
|
||||
style={{
|
||||
...styles,
|
||||
...flexStyles,
|
||||
}}
|
||||
{...rest}
|
||||
>
|
||||
{_.normalizeComponent(column.Header, {
|
||||
data: sortedData,
|
||||
column,
|
||||
})}
|
||||
</ThComponent>
|
||||
)
|
||||
}
|
||||
|
||||
const makeHeaderGroups = () => {
|
||||
const theadGroupProps = _.splitProps(
|
||||
getTheadGroupProps(finalState, undefined, undefined, this)
|
||||
)
|
||||
const theadGroupTrProps = _.splitProps(
|
||||
getTheadGroupTrProps(finalState, undefined, undefined, this)
|
||||
)
|
||||
return (
|
||||
<TheadComponent
|
||||
className={classnames('-headerGroups', theadGroupProps.className)}
|
||||
style={{
|
||||
...theadGroupProps.style,
|
||||
minWidth: `${rowMinWidth}px`,
|
||||
}}
|
||||
{...theadGroupProps.rest}
|
||||
>
|
||||
<TrComponent
|
||||
className={theadGroupTrProps.className}
|
||||
style={theadGroupTrProps.style}
|
||||
{...theadGroupTrProps.rest}
|
||||
>
|
||||
{headerGroups.map(makeHeaderGroup)}
|
||||
</TrComponent>
|
||||
</TheadComponent>
|
||||
)
|
||||
}
|
||||
|
||||
const makeHeader = (column, i) => {
|
||||
const resizedCol = resized.find(x => x.id === column.id) || {}
|
||||
const sort = sorted.find(d => d.id === column.id)
|
||||
const show = typeof column.show === 'function' ? column.show() : column.show
|
||||
const width = _.getFirstDefined(resizedCol.value, column.width, column.minWidth)
|
||||
const maxWidth = _.getFirstDefined(resizedCol.value, column.width, column.maxWidth)
|
||||
const theadThProps = _.splitProps(getTheadThProps(finalState, undefined, column, this))
|
||||
const columnHeaderProps = _.splitProps(
|
||||
column.getHeaderProps(finalState, undefined, column, this)
|
||||
)
|
||||
|
||||
const classes = [column.headerClassName, theadThProps.className, columnHeaderProps.className]
|
||||
|
||||
const styles = {
|
||||
...column.headerStyle,
|
||||
...theadThProps.style,
|
||||
...columnHeaderProps.style,
|
||||
}
|
||||
|
||||
const rest = {
|
||||
...theadThProps.rest,
|
||||
...columnHeaderProps.rest,
|
||||
}
|
||||
|
||||
const isResizable = _.getFirstDefined(column.resizable, resizable, false)
|
||||
const resizer = isResizable ? (
|
||||
<ResizerComponent
|
||||
onMouseDown={e => this.resizeColumnStart(e, column, false)}
|
||||
onTouchStart={e => this.resizeColumnStart(e, column, true)}
|
||||
{...getResizerProps('finalState', undefined, column, this)}
|
||||
/>
|
||||
) : null
|
||||
|
||||
const isSortable = _.getFirstDefined(column.sortable, sortable, false)
|
||||
|
||||
return (
|
||||
<ThComponent
|
||||
key={`${i}-${column.id}`}
|
||||
className={classnames(
|
||||
classes,
|
||||
isResizable && 'rt-resizable-header',
|
||||
sort ? (sort.desc ? '-sort-desc' : '-sort-asc') : '',
|
||||
isSortable && '-cursor-pointer',
|
||||
!show && '-hidden',
|
||||
pivotBy && pivotBy.slice(0, -1).includes(column.id) && 'rt-header-pivot'
|
||||
)}
|
||||
style={{
|
||||
...styles,
|
||||
flex: `${width} 0 auto`,
|
||||
width: _.asPx(width),
|
||||
maxWidth: _.asPx(maxWidth),
|
||||
}}
|
||||
toggleSort={e => {
|
||||
if (isSortable) this.sortColumn(column, multiSort ? e.shiftKey : false)
|
||||
}}
|
||||
{...rest}
|
||||
>
|
||||
<div className={classnames(isResizable && 'rt-resizable-header-content')}>
|
||||
{_.normalizeComponent(column.Header, {
|
||||
data: sortedData,
|
||||
column,
|
||||
})}
|
||||
</div>
|
||||
{resizer}
|
||||
</ThComponent>
|
||||
)
|
||||
}
|
||||
|
||||
const makeHeaders = () => {
|
||||
const theadProps = _.splitProps(getTheadProps(finalState, undefined, undefined, this))
|
||||
const theadTrProps = _.splitProps(getTheadTrProps(finalState, undefined, undefined, this))
|
||||
return (
|
||||
<TheadComponent
|
||||
className={classnames('-header', theadProps.className)}
|
||||
style={{
|
||||
...theadProps.style,
|
||||
minWidth: `${rowMinWidth}px`,
|
||||
}}
|
||||
{...theadProps.rest}
|
||||
>
|
||||
<TrComponent
|
||||
className={theadTrProps.className}
|
||||
style={theadTrProps.style}
|
||||
{...theadTrProps.rest}
|
||||
>
|
||||
{allVisibleColumns.map(makeHeader)}
|
||||
</TrComponent>
|
||||
</TheadComponent>
|
||||
)
|
||||
}
|
||||
|
||||
const makeFilter = (column, i) => {
|
||||
const resizedCol = resized.find(x => x.id === column.id) || {}
|
||||
const width = _.getFirstDefined(resizedCol.value, column.width, column.minWidth)
|
||||
const maxWidth = _.getFirstDefined(resizedCol.value, column.width, column.maxWidth)
|
||||
const theadFilterThProps = _.splitProps(
|
||||
getTheadFilterThProps(finalState, undefined, column, this)
|
||||
)
|
||||
const columnHeaderProps = _.splitProps(
|
||||
column.getHeaderProps(finalState, undefined, column, this)
|
||||
)
|
||||
|
||||
const classes = [
|
||||
column.headerClassName,
|
||||
theadFilterThProps.className,
|
||||
columnHeaderProps.className,
|
||||
]
|
||||
|
||||
const styles = {
|
||||
...column.headerStyle,
|
||||
...theadFilterThProps.style,
|
||||
...columnHeaderProps.style,
|
||||
}
|
||||
|
||||
const rest = {
|
||||
...theadFilterThProps.rest,
|
||||
...columnHeaderProps.rest,
|
||||
}
|
||||
|
||||
const filter = filtered.find(filter => filter.id === column.id)
|
||||
|
||||
const ResolvedFilterComponent = column.Filter || FilterComponent
|
||||
|
||||
const isFilterable = _.getFirstDefined(column.filterable, filterable, false)
|
||||
|
||||
return (
|
||||
<ThComponent
|
||||
key={`${i}-${column.id}`}
|
||||
className={classnames(classes)}
|
||||
style={{
|
||||
...styles,
|
||||
flex: `${width} 0 auto`,
|
||||
width: _.asPx(width),
|
||||
maxWidth: _.asPx(maxWidth),
|
||||
}}
|
||||
{...rest}
|
||||
>
|
||||
{isFilterable
|
||||
? _.normalizeComponent(
|
||||
ResolvedFilterComponent,
|
||||
{
|
||||
column,
|
||||
filter,
|
||||
onChange: value => this.filterColumn(column, value),
|
||||
},
|
||||
defaultProps.column.Filter
|
||||
)
|
||||
: null}
|
||||
</ThComponent>
|
||||
)
|
||||
}
|
||||
|
||||
const makeFilters = () => {
|
||||
const theadFilterProps = _.splitProps(
|
||||
getTheadFilterProps(finalState, undefined, undefined, this)
|
||||
)
|
||||
const theadFilterTrProps = _.splitProps(
|
||||
getTheadFilterTrProps(finalState, undefined, undefined, this)
|
||||
)
|
||||
return (
|
||||
<TheadComponent
|
||||
className={classnames('-filters', theadFilterProps.className)}
|
||||
style={{
|
||||
...theadFilterProps.style,
|
||||
minWidth: `${rowMinWidth}px`,
|
||||
}}
|
||||
{...theadFilterProps.rest}
|
||||
>
|
||||
<TrComponent
|
||||
className={theadFilterTrProps.className}
|
||||
style={theadFilterTrProps.style}
|
||||
{...theadFilterTrProps.rest}
|
||||
>
|
||||
{allVisibleColumns.map(makeFilter)}
|
||||
</TrComponent>
|
||||
</TheadComponent>
|
||||
)
|
||||
}
|
||||
|
||||
const makePageRow = (row, i, path = []) => {
|
||||
const rowInfo = {
|
||||
original: row[originalKey],
|
||||
row,
|
||||
index: row[indexKey],
|
||||
viewIndex: (rowIndex += 1),
|
||||
pageSize,
|
||||
page,
|
||||
level: path.length,
|
||||
nestingPath: path.concat([i]),
|
||||
aggregated: row[aggregatedKey],
|
||||
groupedByPivot: row[groupedByPivotKey],
|
||||
subRows: row[subRowsKey],
|
||||
}
|
||||
const isExpanded = _.get(expanded, rowInfo.nestingPath)
|
||||
const trGroupProps = getTrGroupProps(finalState, rowInfo, undefined, this)
|
||||
const trProps = _.splitProps(getTrProps(finalState, rowInfo, undefined, this))
|
||||
return (
|
||||
<TrGroupComponent key={rowInfo.nestingPath.join('_')} {...trGroupProps}>
|
||||
<TrComponent
|
||||
className={classnames(trProps.className, row._viewIndex % 2 ? '-even' : '-odd')}
|
||||
style={trProps.style}
|
||||
{...trProps.rest}
|
||||
>
|
||||
{allVisibleColumns.map((column, i2) => {
|
||||
const resizedCol = resized.find(x => x.id === column.id) || {}
|
||||
const show = typeof column.show === 'function' ? column.show() : column.show
|
||||
const width = _.getFirstDefined(resizedCol.value, column.width, column.minWidth)
|
||||
const maxWidth = _.getFirstDefined(resizedCol.value, column.width, column.maxWidth)
|
||||
const tdProps = _.splitProps(getTdProps(finalState, rowInfo, column, this))
|
||||
const columnProps = _.splitProps(column.getProps(finalState, rowInfo, column, this))
|
||||
|
||||
const classes = [tdProps.className, column.className, columnProps.className]
|
||||
|
||||
const styles = {
|
||||
...tdProps.style,
|
||||
...column.style,
|
||||
...columnProps.style,
|
||||
}
|
||||
|
||||
const cellInfo = {
|
||||
...rowInfo,
|
||||
isExpanded,
|
||||
column: { ...column },
|
||||
value: rowInfo.row[column.id],
|
||||
pivoted: column.pivoted,
|
||||
expander: column.expander,
|
||||
resized,
|
||||
show,
|
||||
width,
|
||||
maxWidth,
|
||||
tdProps,
|
||||
columnProps,
|
||||
classes,
|
||||
styles,
|
||||
}
|
||||
|
||||
const value = cellInfo.value
|
||||
|
||||
let useOnExpanderClick
|
||||
let isBranch
|
||||
let isPreview
|
||||
|
||||
const onExpanderClick = e => {
|
||||
let newExpanded = _.clone(expanded)
|
||||
if (isExpanded) {
|
||||
newExpanded = _.set(newExpanded, cellInfo.nestingPath, false)
|
||||
} else {
|
||||
newExpanded = _.set(newExpanded, cellInfo.nestingPath, {})
|
||||
}
|
||||
|
||||
return this.setStateWithData(
|
||||
{
|
||||
expanded: newExpanded,
|
||||
},
|
||||
() => onExpandedChange && onExpandedChange(newExpanded, cellInfo.nestingPath, e)
|
||||
)
|
||||
}
|
||||
|
||||
// Default to a standard cell
|
||||
let resolvedCell = _.normalizeComponent(column.Cell, cellInfo, value)
|
||||
|
||||
// Resolve Renderers
|
||||
const ResolvedAggregatedComponent =
|
||||
column.Aggregated || (!column.aggregate ? AggregatedComponent : column.Cell)
|
||||
const ResolvedExpanderComponent = column.Expander || ExpanderComponent
|
||||
const ResolvedPivotValueComponent = column.PivotValue || PivotValueComponent
|
||||
const DefaultResolvedPivotComponent =
|
||||
PivotComponent ||
|
||||
(props => (
|
||||
<div>
|
||||
<ResolvedExpanderComponent {...props} />
|
||||
<ResolvedPivotValueComponent {...props} />
|
||||
</div>
|
||||
))
|
||||
const ResolvedPivotComponent = column.Pivot || DefaultResolvedPivotComponent
|
||||
|
||||
// Is this cell expandable?
|
||||
if (cellInfo.pivoted || cellInfo.expander) {
|
||||
// Make it expandable by defualt
|
||||
cellInfo.expandable = true
|
||||
useOnExpanderClick = true
|
||||
// If pivoted, has no subRows, and does not have a subComponent,
|
||||
// do not make expandable
|
||||
if (cellInfo.pivoted && !cellInfo.subRows && !SubComponent) {
|
||||
cellInfo.expandable = false
|
||||
}
|
||||
}
|
||||
|
||||
if (cellInfo.pivoted) {
|
||||
// Is this column a branch?
|
||||
isBranch = rowInfo.row[pivotIDKey] === column.id && cellInfo.subRows
|
||||
// Should this column be blank?
|
||||
isPreview =
|
||||
pivotBy.indexOf(column.id) > pivotBy.indexOf(rowInfo.row[pivotIDKey]) &&
|
||||
cellInfo.subRows
|
||||
// Pivot Cell Render Override
|
||||
if (isBranch) {
|
||||
// isPivot
|
||||
resolvedCell = _.normalizeComponent(
|
||||
ResolvedPivotComponent,
|
||||
{
|
||||
...cellInfo,
|
||||
value: row[pivotValKey],
|
||||
},
|
||||
row[pivotValKey]
|
||||
)
|
||||
} else if (isPreview) {
|
||||
// Show the pivot preview
|
||||
resolvedCell = _.normalizeComponent(ResolvedAggregatedComponent, cellInfo, value)
|
||||
} else {
|
||||
resolvedCell = null
|
||||
}
|
||||
} else if (cellInfo.aggregated) {
|
||||
resolvedCell = _.normalizeComponent(ResolvedAggregatedComponent, cellInfo, value)
|
||||
}
|
||||
|
||||
if (cellInfo.expander) {
|
||||
resolvedCell = _.normalizeComponent(
|
||||
ResolvedExpanderComponent,
|
||||
cellInfo,
|
||||
row[pivotValKey]
|
||||
)
|
||||
if (pivotBy) {
|
||||
if (cellInfo.groupedByPivot) {
|
||||
resolvedCell = null
|
||||
}
|
||||
if (!cellInfo.subRows && !SubComponent) {
|
||||
resolvedCell = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const resolvedOnExpanderClick = useOnExpanderClick ? onExpanderClick : () => {}
|
||||
|
||||
// If there are multiple onClick events, make sure they don't
|
||||
// override eachother. This should maybe be expanded to handle all
|
||||
// function attributes
|
||||
const interactionProps = {
|
||||
onClick: resolvedOnExpanderClick,
|
||||
}
|
||||
|
||||
if (tdProps.rest.onClick) {
|
||||
interactionProps.onClick = e => {
|
||||
tdProps.rest.onClick(e, () => resolvedOnExpanderClick(e))
|
||||
}
|
||||
}
|
||||
|
||||
if (columnProps.rest.onClick) {
|
||||
interactionProps.onClick = e => {
|
||||
columnProps.rest.onClick(e, () => resolvedOnExpanderClick(e))
|
||||
}
|
||||
}
|
||||
|
||||
// Return the cell
|
||||
return (
|
||||
<TdComponent
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
key={`${i2}-${column.id}`}
|
||||
className={classnames(
|
||||
classes,
|
||||
!show && 'hidden',
|
||||
cellInfo.expandable && 'rt-expandable',
|
||||
(isBranch || isPreview) && 'rt-pivot'
|
||||
)}
|
||||
style={{
|
||||
...styles,
|
||||
flex: `${width} 0 auto`,
|
||||
width: _.asPx(width),
|
||||
maxWidth: _.asPx(maxWidth),
|
||||
}}
|
||||
{...tdProps.rest}
|
||||
{...columnProps.rest}
|
||||
{...interactionProps}
|
||||
>
|
||||
{resolvedCell}
|
||||
</TdComponent>
|
||||
)
|
||||
})}
|
||||
</TrComponent>
|
||||
{rowInfo.subRows &&
|
||||
isExpanded &&
|
||||
rowInfo.subRows.map((d, i) => makePageRow(d, i, rowInfo.nestingPath))}
|
||||
{SubComponent && !rowInfo.subRows && isExpanded && SubComponent(rowInfo)}
|
||||
</TrGroupComponent>
|
||||
)
|
||||
}
|
||||
|
||||
const makePadColumn = (column, i) => {
|
||||
const resizedCol = resized.find(x => x.id === column.id) || {}
|
||||
const show = typeof column.show === 'function' ? column.show() : column.show
|
||||
const width = _.getFirstDefined(resizedCol.value, column.width, column.minWidth)
|
||||
const flex = width
|
||||
const maxWidth = _.getFirstDefined(resizedCol.value, column.width, column.maxWidth)
|
||||
const tdProps = _.splitProps(getTdProps(finalState, undefined, column, this))
|
||||
const columnProps = _.splitProps(column.getProps(finalState, undefined, column, this))
|
||||
|
||||
const classes = [tdProps.className, column.className, columnProps.className]
|
||||
|
||||
const styles = {
|
||||
...tdProps.style,
|
||||
...column.style,
|
||||
...columnProps.style,
|
||||
}
|
||||
|
||||
return (
|
||||
<TdComponent
|
||||
key={`${i}-${column.id}`}
|
||||
className={classnames(classes, !show && 'hidden')}
|
||||
style={{
|
||||
...styles,
|
||||
flex: `${flex} 0 auto`,
|
||||
width: _.asPx(width),
|
||||
maxWidth: _.asPx(maxWidth),
|
||||
}}
|
||||
{...tdProps.rest}
|
||||
>
|
||||
{_.normalizeComponent(PadRowComponent)}
|
||||
</TdComponent>
|
||||
)
|
||||
}
|
||||
|
||||
const makePadRow = (row, i) => {
|
||||
const trGroupProps = getTrGroupProps(finalState, undefined, undefined, this)
|
||||
const trProps = _.splitProps(getTrProps(finalState, undefined, undefined, this))
|
||||
return (
|
||||
<TrGroupComponent key={i} {...trGroupProps}>
|
||||
<TrComponent
|
||||
className={classnames(
|
||||
'-padRow',
|
||||
(pageRows.length + i) % 2 ? '-even' : '-odd',
|
||||
trProps.className
|
||||
)}
|
||||
style={trProps.style || {}}
|
||||
>
|
||||
{allVisibleColumns.map(makePadColumn)}
|
||||
</TrComponent>
|
||||
</TrGroupComponent>
|
||||
)
|
||||
}
|
||||
|
||||
const makeColumnFooter = (column, i) => {
|
||||
const resizedCol = resized.find(x => x.id === column.id) || {}
|
||||
const show = typeof column.show === 'function' ? column.show() : column.show
|
||||
const width = _.getFirstDefined(resizedCol.value, column.width, column.minWidth)
|
||||
const maxWidth = _.getFirstDefined(resizedCol.value, column.width, column.maxWidth)
|
||||
const tFootTdProps = _.splitProps(getTfootTdProps(finalState, undefined, undefined, this))
|
||||
const columnProps = _.splitProps(column.getProps(finalState, undefined, column, this))
|
||||
const columnFooterProps = _.splitProps(
|
||||
column.getFooterProps(finalState, undefined, column, this)
|
||||
)
|
||||
|
||||
const classes = [
|
||||
tFootTdProps.className,
|
||||
column.className,
|
||||
columnProps.className,
|
||||
columnFooterProps.className,
|
||||
]
|
||||
|
||||
const styles = {
|
||||
...tFootTdProps.style,
|
||||
...column.style,
|
||||
...columnProps.style,
|
||||
...columnFooterProps.style,
|
||||
}
|
||||
|
||||
return (
|
||||
<TdComponent
|
||||
key={`${i}-${column.id}`}
|
||||
className={classnames(classes, !show && 'hidden')}
|
||||
style={{
|
||||
...styles,
|
||||
flex: `${width} 0 auto`,
|
||||
width: _.asPx(width),
|
||||
maxWidth: _.asPx(maxWidth),
|
||||
}}
|
||||
{...columnProps.rest}
|
||||
{...tFootTdProps.rest}
|
||||
{...columnFooterProps.rest}
|
||||
>
|
||||
{_.normalizeComponent(column.Footer, {
|
||||
data: sortedData,
|
||||
column,
|
||||
})}
|
||||
</TdComponent>
|
||||
)
|
||||
}
|
||||
|
||||
const makeColumnFooters = () => {
|
||||
const tFootProps = getTfootProps(finalState, undefined, undefined, this)
|
||||
const tFootTrProps = _.splitProps(getTfootTrProps(finalState, undefined, undefined, this))
|
||||
return (
|
||||
<TfootComponent
|
||||
className={tFootProps.className}
|
||||
style={{
|
||||
...tFootProps.style,
|
||||
minWidth: `${rowMinWidth}px`,
|
||||
}}
|
||||
{...tFootProps.rest}
|
||||
>
|
||||
<TrComponent
|
||||
className={classnames(tFootTrProps.className)}
|
||||
style={tFootTrProps.style}
|
||||
{...tFootTrProps.rest}
|
||||
>
|
||||
{allVisibleColumns.map(makeColumnFooter)}
|
||||
</TrComponent>
|
||||
</TfootComponent>
|
||||
)
|
||||
}
|
||||
|
||||
const makePagination = () => {
|
||||
const paginationProps = _.splitProps(
|
||||
getPaginationProps(finalState, undefined, undefined, this)
|
||||
)
|
||||
return (
|
||||
<PaginationComponent
|
||||
{...resolvedState}
|
||||
pages={pages}
|
||||
canPrevious={canPrevious}
|
||||
canNext={canNext}
|
||||
onPageChange={this.onPageChange}
|
||||
onPageSizeChange={this.onPageSizeChange}
|
||||
className={paginationProps.className}
|
||||
style={paginationProps.style}
|
||||
{...paginationProps.rest}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const makeTable = () => {
|
||||
const pagination = makePagination()
|
||||
return (
|
||||
<div
|
||||
className={classnames('ReactTable', className, rootProps.className)}
|
||||
style={{
|
||||
...style,
|
||||
...rootProps.style,
|
||||
}}
|
||||
{...rootProps.rest}
|
||||
>
|
||||
{showPagination && showPaginationTop ? (
|
||||
<div className="pagination-top">{pagination}</div>
|
||||
) : null}
|
||||
<TableComponent
|
||||
className={classnames(tableProps.className, currentlyResizing ? 'rt-resizing' : '')}
|
||||
style={tableProps.style}
|
||||
{...tableProps.rest}
|
||||
>
|
||||
{hasHeaderGroups ? makeHeaderGroups() : null}
|
||||
{makeHeaders()}
|
||||
{hasFilters ? makeFilters() : null}
|
||||
<TbodyComponent
|
||||
className={classnames(tBodyProps.className)}
|
||||
style={{
|
||||
...tBodyProps.style,
|
||||
minWidth: `${rowMinWidth}px`,
|
||||
}}
|
||||
{...tBodyProps.rest}
|
||||
>
|
||||
{pageRows.map((d, i) => makePageRow(d, i))}
|
||||
{padRows.map(makePadRow)}
|
||||
</TbodyComponent>
|
||||
{hasColumnFooter ? makeColumnFooters() : null}
|
||||
</TableComponent>
|
||||
{showPagination && showPaginationBottom ? (
|
||||
<div className="pagination-bottom">{pagination}</div>
|
||||
) : null}
|
||||
{!pageRows.length && (
|
||||
<NoDataComponent {...noDataProps}>{_.normalizeComponent(noDataText)}</NoDataComponent>
|
||||
)}
|
||||
<LoadingComponent loading={loading} loadingText={loadingText} {...loadingProps} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// childProps are optionally passed to a function-as-a-child
|
||||
return children ? children(finalState, makeTable, this) : makeTable()
|
||||
}
|
||||
}
|
||||
|
||||
export { useReactTable, usePagination, useFlexLayout, actions }
|
||||
|
||||
+319
@@ -0,0 +1,319 @@
|
||||
$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
|
||||
flex-direction: column
|
||||
border: 1px solid alpha(black, .1)
|
||||
*
|
||||
box-sizing: border-box
|
||||
.rt-table
|
||||
flex: auto 1
|
||||
display: flex
|
||||
flex-direction: column
|
||||
align-items: stretch
|
||||
width: 100%
|
||||
border-collapse: collapse
|
||||
overflow: auto
|
||||
|
||||
.rt-thead
|
||||
flex: 1 0 auto
|
||||
display: flex
|
||||
flex-direction: column
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
|
||||
&.-headerGroups
|
||||
background: alpha(black, .03)
|
||||
border-bottom: 1px solid alpha(black, .05)
|
||||
|
||||
&.-filters
|
||||
border-bottom: 1px solid alpha(black, 0.05)
|
||||
|
||||
input
|
||||
select
|
||||
input-select-style();
|
||||
|
||||
.rt-th
|
||||
border-right: 1px solid alpha(black, 0.02)
|
||||
|
||||
&.-header
|
||||
box-shadow: 0 2px 15px 0px alpha(black, .15)
|
||||
|
||||
.rt-tr
|
||||
text-align:center
|
||||
|
||||
.rt-th
|
||||
.rt-td
|
||||
padding: 5px 5px
|
||||
line-height: normal
|
||||
position: relative
|
||||
border-right: 1px solid alpha(black, .05)
|
||||
transition box-shadow .3s $easeOutBack
|
||||
box-shadow:inset 0 0 0 0 transparent
|
||||
&.-sort-asc
|
||||
box-shadow:inset 0 3px 0 0 alpha(black, .6)
|
||||
&.-sort-desc
|
||||
box-shadow:inset 0 -3px 0 0 alpha(black, .6)
|
||||
&.-cursor-pointer
|
||||
cursor: pointer
|
||||
&:last-child
|
||||
border-right: 0
|
||||
|
||||
.rt-resizable-header
|
||||
overflow: visible
|
||||
&:last-child
|
||||
overflow: hidden
|
||||
|
||||
.rt-resizable-header-content
|
||||
overflow: hidden
|
||||
text-overflow: ellipsis
|
||||
|
||||
.rt-header-pivot
|
||||
border-right-color: #f7f7f7
|
||||
|
||||
.rt-header-pivot:after, .rt-header-pivot:before
|
||||
left: 100%
|
||||
top: 50%
|
||||
border: solid transparent
|
||||
content: " "
|
||||
height: 0
|
||||
width: 0
|
||||
position: absolute
|
||||
pointer-events: none
|
||||
|
||||
.rt-header-pivot:after
|
||||
border-color: rgba(255, 255, 255, 0)
|
||||
border-left-color: #FFF
|
||||
border-width: 8px
|
||||
margin-top: -8px
|
||||
|
||||
.rt-header-pivot:before
|
||||
border-color: rgba(102, 102, 102, 0)
|
||||
border-left-color: #f7f7f7
|
||||
border-width: 10px
|
||||
margin-top: -10px
|
||||
|
||||
.rt-tbody
|
||||
flex: 99999 1 auto
|
||||
display: flex
|
||||
flex-direction: column
|
||||
overflow: auto
|
||||
// z-index:0
|
||||
.rt-tr-group
|
||||
border-bottom: solid 1px alpha(black, .05)
|
||||
&:last-child
|
||||
border-bottom: 0
|
||||
.rt-td
|
||||
border-right:1px solid alpha(black, .02)
|
||||
&:last-child
|
||||
border-right:0
|
||||
.rt-expandable
|
||||
cursor: pointer
|
||||
text-overflow: clip
|
||||
.rt-tr-group
|
||||
flex: 1 0 auto
|
||||
display: flex
|
||||
flex-direction: column
|
||||
align-items: stretch
|
||||
.rt-tr
|
||||
flex: 1 0 auto
|
||||
display: inline-flex
|
||||
.rt-th
|
||||
.rt-td
|
||||
flex: 1 0 0px
|
||||
white-space: nowrap
|
||||
text-overflow: ellipsis
|
||||
padding: 7px 5px
|
||||
overflow: hidden
|
||||
transition: .3s ease
|
||||
transition-property: width, min-width, padding, opacity
|
||||
|
||||
&.-hidden
|
||||
width: 0 !important
|
||||
min-width: 0 !important
|
||||
padding: 0 !important
|
||||
border:0 !important
|
||||
opacity: 0 !important
|
||||
|
||||
.rt-expander
|
||||
display: inline-block
|
||||
position:relative
|
||||
margin: 0
|
||||
color: transparent
|
||||
margin: 0 10px
|
||||
&:after
|
||||
content: ''
|
||||
position: absolute
|
||||
width: 0
|
||||
height: 0
|
||||
top:50%
|
||||
left:50%
|
||||
transform: translate(-50%, -50%) rotate(-90deg)
|
||||
border-left: ($expandSize * .72) solid transparent
|
||||
border-right: ($expandSize * .72) solid transparent
|
||||
border-top: $expandSize solid alpha(black, .8)
|
||||
transition: all .3s $easeOutBack
|
||||
cursor: pointer
|
||||
&.-open:after
|
||||
transform: translate(-50%, -50%) rotate(0deg)
|
||||
|
||||
.rt-resizer
|
||||
display: inline-block
|
||||
position: absolute
|
||||
width: 36px
|
||||
top: 0
|
||||
bottom: 0
|
||||
right: -18px
|
||||
cursor: col-resize
|
||||
z-index: 10
|
||||
|
||||
.rt-tfoot
|
||||
flex: 1 0 auto
|
||||
display: flex
|
||||
flex-direction: column
|
||||
box-shadow: 0 0px 15px 0px alpha(black, .15)
|
||||
|
||||
.rt-td
|
||||
border-right:1px solid alpha(black, .05)
|
||||
&:last-child
|
||||
border-right:0
|
||||
|
||||
&.-striped
|
||||
.rt-tr.-odd
|
||||
background: alpha(black, .03)
|
||||
&.-highlight
|
||||
.rt-tbody
|
||||
.rt-tr:not(.-padRow):hover
|
||||
background: alpha(black, .05)
|
||||
|
||||
.-pagination
|
||||
z-index: 1
|
||||
display:flex
|
||||
justify-content: space-between
|
||||
align-items: stretch
|
||||
flex-wrap: wrap
|
||||
padding: 3px
|
||||
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
|
||||
width:100%
|
||||
height:100%
|
||||
border: 0
|
||||
border-radius: 3px
|
||||
padding: 6px
|
||||
font-size: 1em
|
||||
color: alpha(black, .6)
|
||||
background: alpha(black, .1)
|
||||
transition: all .1s ease
|
||||
cursor: pointer
|
||||
outline:none
|
||||
|
||||
&[disabled]
|
||||
opacity: .5
|
||||
cursor: default
|
||||
|
||||
&:not([disabled]):hover
|
||||
background: alpha(black, .3)
|
||||
color: white
|
||||
|
||||
.-previous
|
||||
.-next
|
||||
flex: 1
|
||||
text-align: center
|
||||
|
||||
.-center
|
||||
flex: 1.5
|
||||
text-align:center
|
||||
margin-bottom:0
|
||||
display: flex
|
||||
flex-direction: row
|
||||
flex-wrap: wrap
|
||||
align-items: center
|
||||
justify-content: space-around
|
||||
|
||||
.-pageInfo
|
||||
display: inline-block
|
||||
margin: 3px 10px
|
||||
white-space: nowrap
|
||||
|
||||
.-pageJump
|
||||
display:inline-block
|
||||
input
|
||||
width: 70px
|
||||
text-align:center
|
||||
|
||||
.-pageSizeOptions
|
||||
margin: 3px 10px
|
||||
|
||||
.rt-noData
|
||||
display:block
|
||||
position:absolute
|
||||
left:50%
|
||||
top:50%
|
||||
transform: translate(-50%, -50%)
|
||||
background: alpha(white, .8)
|
||||
transition: all .3s ease
|
||||
z-index: 1
|
||||
pointer-events: none
|
||||
padding: 20px
|
||||
color: alpha(black, .5)
|
||||
|
||||
.-loading
|
||||
display:block
|
||||
position:absolute
|
||||
left:0
|
||||
right:0
|
||||
top:0
|
||||
bottom:0
|
||||
background: alpha(white, .8)
|
||||
transition: all .3s ease
|
||||
z-index: -1
|
||||
opacity: 0
|
||||
pointer-events: none
|
||||
|
||||
> div
|
||||
position:absolute
|
||||
display: block
|
||||
text-align:center
|
||||
width:100%
|
||||
top:50%
|
||||
left: 0
|
||||
font-size: 15px
|
||||
color: alpha(black, .6)
|
||||
transform: translateY(-52%)
|
||||
transition: all .3s $easeOutQuad
|
||||
|
||||
&.-active
|
||||
opacity: 1
|
||||
z-index: 2
|
||||
pointer-events: all
|
||||
> div
|
||||
transform: translateY(50%)
|
||||
|
||||
.rt-resizing
|
||||
.rt-th
|
||||
.rt-td
|
||||
transition: none!important
|
||||
cursor: col-resize
|
||||
user-select none
|
||||
@@ -0,0 +1,128 @@
|
||||
export default Base =>
|
||||
class extends Base {
|
||||
componentWillMount () {
|
||||
this.setStateWithData(this.getDataModel(this.getResolvedState()))
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
this.fireFetchData()
|
||||
}
|
||||
|
||||
componentWillReceiveProps (nextProps, nextState) {
|
||||
const oldState = this.getResolvedState()
|
||||
const newState = this.getResolvedState(nextProps, nextState)
|
||||
|
||||
// Do a deep compare of new and old `defaultOption` and
|
||||
// if they are different reset `option = defaultOption`
|
||||
const defaultableOptions = ['sorted', 'filtered', 'resized', 'expanded']
|
||||
defaultableOptions.forEach(x => {
|
||||
const defaultName = `default${x.charAt(0).toUpperCase() + x.slice(1)}`
|
||||
if (JSON.stringify(oldState[defaultName]) !== JSON.stringify(newState[defaultName])) {
|
||||
newState[x] = newState[defaultName]
|
||||
}
|
||||
})
|
||||
|
||||
// If they change these table options, we need to reset defaults
|
||||
// or else we could get into a state where the user has changed the UI
|
||||
// and then disabled the ability to change it back.
|
||||
// e.g. If `filterable` has changed, set `filtered = defaultFiltered`
|
||||
const resettableOptions = ['sortable', 'filterable', 'resizable']
|
||||
resettableOptions.forEach(x => {
|
||||
if (oldState[x] !== newState[x]) {
|
||||
const baseName = x.replace('able', '')
|
||||
const optionName = `${baseName}ed`
|
||||
const defaultName = `default${optionName.charAt(0).toUpperCase() + optionName.slice(1)}`
|
||||
newState[optionName] = newState[defaultName]
|
||||
}
|
||||
})
|
||||
|
||||
// Props that trigger a data update
|
||||
if (
|
||||
oldState.data !== newState.data ||
|
||||
oldState.columns !== newState.columns ||
|
||||
oldState.pivotBy !== newState.pivotBy ||
|
||||
oldState.sorted !== newState.sorted ||
|
||||
oldState.filtered !== newState.filtered
|
||||
) {
|
||||
this.setStateWithData(this.getDataModel(newState))
|
||||
}
|
||||
}
|
||||
|
||||
setStateWithData (newState, cb) {
|
||||
const oldState = this.getResolvedState()
|
||||
const newResolvedState = this.getResolvedState({}, newState)
|
||||
const { freezeWhenExpanded } = newResolvedState
|
||||
|
||||
// Default to unfrozen state
|
||||
newResolvedState.frozen = false
|
||||
|
||||
// If freezeWhenExpanded is set, check for frozen conditions
|
||||
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) {
|
||||
if (newResolvedState.expanded[keys[i]]) {
|
||||
newResolvedState.frozen = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the data isn't frozen and either the data or
|
||||
// sorting model has changed, update the data
|
||||
if (
|
||||
(oldState.frozen && !newResolvedState.frozen) ||
|
||||
oldState.sorted !== newResolvedState.sorted ||
|
||||
oldState.filtered !== newResolvedState.filtered ||
|
||||
oldState.showFilters !== newResolvedState.showFilters ||
|
||||
(!newResolvedState.frozen && oldState.resolvedData !== newResolvedState.resolvedData)
|
||||
) {
|
||||
// Handle collapseOnsortedChange & collapseOnDataChange
|
||||
if (
|
||||
(oldState.sorted !== newResolvedState.sorted && this.props.collapseOnSortingChange) ||
|
||||
oldState.filtered !== newResolvedState.filtered ||
|
||||
oldState.showFilters !== newResolvedState.showFilters ||
|
||||
(oldState.sortedData &&
|
||||
!newResolvedState.frozen &&
|
||||
oldState.resolvedData !== newResolvedState.resolvedData &&
|
||||
this.props.collapseOnDataChange)
|
||||
) {
|
||||
newResolvedState.expanded = {}
|
||||
}
|
||||
|
||||
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.page = Math.max(
|
||||
newResolvedState.page >= newResolvedState.pages
|
||||
? newResolvedState.pages - 1
|
||||
: newResolvedState.page,
|
||||
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()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
+670
@@ -0,0 +1,670 @@
|
||||
import React from 'react'
|
||||
import _ from './utils'
|
||||
|
||||
export default Base =>
|
||||
class extends Base {
|
||||
getResolvedState (props, state) {
|
||||
const resolvedState = {
|
||||
..._.compactObject(this.state),
|
||||
..._.compactObject(this.props),
|
||||
..._.compactObject(state),
|
||||
..._.compactObject(props),
|
||||
}
|
||||
return resolvedState
|
||||
}
|
||||
|
||||
getDataModel (newState) {
|
||||
const {
|
||||
columns,
|
||||
pivotBy = [],
|
||||
data,
|
||||
resolveData,
|
||||
pivotIDKey,
|
||||
pivotValKey,
|
||||
subRowsKey,
|
||||
aggregatedKey,
|
||||
nestingLevelKey,
|
||||
originalKey,
|
||||
indexKey,
|
||||
groupedByPivotKey,
|
||||
SubComponent,
|
||||
} = newState
|
||||
|
||||
// Determine Header Groups
|
||||
let hasHeaderGroups = false
|
||||
columns.forEach(column => {
|
||||
if (column.columns) {
|
||||
hasHeaderGroups = true
|
||||
}
|
||||
})
|
||||
|
||||
let columnsWithExpander = [...columns]
|
||||
|
||||
let expanderColumn = columns.find(
|
||||
col => col.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) {
|
||||
expanderColumn = expanderColumn.columns.find(col => col.expander)
|
||||
}
|
||||
|
||||
// If we have SubComponent's we need to make sure we have an expander column
|
||||
if (SubComponent && !expanderColumn) {
|
||||
expanderColumn = { expander: true }
|
||||
columnsWithExpander = [expanderColumn, ...columnsWithExpander]
|
||||
}
|
||||
|
||||
const makeDecoratedColumn = (column, parentColumn) => {
|
||||
let dcol
|
||||
if (column.expander) {
|
||||
dcol = {
|
||||
...this.props.column,
|
||||
...this.props.expanderDefaults,
|
||||
...column,
|
||||
}
|
||||
} else {
|
||||
dcol = {
|
||||
...this.props.column,
|
||||
...column,
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
dcol.accessor = row => _.get(row, accessorString)
|
||||
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.'
|
||||
)
|
||||
}
|
||||
|
||||
// Fall back to an undefined accessor
|
||||
if (!dcol.accessor) {
|
||||
dcol.accessor = () => undefined
|
||||
}
|
||||
|
||||
return dcol
|
||||
}
|
||||
|
||||
const allDecoratedColumns = []
|
||||
|
||||
// Decorate the columns
|
||||
const decorateAndAddToAll = (column, parentColumn) => {
|
||||
const decoratedColumn = makeDecoratedColumn(column, parentColumn)
|
||||
allDecoratedColumns.push(decoratedColumn)
|
||||
return decoratedColumn
|
||||
}
|
||||
|
||||
const decoratedColumns = columnsWithExpander.map(column => {
|
||||
if (column.columns) {
|
||||
return {
|
||||
...column,
|
||||
columns: column.columns.map(d => decorateAndAddToAll(d, column)),
|
||||
}
|
||||
}
|
||||
return decorateAndAddToAll(column)
|
||||
})
|
||||
|
||||
// Build the visible columns, headers and flat column list
|
||||
let visibleColumns = decoratedColumns.slice()
|
||||
let allVisibleColumns = []
|
||||
|
||||
visibleColumns = visibleColumns.map(column => {
|
||||
if (column.columns) {
|
||||
const visibleSubColumns = column.columns.filter(
|
||||
d => (pivotBy.indexOf(d.id) > -1 ? false : _.getFirstDefined(d.show, true))
|
||||
)
|
||||
return {
|
||||
...column,
|
||||
columns: visibleSubColumns,
|
||||
}
|
||||
}
|
||||
return column
|
||||
})
|
||||
|
||||
visibleColumns = visibleColumns.filter(
|
||||
column =>
|
||||
column.columns
|
||||
? column.columns.length
|
||||
: pivotBy.indexOf(column.id) > -1
|
||||
? false
|
||||
: _.getFirstDefined(column.show, true)
|
||||
)
|
||||
|
||||
// Find any custom pivot location
|
||||
const pivotIndex = visibleColumns.findIndex(col => col.pivot)
|
||||
|
||||
// Handle Pivot Columns
|
||||
if (pivotBy.length) {
|
||||
// Retrieve the pivot columns in the correct pivot order
|
||||
const pivotColumns = []
|
||||
pivotBy.forEach(pivotID => {
|
||||
const found = allDecoratedColumns.find(d => d.id === pivotID)
|
||||
if (found) {
|
||||
pivotColumns.push(found)
|
||||
}
|
||||
})
|
||||
|
||||
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,
|
||||
columns: pivotColumns.map(col => ({
|
||||
...this.props.pivotDefaults,
|
||||
...col,
|
||||
pivoted: true,
|
||||
})),
|
||||
}
|
||||
|
||||
// Place the pivotColumns back into the visibleColumns
|
||||
if (pivotIndex >= 0) {
|
||||
pivotColumnGroup = {
|
||||
...visibleColumns[pivotIndex],
|
||||
...pivotColumnGroup,
|
||||
}
|
||||
visibleColumns.splice(pivotIndex, 1, pivotColumnGroup)
|
||||
} else {
|
||||
visibleColumns.unshift(pivotColumnGroup)
|
||||
}
|
||||
}
|
||||
|
||||
// Build Header Groups
|
||||
const headerGroups = []
|
||||
let currentSpan = []
|
||||
|
||||
// A convenience function to add a header and reset the currentSpan
|
||||
const addHeader = (columns, column) => {
|
||||
headerGroups.push({
|
||||
...this.props.column,
|
||||
...column,
|
||||
columns,
|
||||
})
|
||||
currentSpan = []
|
||||
}
|
||||
|
||||
// Build flast list of allVisibleColumns and HeaderGroups
|
||||
visibleColumns.forEach(column => {
|
||||
if (column.columns) {
|
||||
allVisibleColumns = allVisibleColumns.concat(column.columns)
|
||||
if (currentSpan.length > 0) {
|
||||
addHeader(currentSpan)
|
||||
}
|
||||
addHeader(column.columns, column)
|
||||
return
|
||||
}
|
||||
allVisibleColumns.push(column)
|
||||
currentSpan.push(column)
|
||||
})
|
||||
if (hasHeaderGroups && currentSpan.length > 0) {
|
||||
addHeader(currentSpan)
|
||||
}
|
||||
|
||||
// Access the data
|
||||
const accessRow = (d, i, level = 0) => {
|
||||
const row = {
|
||||
[originalKey]: d,
|
||||
[indexKey]: i,
|
||||
[subRowsKey]: d[subRowsKey],
|
||||
[nestingLevelKey]: level,
|
||||
}
|
||||
allDecoratedColumns.forEach(column => {
|
||||
if (column.expander) return
|
||||
row[column.id] = column.accessor(d)
|
||||
})
|
||||
if (row[subRowsKey]) {
|
||||
row[subRowsKey] = row[subRowsKey].map((d, i) => accessRow(d, i, level + 1))
|
||||
}
|
||||
return row
|
||||
}
|
||||
let resolvedData = resolveData(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 = {}
|
||||
aggregatingColumns.forEach(column => {
|
||||
const values = rows.map(d => d[column.id])
|
||||
aggregationValues[column.id] = column.aggregate(values, rows)
|
||||
})
|
||||
return aggregationValues
|
||||
}
|
||||
if (pivotBy.length) {
|
||||
const groupRecursively = (rows, keys, i = 0) => {
|
||||
// This is the last level, just return the rows
|
||||
if (i === keys.length) {
|
||||
return rows
|
||||
}
|
||||
// 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,
|
||||
}))
|
||||
// Recurse into the subRows
|
||||
groupedRows = groupedRows.map(rowGroup => {
|
||||
const subRows = groupRecursively(rowGroup[subRowsKey], keys, i + 1)
|
||||
return {
|
||||
...rowGroup,
|
||||
[subRowsKey]: subRows,
|
||||
[aggregatedKey]: true,
|
||||
...aggregate(subRows),
|
||||
}
|
||||
})
|
||||
return groupedRows
|
||||
}
|
||||
resolvedData = groupRecursively(resolvedData, pivotBy)
|
||||
}
|
||||
|
||||
return {
|
||||
...newState,
|
||||
resolvedData,
|
||||
allVisibleColumns,
|
||||
headerGroups,
|
||||
allDecoratedColumns,
|
||||
hasHeaderGroups,
|
||||
}
|
||||
}
|
||||
|
||||
getSortedData (resolvedState) {
|
||||
const {
|
||||
manual,
|
||||
sorted,
|
||||
filtered,
|
||||
defaultFilterMethod,
|
||||
resolvedData,
|
||||
allVisibleColumns,
|
||||
allDecoratedColumns,
|
||||
} = resolvedState
|
||||
|
||||
const sortMethodsByColumnID = {}
|
||||
|
||||
allDecoratedColumns.filter(col => col.sortMethod).forEach(col => {
|
||||
sortMethodsByColumnID[col.id] = col.sortMethod
|
||||
})
|
||||
|
||||
// Resolve the data from either manual data or sorted data
|
||||
return {
|
||||
sortedData: manual
|
||||
? resolvedData
|
||||
: this.sortData(
|
||||
this.filterData(resolvedData, filtered, defaultFilterMethod, allVisibleColumns),
|
||||
sorted,
|
||||
sortMethodsByColumnID
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fireFetchData () {
|
||||
this.props.onFetchData(this.getResolvedState(), this)
|
||||
}
|
||||
|
||||
getPropOrState (key) {
|
||||
return _.getFirstDefined(this.props[key], this.state[key])
|
||||
}
|
||||
|
||||
getStateOrProp (key) {
|
||||
return _.getFirstDefined(this.state[key], this.props[key])
|
||||
}
|
||||
|
||||
filterData (data, filtered, defaultFilterMethod, allVisibleColumns) {
|
||||
let filteredData = data
|
||||
|
||||
if (filtered.length) {
|
||||
filteredData = filtered.reduce((filteredSoFar, nextFilter) => {
|
||||
const column = allVisibleColumns.find(x => x.id === nextFilter.id)
|
||||
|
||||
// Don't filter hidden columns or columns that have had their filters disabled
|
||||
if (!column || column.filterable === false) {
|
||||
return filteredSoFar
|
||||
}
|
||||
|
||||
const filterMethod = column.filterMethod || defaultFilterMethod
|
||||
|
||||
// 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))
|
||||
}, filteredData)
|
||||
|
||||
// Apply the filter to the subrows if we are pivoting, and then
|
||||
// filter any rows without subcolumns because it would be strange to show
|
||||
filteredData = filteredData
|
||||
.map(row => {
|
||||
if (!row[this.props.subRowsKey]) {
|
||||
return row
|
||||
}
|
||||
return {
|
||||
...row,
|
||||
[this.props.subRowsKey]: this.filterData(
|
||||
row[this.props.subRowsKey],
|
||||
filtered,
|
||||
defaultFilterMethod,
|
||||
allVisibleColumns
|
||||
),
|
||||
}
|
||||
})
|
||||
.filter(row => {
|
||||
if (!row[this.props.subRowsKey]) {
|
||||
return true
|
||||
}
|
||||
return row[this.props.subRowsKey].length > 0
|
||||
})
|
||||
}
|
||||
|
||||
return filteredData
|
||||
}
|
||||
|
||||
sortData (data, sorted, sortMethodsByColumnID = {}) {
|
||||
if (!sorted.length) {
|
||||
return data
|
||||
}
|
||||
|
||||
const sortedData = (this.props.orderByMethod || _.orderBy)(
|
||||
data,
|
||||
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) => this.props.defaultSortMethod(a[sort.id], b[sort.id], sort.desc)
|
||||
}),
|
||||
sorted.map(d => !d.desc),
|
||||
this.props.indexKey
|
||||
)
|
||||
|
||||
sortedData.forEach(row => {
|
||||
if (!row[this.props.subRowsKey]) {
|
||||
return
|
||||
}
|
||||
row[this.props.subRowsKey] = this.sortData(
|
||||
row[this.props.subRowsKey],
|
||||
sorted,
|
||||
sortMethodsByColumnID
|
||||
)
|
||||
})
|
||||
|
||||
return sortedData
|
||||
}
|
||||
|
||||
getMinRows () {
|
||||
return _.getFirstDefined(this.props.minRows, this.getStateOrProp('pageSize'))
|
||||
}
|
||||
|
||||
// User actions
|
||||
onPageChange (page) {
|
||||
const { onPageChange, collapseOnPageChange } = this.props
|
||||
|
||||
const newState = { page }
|
||||
if (collapseOnPageChange) {
|
||||
newState.expanded = {}
|
||||
}
|
||||
this.setStateWithData(newState, () => onPageChange && onPageChange(page))
|
||||
}
|
||||
|
||||
onPageSizeChange (newPageSize) {
|
||||
const { onPageSizeChange } = this.props
|
||||
const { pageSize, page } = this.getResolvedState()
|
||||
|
||||
// Normalize the page to display
|
||||
const currentRow = pageSize * page
|
||||
const newPage = Math.floor(currentRow / newPageSize)
|
||||
|
||||
this.setStateWithData(
|
||||
{
|
||||
pageSize: newPageSize,
|
||||
page: newPage,
|
||||
},
|
||||
() => onPageSizeChange && onPageSizeChange(newPageSize, newPage)
|
||||
)
|
||||
}
|
||||
|
||||
sortColumn (column, additive) {
|
||||
const { sorted, skipNextSort, defaultSortDesc } = this.getResolvedState()
|
||||
|
||||
const firstSortDirection = Object.prototype.hasOwnProperty.call(column, 'defaultSortDesc')
|
||||
? column.defaultSortDesc
|
||||
: defaultSortDesc
|
||||
const secondSortDirection = !firstSortDirection
|
||||
|
||||
// we can't stop event propagation from the column resize move handlers
|
||||
// attached to the document because of react's synthetic events
|
||||
// so we have to prevent the sort function from actually sorting
|
||||
// if we click on the column resize element within a header.
|
||||
if (skipNextSort) {
|
||||
this.setStateWithData({
|
||||
skipNextSort: false,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
const { onSortedChange } = this.props
|
||||
|
||||
let newSorted = _.clone(sorted || []).map(d => {
|
||||
d.desc = _.isSortingDesc(d)
|
||||
return d
|
||||
})
|
||||
if (!_.isArray(column)) {
|
||||
// Single-Sort
|
||||
const existingIndex = newSorted.findIndex(d => d.id === column.id)
|
||||
if (existingIndex > -1) {
|
||||
const existing = newSorted[existingIndex]
|
||||
if (existing.desc === secondSortDirection) {
|
||||
if (additive) {
|
||||
newSorted.splice(existingIndex, 1)
|
||||
} else {
|
||||
existing.desc = firstSortDirection
|
||||
newSorted = [existing]
|
||||
}
|
||||
} else {
|
||||
existing.desc = secondSortDirection
|
||||
if (!additive) {
|
||||
newSorted = [existing]
|
||||
}
|
||||
}
|
||||
} else if (additive) {
|
||||
newSorted.push({
|
||||
id: column.id,
|
||||
desc: firstSortDirection,
|
||||
})
|
||||
} else {
|
||||
newSorted = [
|
||||
{
|
||||
id: column.id,
|
||||
desc: firstSortDirection,
|
||||
},
|
||||
]
|
||||
}
|
||||
} else {
|
||||
// Multi-Sort
|
||||
const existingIndex = newSorted.findIndex(d => d.id === column[0].id)
|
||||
// Existing Sorted Column
|
||||
if (existingIndex > -1) {
|
||||
const existing = newSorted[existingIndex]
|
||||
if (existing.desc === secondSortDirection) {
|
||||
if (additive) {
|
||||
newSorted.splice(existingIndex, column.length)
|
||||
} else {
|
||||
column.forEach((d, i) => {
|
||||
newSorted[existingIndex + i].desc = firstSortDirection
|
||||
})
|
||||
}
|
||||
} else {
|
||||
column.forEach((d, i) => {
|
||||
newSorted[existingIndex + i].desc = secondSortDirection
|
||||
})
|
||||
}
|
||||
if (!additive) {
|
||||
newSorted = newSorted.slice(existingIndex, column.length)
|
||||
}
|
||||
// New Sort Column
|
||||
} else if (additive) {
|
||||
newSorted = newSorted.concat(
|
||||
column.map(d => ({
|
||||
id: d.id,
|
||||
desc: firstSortDirection,
|
||||
}))
|
||||
)
|
||||
} else {
|
||||
newSorted = column.map(d => ({
|
||||
id: d.id,
|
||||
desc: firstSortDirection,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
this.setStateWithData(
|
||||
{
|
||||
page: (!sorted.length && newSorted.length) || !additive ? 0 : this.state.page,
|
||||
sorted: newSorted,
|
||||
},
|
||||
() => onSortedChange && onSortedChange(newSorted, column, additive)
|
||||
)
|
||||
}
|
||||
|
||||
filterColumn (column, value) {
|
||||
const { filtered } = this.getResolvedState()
|
||||
const { onFilteredChange } = this.props
|
||||
|
||||
// Remove old filter first if it exists
|
||||
const newFiltering = (filtered || []).filter(x => x.id !== column.id)
|
||||
|
||||
if (value !== '') {
|
||||
newFiltering.push({
|
||||
id: column.id,
|
||||
value,
|
||||
})
|
||||
}
|
||||
|
||||
this.setStateWithData(
|
||||
{
|
||||
filtered: newFiltering,
|
||||
},
|
||||
() => onFilteredChange && onFilteredChange(newFiltering, column, value)
|
||||
)
|
||||
}
|
||||
|
||||
resizeColumnStart (event, column, isTouch) {
|
||||
event.stopPropagation()
|
||||
const parentWidth = event.target.parentElement.getBoundingClientRect().width
|
||||
|
||||
let pageX
|
||||
if (isTouch) {
|
||||
pageX = event.changedTouches[0].pageX
|
||||
} else {
|
||||
pageX = event.pageX
|
||||
}
|
||||
|
||||
this.trapEvents = true
|
||||
this.setStateWithData(
|
||||
{
|
||||
currentlyResizing: {
|
||||
id: column.id,
|
||||
startX: pageX,
|
||||
parentWidth,
|
||||
},
|
||||
},
|
||||
() => {
|
||||
if (isTouch) {
|
||||
document.addEventListener('touchmove', this.resizeColumnMoving)
|
||||
document.addEventListener('touchcancel', this.resizeColumnEnd)
|
||||
document.addEventListener('touchend', this.resizeColumnEnd)
|
||||
} else {
|
||||
document.addEventListener('mousemove', this.resizeColumnMoving)
|
||||
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'
|
||||
|
||||
if (isTouch) {
|
||||
document.removeEventListener('touchmove', this.resizeColumnMoving)
|
||||
document.removeEventListener('touchcancel', this.resizeColumnEnd)
|
||||
document.removeEventListener('touchend', this.resizeColumnEnd)
|
||||
}
|
||||
|
||||
// If its a touch event clear the mouse one's as well because sometimes
|
||||
// the mouseDown event gets called as well, but the mouseUp event doesn't
|
||||
document.removeEventListener('mousemove', this.resizeColumnMoving)
|
||||
document.removeEventListener('mouseup', this.resizeColumnEnd)
|
||||
document.removeEventListener('mouseleave', this.resizeColumnEnd)
|
||||
|
||||
// The touch events don't propagate up to the sorting's onMouseDown event so
|
||||
// no need to prevent it from happening or else the first click after a touch
|
||||
// event resize will not sort the column.
|
||||
if (!isTouch) {
|
||||
this.setStateWithData({
|
||||
skipNextSort: true,
|
||||
currentlyResizing: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
import React, { Component } from 'react'
|
||||
import classnames from 'classnames'
|
||||
//
|
||||
// import _ from './utils'
|
||||
|
||||
const defaultButton = props => (
|
||||
<button type="button" {...props} className="-btn">
|
||||
{props.children}
|
||||
</button>
|
||||
)
|
||||
|
||||
export default class ReactTablePagination extends Component {
|
||||
constructor (props) {
|
||||
super()
|
||||
|
||||
this.getSafePage = this.getSafePage.bind(this)
|
||||
this.changePage = this.changePage.bind(this)
|
||||
this.applyPage = this.applyPage.bind(this)
|
||||
|
||||
this.state = {
|
||||
page: props.page,
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
this.setState({ page: nextProps.page })
|
||||
}
|
||||
|
||||
getSafePage (page) {
|
||||
if (Number.isNaN(page)) {
|
||||
page = this.props.page
|
||||
}
|
||||
return Math.min(Math.max(page, 0), this.props.pages - 1)
|
||||
}
|
||||
|
||||
changePage (page) {
|
||||
page = this.getSafePage(page)
|
||||
this.setState({ page })
|
||||
if (this.props.page !== page) {
|
||||
this.props.onPageChange(page)
|
||||
}
|
||||
}
|
||||
|
||||
applyPage (e) {
|
||||
if (e) {
|
||||
e.preventDefault()
|
||||
}
|
||||
const page = this.state.page
|
||||
this.changePage(page === '' ? this.props.page : page)
|
||||
}
|
||||
|
||||
render () {
|
||||
const {
|
||||
// Computed
|
||||
pages,
|
||||
// Props
|
||||
page,
|
||||
showPageSizeOptions,
|
||||
pageSizeOptions,
|
||||
pageSize,
|
||||
showPageJump,
|
||||
canPrevious,
|
||||
canNext,
|
||||
onPageSizeChange,
|
||||
className,
|
||||
PreviousComponent = defaultButton,
|
||||
NextComponent = defaultButton,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<div className={classnames(className, '-pagination')} style={this.props.style}>
|
||||
<div className="-previous">
|
||||
<PreviousComponent
|
||||
onClick={() => {
|
||||
if (!canPrevious) return
|
||||
this.changePage(page - 1)
|
||||
}}
|
||||
disabled={!canPrevious}
|
||||
>
|
||||
{this.props.previousText}
|
||||
</PreviousComponent>
|
||||
</div>
|
||||
<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>
|
||||
)}{' '}
|
||||
{this.props.ofText} <span className="-totalPages">{pages || 1}</span>
|
||||
</span>
|
||||
{showPageSizeOptions && (
|
||||
<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>
|
||||
))}
|
||||
</select>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="-next">
|
||||
<NextComponent
|
||||
onClick={() => {
|
||||
if (!canNext) return
|
||||
this.changePage(page + 1)
|
||||
}}
|
||||
disabled={!canNext}
|
||||
>
|
||||
{this.props.nextText}
|
||||
</NextComponent>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
export default {
|
||||
// General
|
||||
data: PropTypes.any.isRequired,
|
||||
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]),
|
||||
}
|
||||
@@ -1,195 +0,0 @@
|
||||
import { useMemo, useState } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import { getFirstDefined, sum } from './utils'
|
||||
|
||||
const propTypes = {
|
||||
defaultFlex: PropTypes.number,
|
||||
}
|
||||
|
||||
export const actions = {}
|
||||
|
||||
export default function useFlexLayout (api, props = {}) {
|
||||
// Validate props
|
||||
PropTypes.checkPropTypes(propTypes, props, 'property', 'useFlexLayout')
|
||||
|
||||
const {
|
||||
hooks: {
|
||||
getRowProps, getHeaderRowProps, getHeaderProps, getCellProps,
|
||||
},
|
||||
visibleColumns,
|
||||
} = api
|
||||
|
||||
const { defaultFlex = 1 } = props
|
||||
|
||||
const [columnMeasurements, setColumnMeasurements] = useState({})
|
||||
|
||||
const rowStyles = useMemo(
|
||||
() => {
|
||||
let sumWidth = 0
|
||||
visibleColumns.forEach(column => {
|
||||
const { width, minWidth } = getSizesForColumn(
|
||||
column,
|
||||
defaultFlex,
|
||||
undefined,
|
||||
undefined,
|
||||
api
|
||||
)
|
||||
if (width) {
|
||||
sumWidth += width
|
||||
} else if (minWidth) {
|
||||
sumWidth += minWidth
|
||||
} else {
|
||||
sumWidth += defaultFlex
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
style: {
|
||||
display: 'flex',
|
||||
minWidth: `${sumWidth}px`,
|
||||
},
|
||||
}
|
||||
},
|
||||
[visibleColumns]
|
||||
)
|
||||
|
||||
getRowProps.push(row => rowStyles)
|
||||
getHeaderRowProps.push(row => rowStyles)
|
||||
|
||||
getHeaderProps.push(column => ({
|
||||
style: {
|
||||
boxSizing: 'border-box',
|
||||
...getStylesForColumn(column, columnMeasurements, defaultFlex, api),
|
||||
},
|
||||
// [refKey]: el => {
|
||||
// renderedCellInfoRef.current[key] = {
|
||||
// column,
|
||||
// el
|
||||
// };
|
||||
// },
|
||||
}))
|
||||
|
||||
getCellProps.push(cell => ({
|
||||
style: {
|
||||
display: 'block',
|
||||
boxSizing: 'border-box',
|
||||
...getStylesForColumn(cell.column, columnMeasurements, defaultFlex, undefined, api),
|
||||
},
|
||||
// [refKey]: el => {
|
||||
// renderedCellInfoRef.current[columnPathStr] = {
|
||||
// column,
|
||||
// el
|
||||
// };
|
||||
// }
|
||||
}))
|
||||
|
||||
return {
|
||||
rowStyles,
|
||||
}
|
||||
}
|
||||
|
||||
function getStylesForColumn (column, columnMeasurements, defaultFlex, api) {
|
||||
const { flex, width, maxWidth } = getSizesForColumn(column, columnMeasurements, defaultFlex, api)
|
||||
|
||||
return {
|
||||
flex: `${flex} 0 auto`,
|
||||
width: `${width}px`,
|
||||
maxWidth: `${maxWidth}px`,
|
||||
}
|
||||
}
|
||||
|
||||
function getSizesForColumn (
|
||||
{
|
||||
columns, id, width, minWidth, maxWidth,
|
||||
},
|
||||
columnMeasurements,
|
||||
defaultFlex,
|
||||
api
|
||||
) {
|
||||
if (columns) {
|
||||
columns = columns
|
||||
.map(column => getSizesForColumn(column, columnMeasurements, defaultFlex, api))
|
||||
.filter(Boolean)
|
||||
|
||||
if (!columns.length) {
|
||||
return false
|
||||
}
|
||||
|
||||
const flex = sum(columns.map(col => col.flex))
|
||||
const width = sum(columns.map(col => col.width))
|
||||
const maxWidth = sum(columns.map(col => col.maxWidth))
|
||||
|
||||
return {
|
||||
flex,
|
||||
width,
|
||||
maxWidth,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
flex: width ? 0 : defaultFlex,
|
||||
width:
|
||||
width === 'auto'
|
||||
? columnMeasurements[id] || defaultFlex
|
||||
: getFirstDefined(width, minWidth, defaultFlex),
|
||||
maxWidth,
|
||||
}
|
||||
}
|
||||
|
||||
// const resetRefs = () => {
|
||||
// if (debug) console.info("resetRefs");
|
||||
// renderedCellInfoRef.current = {};
|
||||
// };
|
||||
|
||||
// const calculateAutoWidths = () => {
|
||||
// RAF(() => {
|
||||
// const newColumnMeasurements = {};
|
||||
// Object.values(renderedCellInfoRef.current).forEach(({ column, el }) => {
|
||||
// if (!el) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// let measurement = 0;
|
||||
|
||||
// const measureChildren = children => {
|
||||
// if (children) {
|
||||
// [].slice.call(children).forEach(child => {
|
||||
// measurement = Math.max(
|
||||
// measurement,
|
||||
// Math.ceil(child.offsetWidth) || 0
|
||||
// );
|
||||
// measureChildren(child.children);
|
||||
// });
|
||||
// }
|
||||
// return measurement;
|
||||
// };
|
||||
|
||||
// const parentDims = getElementDimensions(el);
|
||||
// measureChildren(el.children);
|
||||
|
||||
// newColumnMeasurements[column.id] = Math.max(
|
||||
// newColumnMeasurements[column.id] || 0,
|
||||
// measurement + parentDims.paddingLeft + parentDims.paddingRight
|
||||
// );
|
||||
// });
|
||||
|
||||
// const oldKeys = Object.keys(columnMeasurements);
|
||||
// const newKeys = Object.keys(newColumnMeasurements);
|
||||
|
||||
// const needsUpdate =
|
||||
// oldKeys.length !== newKeys.length ||
|
||||
// oldKeys.some(key => {
|
||||
// return columnMeasurements[key] !== newColumnMeasurements[key];
|
||||
// });
|
||||
|
||||
// if (needsUpdate) {
|
||||
// setState(old => {
|
||||
// return {
|
||||
// ...old,
|
||||
// columnMeasurements: newColumnMeasurements
|
||||
// };
|
||||
// }, actions.updateAutoWidth);
|
||||
// }
|
||||
// });
|
||||
// };
|
||||
@@ -1,155 +0,0 @@
|
||||
import { useMemo, useState, useLayoutEffect } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import { warnUnknownProps } from './utils'
|
||||
import useControlledState from './hooks/useControlledState'
|
||||
|
||||
const propTypes = {
|
||||
defaultPageSize: PropTypes.number,
|
||||
defaultPageIndex: PropTypes.number,
|
||||
pageSize: PropTypes.number,
|
||||
pages: PropTypes.number,
|
||||
pageIndex: PropTypes.number,
|
||||
onStateChange: PropTypes.func,
|
||||
stateReducer: PropTypes.func,
|
||||
subRowsKey: PropTypes.string,
|
||||
debug: PropTypes.bool,
|
||||
}
|
||||
|
||||
export const actions = {
|
||||
pageChange: '__pageChange__',
|
||||
}
|
||||
|
||||
export default function usePagination (
|
||||
{
|
||||
debug: parentDebug, rows, prepareRows, groupedRows, sortedRows, filteredRows,
|
||||
},
|
||||
props = {}
|
||||
) {
|
||||
// Validate props
|
||||
PropTypes.checkPropTypes(propTypes, props, 'property', 'usePagination')
|
||||
|
||||
// Destructure props
|
||||
const {
|
||||
defaultPageSize = 10,
|
||||
defaultPageIndex = 0,
|
||||
pageSize: userPageSize,
|
||||
pageIndex: userPageIndex,
|
||||
state: userState,
|
||||
manualPagination,
|
||||
pageCount: userPageCount,
|
||||
pageOptions: userPageOptions,
|
||||
debug = parentDebug,
|
||||
...rest
|
||||
} = props
|
||||
|
||||
warnUnknownProps(rest)
|
||||
|
||||
const defaultState = useState({})
|
||||
const localState = userState || defaultState
|
||||
|
||||
// Build the controllable state
|
||||
const [{ pageSize, pageIndex }, setState] = useControlledState(
|
||||
localState,
|
||||
{
|
||||
pageSize: defaultPageSize,
|
||||
pageIndex: defaultPageIndex,
|
||||
},
|
||||
{
|
||||
pageSize: userPageSize,
|
||||
pageIndex: userPageIndex,
|
||||
}
|
||||
)
|
||||
|
||||
useLayoutEffect(
|
||||
() => {
|
||||
if (manualPagination) {
|
||||
return
|
||||
}
|
||||
setState(
|
||||
old => ({
|
||||
...old,
|
||||
pageIndex: 0,
|
||||
}),
|
||||
actions.pageChange
|
||||
)
|
||||
},
|
||||
[groupedRows, sortedRows, filteredRows]
|
||||
)
|
||||
|
||||
const { pages, pageCount } = useMemo(
|
||||
() => {
|
||||
if (manualPagination) {
|
||||
return {
|
||||
pages: [rows],
|
||||
pageCount: userPageCount,
|
||||
}
|
||||
}
|
||||
if (debug) console.info('getPages')
|
||||
|
||||
// Create a new pages with the first page ready to go.
|
||||
const pages = rows.length ? [] : [[]]
|
||||
|
||||
// Start the pageIndex and currentPage cursors
|
||||
let cursor = 0
|
||||
while (cursor < rows.length) {
|
||||
const end = cursor + pageSize
|
||||
pages.push(rows.slice(cursor, end))
|
||||
cursor = end
|
||||
}
|
||||
|
||||
const pageCount = pages.length
|
||||
|
||||
return {
|
||||
pages,
|
||||
pageCount,
|
||||
pageOptions,
|
||||
}
|
||||
},
|
||||
[rows, pageSize, userPageCount]
|
||||
)
|
||||
|
||||
const pageOptions = [...new Array(pageCount)].map((d, i) => i)
|
||||
const page = manualPagination ? rows : pages[pageIndex] || []
|
||||
const canPreviousPage = pageIndex > 0
|
||||
const canNextPage = pageIndex < pageCount - 1
|
||||
|
||||
const gotoPage = pageIndex => {
|
||||
if (debug) console.info('gotoPage')
|
||||
return setState(old => {
|
||||
if (pageIndex < 0 || pageIndex > pageCount - 1) {
|
||||
return old
|
||||
}
|
||||
return {
|
||||
...old,
|
||||
pageIndex,
|
||||
}
|
||||
}, actions.pageChange)
|
||||
}
|
||||
|
||||
const previousPage = () => gotoPage(pageIndex - 1)
|
||||
|
||||
const nextPage = () => gotoPage(pageIndex + 1)
|
||||
|
||||
const setPageSize = pageSize => {
|
||||
setState(old => ({
|
||||
...old,
|
||||
pageSize,
|
||||
}))
|
||||
}
|
||||
|
||||
prepareRows(page)
|
||||
|
||||
return {
|
||||
pages,
|
||||
pageIndex,
|
||||
pageOptions,
|
||||
page,
|
||||
canPreviousPage,
|
||||
canNextPage,
|
||||
gotoPage,
|
||||
previousPage,
|
||||
nextPage,
|
||||
setPageSize,
|
||||
}
|
||||
}
|
||||
@@ -1,470 +0,0 @@
|
||||
import { useState, useMemo, useRef } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
//
|
||||
import {
|
||||
defaultOrderByFn,
|
||||
defaultSortByFn,
|
||||
defaultGroupByFn,
|
||||
defaultFilterFn,
|
||||
flexRender,
|
||||
findExpandedDepth,
|
||||
applyHooks,
|
||||
mergeProps,
|
||||
warnUnknownProps,
|
||||
} from './utils'
|
||||
|
||||
// Internal Hooks
|
||||
import useControlledState from './hooks/useControlledState'
|
||||
import useColumns from './hooks/useColumns'
|
||||
import useTableMethods from './hooks/useTableMethods'
|
||||
import useAccessedRows from './hooks/useAccessedRows'
|
||||
import useGroupedRows from './hooks/useGroupedRows'
|
||||
import useFilteredRows from './hooks/useFilteredRows'
|
||||
import useSortedRows from './hooks/useSortedRows'
|
||||
import useExpandedRows from './hooks/useExpandedRows'
|
||||
|
||||
const defaultFlex = 1
|
||||
const renderErr =
|
||||
'You must specify a render "type". This could be "Header", "Filter", or any other custom renderers you have set on your column.'
|
||||
|
||||
export const actions = {
|
||||
sortByChange: '__sortByChange',
|
||||
updateAutoWidth: '__updateAutoWidth__',
|
||||
toggleGroupBy: '__toggleGroupBy__',
|
||||
toggleExpanded: '__toggleExpanded__',
|
||||
setExpanded: '__setExpanded__',
|
||||
setFilter: '__setFilter__',
|
||||
setAllFilters: '__setAllFilters__',
|
||||
}
|
||||
|
||||
const propTypes = {
|
||||
// General
|
||||
data: PropTypes.any,
|
||||
columns: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
aggregate: PropTypes.func,
|
||||
filterFn: PropTypes.func,
|
||||
filterAll: PropTypes.bool,
|
||||
sortByFn: PropTypes.func,
|
||||
resolvedDefaultSortDesc: PropTypes.bool,
|
||||
canSortBy: PropTypes.bool,
|
||||
canGroupBy: PropTypes.bool,
|
||||
Cell: PropTypes.any,
|
||||
Header: PropTypes.any,
|
||||
Filter: PropTypes.any,
|
||||
})
|
||||
),
|
||||
defaultFilters: PropTypes.array,
|
||||
defaultSortBy: PropTypes.array,
|
||||
defaultGroupBy: PropTypes.array,
|
||||
|
||||
groupBy: PropTypes.array,
|
||||
filters: PropTypes.array,
|
||||
sortBy: PropTypes.array,
|
||||
|
||||
filterFn: PropTypes.func,
|
||||
sortByFn: PropTypes.func,
|
||||
orderByFn: PropTypes.func,
|
||||
groupByFn: PropTypes.func,
|
||||
|
||||
manualGrouping: PropTypes.bool,
|
||||
manualFilters: PropTypes.bool,
|
||||
manualSorting: PropTypes.bool,
|
||||
|
||||
disableGrouping: PropTypes.bool,
|
||||
disableFilters: PropTypes.bool,
|
||||
disableSorting: PropTypes.bool,
|
||||
|
||||
defaultSortDesc: PropTypes.bool,
|
||||
disableMultiSort: PropTypes.bool,
|
||||
subRowsKey: PropTypes.string,
|
||||
expandedKey: PropTypes.string,
|
||||
userAggregations: PropTypes.object,
|
||||
|
||||
debug: PropTypes.bool,
|
||||
}
|
||||
|
||||
export default function useReactTable (props) {
|
||||
// Validate props
|
||||
PropTypes.checkPropTypes(propTypes, props, 'property', 'useReactTable')
|
||||
|
||||
// Destructure props
|
||||
const {
|
||||
data = [],
|
||||
state: userState,
|
||||
columns: userColumns,
|
||||
sortBy: userSortBy,
|
||||
groupBy: userGroupBy,
|
||||
filters: userFilters,
|
||||
expanded: userExpanded,
|
||||
defaultSortBy = [],
|
||||
defaultGroupBy = [],
|
||||
defaultFilters = {},
|
||||
defaultExpanded = {},
|
||||
manualGrouping,
|
||||
manualFilters,
|
||||
manualSorting,
|
||||
disableSorting,
|
||||
disableGrouping,
|
||||
disableFilters,
|
||||
defaultSortDesc,
|
||||
disableMultiSort,
|
||||
subRowsKey = 'subRows',
|
||||
expandedKey = 'expanded',
|
||||
filterFn = defaultFilterFn,
|
||||
sortByFn = defaultSortByFn,
|
||||
orderByFn = defaultOrderByFn,
|
||||
groupByFn = defaultGroupByFn,
|
||||
userAggregations = {},
|
||||
debug,
|
||||
...rest
|
||||
} = props
|
||||
|
||||
warnUnknownProps(rest)
|
||||
|
||||
const defaultState = useState({})
|
||||
|
||||
const localState = userState || defaultState
|
||||
|
||||
// Build the controllable state
|
||||
const [{
|
||||
sortBy, groupBy, filters, expanded,
|
||||
}, setState] = useControlledState(
|
||||
localState,
|
||||
{
|
||||
sortBy: defaultSortBy,
|
||||
groupBy: defaultGroupBy,
|
||||
filters: defaultFilters,
|
||||
expanded: defaultExpanded,
|
||||
},
|
||||
{
|
||||
sortBy: userSortBy,
|
||||
groupBy: userGroupBy,
|
||||
filters: userFilters,
|
||||
expanded: userExpanded,
|
||||
}
|
||||
)
|
||||
|
||||
const expandedDepth = findExpandedDepth(expanded)
|
||||
const renderedCellInfoRef = useRef({})
|
||||
|
||||
// Build the base column
|
||||
let { columns, headerGroups, headers } = useColumns({
|
||||
debug,
|
||||
groupBy,
|
||||
userColumns,
|
||||
defaultFlex,
|
||||
renderedCellInfoRef,
|
||||
disableSorting,
|
||||
disableGrouping,
|
||||
disableFilters,
|
||||
})
|
||||
|
||||
// Use data and columns as memoization
|
||||
const accessedRows = useAccessedRows({
|
||||
debug,
|
||||
data,
|
||||
columns,
|
||||
subRowsKey,
|
||||
})
|
||||
|
||||
// Use rows and groupBy as memoization for row grouping
|
||||
const groupedRows = useGroupedRows({
|
||||
debug,
|
||||
rows: accessedRows,
|
||||
groupBy,
|
||||
columns,
|
||||
groupByFn,
|
||||
manualGrouping,
|
||||
userAggregations,
|
||||
})
|
||||
|
||||
const filteredRows = useFilteredRows({
|
||||
debug,
|
||||
rows: groupedRows,
|
||||
filters,
|
||||
columns,
|
||||
filterFn,
|
||||
manualFilters,
|
||||
})
|
||||
|
||||
const sortedRows = useSortedRows({
|
||||
debug,
|
||||
rows: filteredRows,
|
||||
sortBy,
|
||||
columns,
|
||||
orderByFn,
|
||||
sortByFn,
|
||||
manualSorting,
|
||||
})
|
||||
|
||||
const rows = useExpandedRows({
|
||||
debug,
|
||||
rows: sortedRows,
|
||||
expanded,
|
||||
expandedKey,
|
||||
columns,
|
||||
groupBy,
|
||||
setState,
|
||||
actions,
|
||||
})
|
||||
|
||||
// Mutate columns to reflect sorting state
|
||||
columns.forEach(column => {
|
||||
const { id } = column
|
||||
column.sorted = sortBy.find(d => d.id === id)
|
||||
column.sortedIndex = sortBy.findIndex(d => d.id === id)
|
||||
column.sortedDesc = column.sorted ? column.sorted.desc : undefined
|
||||
column.filterVal = filters[id]
|
||||
})
|
||||
|
||||
// Public API
|
||||
|
||||
const {
|
||||
toggleExpandedByPath,
|
||||
toggleSortByID,
|
||||
toggleGroupBy,
|
||||
setFilter,
|
||||
setAllFilters,
|
||||
} = useTableMethods({
|
||||
debug,
|
||||
setState,
|
||||
actions,
|
||||
groupBy,
|
||||
columns,
|
||||
defaultSortDesc,
|
||||
filters,
|
||||
})
|
||||
|
||||
const state = {
|
||||
// State
|
||||
columns,
|
||||
expandedDepth,
|
||||
accessedRows,
|
||||
groupedRows,
|
||||
filteredRows,
|
||||
sortedRows,
|
||||
rows,
|
||||
headerGroups,
|
||||
renderedCellInfoRef,
|
||||
disableMultiSort,
|
||||
|
||||
// Controllable state
|
||||
groupBy,
|
||||
filters,
|
||||
sortBy,
|
||||
expanded,
|
||||
}
|
||||
|
||||
const api = {
|
||||
// State manager,
|
||||
...state,
|
||||
|
||||
// Methods
|
||||
toggleExpandedByPath,
|
||||
toggleSortByID,
|
||||
toggleGroupBy,
|
||||
setFilter,
|
||||
setAllFilters,
|
||||
}
|
||||
|
||||
columns.forEach(column => attachApi(column, api))
|
||||
headers.forEach(header => attachApi(header, api))
|
||||
|
||||
const visibleColumns = columns.filter(column => {
|
||||
column.visible = typeof column.show === 'function' ? column.show(state) : !!column.show
|
||||
return column.visible
|
||||
})
|
||||
|
||||
state.visibleColumns = visibleColumns
|
||||
api.visibleColumns = visibleColumns
|
||||
|
||||
api.hooks = {
|
||||
getTableProps: [],
|
||||
getRowProps: [],
|
||||
getHeaderRowProps: [],
|
||||
getCellProps: [],
|
||||
getHeaderProps: [],
|
||||
getSortByToggleProps: [],
|
||||
getGroupByToggleProps: [],
|
||||
}
|
||||
|
||||
api.getTableProps = props => mergeProps(
|
||||
{
|
||||
style: {
|
||||
overflowX: 'auto',
|
||||
},
|
||||
},
|
||||
applyHooks(api.hooks.getTableProps),
|
||||
props
|
||||
)
|
||||
|
||||
api.getRowProps = props => mergeProps(applyHooks(api.hooks.getRowProps), props)
|
||||
|
||||
// Filter out hidden header groups or header groups that
|
||||
// have no visible columns, then add the getRowProps method
|
||||
headerGroups = useMemo(
|
||||
() =>
|
||||
headerGroups.filter((headerGroup, i) => {
|
||||
headerGroup.headers = headerGroup.headers.filter(header => {
|
||||
const recurse = columns => columns.filter(column => {
|
||||
if (column.columns) {
|
||||
return recurse(column.columns)
|
||||
}
|
||||
return column.visible
|
||||
}).length
|
||||
if (header.columns) {
|
||||
return recurse(header.columns)
|
||||
}
|
||||
return header.visible
|
||||
})
|
||||
|
||||
if (headerGroup.headers.length) {
|
||||
headerGroup.getRowProps = (props = {}) => mergeProps(
|
||||
{
|
||||
key: [`header${i}`].join('_'),
|
||||
},
|
||||
applyHooks(api.hooks.getHeaderRowProps, headerGroup),
|
||||
props
|
||||
)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}),
|
||||
[headerGroups]
|
||||
)
|
||||
|
||||
// A function that mutates and prepares page rows with methods
|
||||
api.prepareRows = rows => {
|
||||
rows.forEach((row, i) => {
|
||||
const { path } = row
|
||||
row.getRowProps = props => mergeProps(
|
||||
{ key: ['row', i].join('_') },
|
||||
applyHooks(api.hooks.getRowProps, row),
|
||||
props
|
||||
)
|
||||
|
||||
row.toggleExpanded = set => toggleExpandedByPath(path, set)
|
||||
|
||||
row.cells = row.cells.filter(cell => cell.column.visible);
|
||||
[row.groupByCell, ...row.cells].forEach(cell => {
|
||||
if (!cell) {
|
||||
return
|
||||
}
|
||||
|
||||
const { column } = cell
|
||||
|
||||
cell.getCellProps = props => {
|
||||
const columnPathStr = [i, column.id].join('_')
|
||||
return mergeProps(
|
||||
{
|
||||
key: ['cell', columnPathStr].join('_'),
|
||||
},
|
||||
applyHooks(api.hooks.getCellProps, cell),
|
||||
props
|
||||
)
|
||||
}
|
||||
|
||||
cell.render = (type, userProps = {}) => {
|
||||
if (!type) {
|
||||
throw new Error(
|
||||
'You must specify a render "type". This could be "Cell", "Header", "Filter", "Aggregated" or any other custom renderers you have set on your column.'
|
||||
)
|
||||
}
|
||||
return flexRender(column[type], {
|
||||
...api,
|
||||
...cell,
|
||||
...userProps,
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const makeHook = api => {
|
||||
api.hook = (hook, ...args) => {
|
||||
const result = hook(api, ...args) || {}
|
||||
const newApi = {
|
||||
...api,
|
||||
...result,
|
||||
}
|
||||
makeHook(newApi)
|
||||
return newApi
|
||||
}
|
||||
}
|
||||
|
||||
makeHook(api)
|
||||
|
||||
return api
|
||||
}
|
||||
|
||||
function attachApi (column, api) {
|
||||
const {
|
||||
id, canSortBy, canGroupBy, canFilter,
|
||||
} = column
|
||||
const { toggleSortByID, toggleGroupBy, setFilter } = api
|
||||
|
||||
column.render = (type, userProps = {}) => {
|
||||
if (!type) {
|
||||
throw new Error(renderErr)
|
||||
}
|
||||
return flexRender(column[type], {
|
||||
...api,
|
||||
...column,
|
||||
...userProps,
|
||||
})
|
||||
}
|
||||
|
||||
if (canSortBy) {
|
||||
column.toggleSortBy = (desc, multi) => toggleSortByID(id, desc, multi)
|
||||
}
|
||||
if (canGroupBy) {
|
||||
column.toggleGroupBy = () => toggleGroupBy(id)
|
||||
}
|
||||
if (canFilter) {
|
||||
column.setFilter = val => setFilter(id, val)
|
||||
}
|
||||
|
||||
column.getSortByToggleProps = props => mergeProps(
|
||||
{
|
||||
onClick: canSortBy
|
||||
? e => {
|
||||
e.persist()
|
||||
column.toggleSortBy(undefined, !api.disableMultiSort && e.shiftKey)
|
||||
}
|
||||
: undefined,
|
||||
style: {
|
||||
cursor: canSortBy ? 'pointer' : undefined,
|
||||
},
|
||||
title: 'Toggle SortBy',
|
||||
},
|
||||
applyHooks(api.hooks.getSortByToggleProps, column),
|
||||
props
|
||||
)
|
||||
|
||||
column.getGroupByToggleProps = props => mergeProps(
|
||||
{
|
||||
onClick: canGroupBy
|
||||
? e => {
|
||||
e.persist()
|
||||
column.toggleGroupBy()
|
||||
}
|
||||
: undefined,
|
||||
style: {
|
||||
cursor: canGroupBy ? 'pointer' : undefined,
|
||||
},
|
||||
title: 'Toggle GroupBy',
|
||||
},
|
||||
applyHooks(api.hooks.getGroupByToggleProps, column),
|
||||
props
|
||||
)
|
||||
|
||||
column.getHeaderProps = props => mergeProps(
|
||||
{
|
||||
key: ['header', column.id].join('_'),
|
||||
},
|
||||
applyHooks(api.hooks.getHeaderProps, column),
|
||||
props
|
||||
)
|
||||
}
|
||||
Executable → Regular
+160
-122
@@ -1,53 +1,114 @@
|
||||
import React from 'react'
|
||||
import classnames from 'classnames'
|
||||
//
|
||||
export default {
|
||||
get,
|
||||
set,
|
||||
takeRight,
|
||||
last,
|
||||
orderBy,
|
||||
range,
|
||||
remove,
|
||||
clone,
|
||||
getFirstDefined,
|
||||
sum,
|
||||
makeTemplateComponent,
|
||||
groupBy,
|
||||
isArray,
|
||||
splitProps,
|
||||
compactObject,
|
||||
isSortingDesc,
|
||||
normalizeComponent,
|
||||
asPx,
|
||||
}
|
||||
|
||||
export function getBy (obj, path, def) {
|
||||
function get (obj, path, def) {
|
||||
if (!path) {
|
||||
return obj
|
||||
}
|
||||
const pathObj = makePathArray(path)
|
||||
let val
|
||||
try {
|
||||
val = pathObj.reduce((cursor, pathPart) => cursor[pathPart], obj)
|
||||
val = pathObj.reduce((current, pathPart) => current[pathPart], obj)
|
||||
} catch (e) {
|
||||
// continue regardless of error
|
||||
}
|
||||
return typeof val !== 'undefined' ? val : def
|
||||
}
|
||||
|
||||
export function defaultOrderByFn (arr, funcs, dirs) {
|
||||
return [...arr].sort((rowA, rowB) => {
|
||||
function set (obj = {}, path, value) {
|
||||
const keys = makePathArray(path)
|
||||
let keyPart
|
||||
let cursor = obj
|
||||
while ((keyPart = keys.shift()) && keys.length) {
|
||||
if (!cursor[keyPart]) {
|
||||
cursor[keyPart] = {}
|
||||
}
|
||||
cursor = cursor[keyPart]
|
||||
}
|
||||
cursor[keyPart] = value
|
||||
return obj
|
||||
}
|
||||
|
||||
function takeRight (arr, n) {
|
||||
const start = n > arr.length ? 0 : arr.length - n
|
||||
return arr.slice(start)
|
||||
}
|
||||
|
||||
function last (arr) {
|
||||
return arr[arr.length - 1]
|
||||
}
|
||||
|
||||
function range (n) {
|
||||
const arr = []
|
||||
for (let i = 0; i < n; i += 1) {
|
||||
arr.push(n)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
function orderBy (arr, funcs, dirs, indexKey) {
|
||||
return arr.sort((rowA, rowB) => {
|
||||
for (let i = 0; i < funcs.length; i += 1) {
|
||||
const sortFn = funcs[i]
|
||||
const comp = funcs[i]
|
||||
const desc = dirs[i] === false || dirs[i] === 'desc'
|
||||
const sortInt = sortFn(rowA, rowB)
|
||||
if (sortInt !== 0) {
|
||||
const sortInt = comp(rowA, rowB)
|
||||
if (sortInt) {
|
||||
return desc ? -sortInt : sortInt
|
||||
}
|
||||
}
|
||||
return dirs[0] ? rowA.index - rowB.index : rowB.index - rowA.index
|
||||
// Use the row index for tie breakers
|
||||
return dirs[0] ? rowA[indexKey] - rowB[indexKey] : rowB[indexKey] - rowA[indexKey]
|
||||
})
|
||||
}
|
||||
|
||||
export function defaultSortByFn (a, b, desc) {
|
||||
// force null and undefined to the bottom
|
||||
a = a === null || a === undefined ? '' : a
|
||||
b = b === null || b === undefined ? '' : b
|
||||
// force any string values to lowercase
|
||||
a = typeof a === 'string' ? a.toLowerCase() : a
|
||||
b = typeof b === 'string' ? b.toLowerCase() : b
|
||||
// Return either 1 or -1 to indicate a sort priority
|
||||
if (a > b) {
|
||||
return 1
|
||||
}
|
||||
if (a < b) {
|
||||
return -1
|
||||
}
|
||||
// returning 0, undefined or any falsey value will defer to the next
|
||||
// sorting mechanism or eventually the columns index via the orderByFn
|
||||
return 0
|
||||
function remove (a, b) {
|
||||
return a.filter((o, i) => {
|
||||
const r = b(o)
|
||||
if (r) {
|
||||
a.splice(i, 1)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
export function getFirstDefined (...args) {
|
||||
function clone (a) {
|
||||
try {
|
||||
return JSON.parse(
|
||||
JSON.stringify(a, (key, value) => {
|
||||
if (typeof value === 'function') {
|
||||
return value.toString()
|
||||
}
|
||||
return value
|
||||
})
|
||||
)
|
||||
} catch (e) {
|
||||
return a
|
||||
}
|
||||
}
|
||||
|
||||
function getFirstDefined (...args) {
|
||||
for (let i = 0; i < args.length; i += 1) {
|
||||
if (typeof args[i] !== 'undefined') {
|
||||
return args[i]
|
||||
@@ -55,108 +116,44 @@ export function getFirstDefined (...args) {
|
||||
}
|
||||
}
|
||||
|
||||
export function defaultGroupByFn (rows, grouper) {
|
||||
return rows.reduce((prev, row, i) => {
|
||||
const resKey = typeof grouper === 'function' ? grouper(row.values, i) : row.values[grouper]
|
||||
prev[resKey] = Array.isArray(prev[resKey]) ? prev[resKey] : []
|
||||
prev[resKey].push(row)
|
||||
return prev
|
||||
function sum (arr) {
|
||||
return arr.reduce((a, b) => a + b, 0)
|
||||
}
|
||||
|
||||
function makeTemplateComponent (compClass, displayName) {
|
||||
if (!displayName) {
|
||||
throw new Error('No displayName found for template component:', compClass)
|
||||
}
|
||||
const cmp = ({ children, className, ...rest }) => (
|
||||
<div className={classnames(compClass, className)} {...rest}>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
cmp.displayName = displayName
|
||||
return cmp
|
||||
}
|
||||
|
||||
function groupBy (xs, key) {
|
||||
return xs.reduce((rv, x, i) => {
|
||||
const resKey = typeof key === 'function' ? key(x, i) : x[key]
|
||||
rv[resKey] = isArray(rv[resKey]) ? rv[resKey] : []
|
||||
rv[resKey].push(x)
|
||||
return rv
|
||||
}, {})
|
||||
}
|
||||
|
||||
export function defaultFilterFn (row, id, value, column) {
|
||||
return row.values[id] !== undefined
|
||||
? String(row.values[id])
|
||||
.toLowerCase()
|
||||
.includes(String(value).toLowerCase())
|
||||
: true
|
||||
function asPx (value) {
|
||||
value = Number(value)
|
||||
return Number.isNaN(value) ? null : `${value}px`
|
||||
}
|
||||
|
||||
export function setBy (obj = {}, path, value) {
|
||||
const recurse = (obj, depth = 0) => {
|
||||
const key = path[depth]
|
||||
const target = typeof obj[key] !== 'object' ? {} : obj[key]
|
||||
const subValue = depth === path.length - 1 ? value : recurse(target, depth + 1)
|
||||
return {
|
||||
...obj,
|
||||
[key]: subValue,
|
||||
}
|
||||
}
|
||||
|
||||
return recurse(obj)
|
||||
function isArray (a) {
|
||||
return Array.isArray(a)
|
||||
}
|
||||
|
||||
export function getElementDimensions (element) {
|
||||
const rect = element.getBoundingClientRect()
|
||||
const style = window.getComputedStyle(element)
|
||||
const margins = {
|
||||
left: parseInt(style.marginLeft),
|
||||
right: parseInt(style.marginRight),
|
||||
}
|
||||
const padding = {
|
||||
left: parseInt(style.paddingLeft),
|
||||
right: parseInt(style.paddingRight),
|
||||
}
|
||||
return {
|
||||
left: Math.ceil(rect.left),
|
||||
width: Math.ceil(rect.width),
|
||||
outerWidth: Math.ceil(rect.width + margins.left + margins.right + padding.left + padding.right),
|
||||
marginLeft: margins.left,
|
||||
marginRight: margins.right,
|
||||
paddingLeft: padding.left,
|
||||
paddingRight: padding.right,
|
||||
scrollWidth: element.scrollWidth,
|
||||
}
|
||||
}
|
||||
|
||||
export function flexRender (Comp, props) {
|
||||
if (typeof Comp === 'function') {
|
||||
return Object.getPrototypeOf(Comp).isReactComponent ? <Comp {...props} /> : Comp(props)
|
||||
}
|
||||
return Comp
|
||||
}
|
||||
|
||||
export function findExpandedDepth (obj, depth = 1) {
|
||||
return Object.values(obj).reduce((prev, curr) => {
|
||||
if (typeof curr === 'object') {
|
||||
return Math.max(prev, findExpandedDepth(curr, depth + 1))
|
||||
}
|
||||
return depth
|
||||
}, 0)
|
||||
}
|
||||
|
||||
export const mergeProps = (...groups) => {
|
||||
let props = {}
|
||||
groups.forEach(({ style = {}, className, ...rest } = {}) => {
|
||||
props = {
|
||||
...props,
|
||||
...rest,
|
||||
style: {
|
||||
...(props.style || {}),
|
||||
...style,
|
||||
},
|
||||
className: [props.className, className].filter(Boolean).join(' '),
|
||||
}
|
||||
})
|
||||
return props
|
||||
}
|
||||
|
||||
export const applyHooks = (hooks, ...args) =>
|
||||
hooks.reduce((prev, next) => mergeProps(prev, next(...args)), {})
|
||||
|
||||
export const warnUnknownProps = props => {
|
||||
if (Object.keys(props).length) {
|
||||
throw new Error(
|
||||
`Unknown options passed to useReactTable:
|
||||
|
||||
${JSON.stringify(props, null, 2)}`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export function sum (arr) {
|
||||
return arr.reduce((prev, curr) => prev + curr, 0)
|
||||
}
|
||||
// ########################################################################
|
||||
// Non-exported Helpers
|
||||
// ########################################################################
|
||||
|
||||
function makePathArray (obj) {
|
||||
return flattenDeep(obj)
|
||||
@@ -167,7 +164,7 @@ function makePathArray (obj) {
|
||||
}
|
||||
|
||||
function flattenDeep (arr, newArr = []) {
|
||||
if (!Array.isArray(arr)) {
|
||||
if (!isArray(arr)) {
|
||||
newArr.push(arr)
|
||||
} else {
|
||||
for (let i = 0; i < arr.length; i += 1) {
|
||||
@@ -176,3 +173,44 @@ function flattenDeep (arr, newArr = []) {
|
||||
}
|
||||
return newArr
|
||||
}
|
||||
|
||||
function splitProps ({ className, style, ...rest }) {
|
||||
return {
|
||||
className,
|
||||
style,
|
||||
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
|
||||
})
|
||||
}
|
||||
return newObj
|
||||
}
|
||||
|
||||
function isSortingDesc (d) {
|
||||
return !!(d.sort === 'desc' || d.desc === true || d.asc === false)
|
||||
}
|
||||
|
||||
function normalizeComponent (Comp, params = {}, fallback = Comp) {
|
||||
return typeof Comp === 'function' ? (
|
||||
Object.getPrototypeOf(Comp).isReactComponent ? (
|
||||
<Comp {...params} />
|
||||
) : (
|
||||
Comp(params)
|
||||
)
|
||||
) : (
|
||||
fallback
|
||||
)
|
||||
}
|
||||
|
||||
@@ -144,7 +144,13 @@ ansi-styles@^2.1.0, ansi-styles@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
|
||||
|
||||
ansi-styles@^3.2.0, ansi-styles@^3.2.1:
|
||||
ansi-styles@^3.2.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.0.tgz#c159b8d5be0f9e5a6f346dab94f16ce022161b88"
|
||||
dependencies:
|
||||
color-convert "^1.9.0"
|
||||
|
||||
ansi-styles@^3.2.1:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
|
||||
dependencies:
|
||||
@@ -383,13 +389,13 @@ babel-generator@^6.22.0:
|
||||
lodash "^4.2.0"
|
||||
source-map "^0.5.0"
|
||||
|
||||
babel-helper-builder-binary-assignment-operator-visitor@^6.24.1:
|
||||
version "6.24.1"
|
||||
resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664"
|
||||
babel-helper-builder-binary-assignment-operator-visitor@^6.22.0:
|
||||
version "6.22.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.22.0.tgz#29df56be144d81bdeac08262bfa41d2c5e91cdcd"
|
||||
dependencies:
|
||||
babel-helper-explode-assignable-expression "^6.24.1"
|
||||
babel-helper-explode-assignable-expression "^6.22.0"
|
||||
babel-runtime "^6.22.0"
|
||||
babel-types "^6.24.1"
|
||||
babel-types "^6.22.0"
|
||||
|
||||
babel-helper-builder-react-jsx@^6.24.1:
|
||||
version "6.26.0"
|
||||
@@ -417,13 +423,23 @@ babel-helper-define-map@^6.24.1:
|
||||
babel-types "^6.26.0"
|
||||
lodash "^4.17.4"
|
||||
|
||||
babel-helper-explode-assignable-expression@^6.24.1:
|
||||
version "6.24.1"
|
||||
resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa"
|
||||
babel-helper-explode-assignable-expression@^6.22.0:
|
||||
version "6.22.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.22.0.tgz#c97bf76eed3e0bae4048121f2b9dae1a4e7d0478"
|
||||
dependencies:
|
||||
babel-runtime "^6.22.0"
|
||||
babel-traverse "^6.24.1"
|
||||
babel-types "^6.24.1"
|
||||
babel-traverse "^6.22.0"
|
||||
babel-types "^6.22.0"
|
||||
|
||||
babel-helper-function-name@^6.22.0:
|
||||
version "6.22.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.22.0.tgz#51f1bdc4bb89b15f57a9b249f33d742816dcbefc"
|
||||
dependencies:
|
||||
babel-helper-get-function-arity "^6.22.0"
|
||||
babel-runtime "^6.22.0"
|
||||
babel-template "^6.22.0"
|
||||
babel-traverse "^6.22.0"
|
||||
babel-types "^6.22.0"
|
||||
|
||||
babel-helper-function-name@^6.24.1:
|
||||
version "6.24.1"
|
||||
@@ -435,6 +451,13 @@ babel-helper-function-name@^6.24.1:
|
||||
babel-traverse "^6.24.1"
|
||||
babel-types "^6.24.1"
|
||||
|
||||
babel-helper-get-function-arity@^6.22.0:
|
||||
version "6.22.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.22.0.tgz#0beb464ad69dc7347410ac6ade9f03a50634f5ce"
|
||||
dependencies:
|
||||
babel-runtime "^6.22.0"
|
||||
babel-types "^6.22.0"
|
||||
|
||||
babel-helper-get-function-arity@^6.24.1:
|
||||
version "6.24.1"
|
||||
resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d"
|
||||
@@ -464,15 +487,15 @@ babel-helper-regex@^6.24.1:
|
||||
babel-types "^6.26.0"
|
||||
lodash "^4.17.4"
|
||||
|
||||
babel-helper-remap-async-to-generator@^6.24.1:
|
||||
version "6.24.1"
|
||||
resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b"
|
||||
babel-helper-remap-async-to-generator@^6.22.0:
|
||||
version "6.22.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.22.0.tgz#2186ae73278ed03b8b15ced089609da981053383"
|
||||
dependencies:
|
||||
babel-helper-function-name "^6.24.1"
|
||||
babel-helper-function-name "^6.22.0"
|
||||
babel-runtime "^6.22.0"
|
||||
babel-template "^6.24.1"
|
||||
babel-traverse "^6.24.1"
|
||||
babel-types "^6.24.1"
|
||||
babel-template "^6.22.0"
|
||||
babel-traverse "^6.22.0"
|
||||
babel-types "^6.22.0"
|
||||
|
||||
babel-helper-replace-supers@^6.24.1:
|
||||
version "6.24.1"
|
||||
@@ -492,7 +515,13 @@ babel-helpers@^6.22.0:
|
||||
babel-runtime "^6.22.0"
|
||||
babel-template "^6.22.0"
|
||||
|
||||
babel-messages@^6.22.0, babel-messages@^6.23.0:
|
||||
babel-messages@^6.22.0:
|
||||
version "6.22.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.22.0.tgz#36066a214f1217e4ed4164867669ecb39e3ea575"
|
||||
dependencies:
|
||||
babel-runtime "^6.22.0"
|
||||
|
||||
babel-messages@^6.23.0:
|
||||
version "6.23.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e"
|
||||
dependencies:
|
||||
@@ -539,10 +568,10 @@ babel-plugin-syntax-trailing-function-commas@^6.22.0:
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3"
|
||||
|
||||
babel-plugin-transform-async-to-generator@^6.22.0:
|
||||
version "6.24.1"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761"
|
||||
version "6.22.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.22.0.tgz#194b6938ec195ad36efc4c33a971acf00d8cd35e"
|
||||
dependencies:
|
||||
babel-helper-remap-async-to-generator "^6.24.1"
|
||||
babel-helper-remap-async-to-generator "^6.22.0"
|
||||
babel-plugin-syntax-async-functions "^6.8.0"
|
||||
babel-runtime "^6.22.0"
|
||||
|
||||
@@ -631,7 +660,15 @@ babel-plugin-transform-es2015-literals@^6.22.0:
|
||||
dependencies:
|
||||
babel-runtime "^6.22.0"
|
||||
|
||||
babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.1:
|
||||
babel-plugin-transform-es2015-modules-amd@^6.22.0:
|
||||
version "6.22.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.22.0.tgz#bf69cd34889a41c33d90dfb740e0091ccff52f21"
|
||||
dependencies:
|
||||
babel-plugin-transform-es2015-modules-commonjs "^6.22.0"
|
||||
babel-runtime "^6.22.0"
|
||||
babel-template "^6.22.0"
|
||||
|
||||
babel-plugin-transform-es2015-modules-amd@^6.24.1:
|
||||
version "6.24.1"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154"
|
||||
dependencies:
|
||||
@@ -639,9 +676,18 @@ babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015
|
||||
babel-runtime "^6.22.0"
|
||||
babel-template "^6.24.1"
|
||||
|
||||
babel-plugin-transform-es2015-modules-commonjs@^6.22.0:
|
||||
version "6.22.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.22.0.tgz#6ca04e22b8e214fb50169730657e7a07dc941145"
|
||||
dependencies:
|
||||
babel-plugin-transform-strict-mode "^6.22.0"
|
||||
babel-runtime "^6.22.0"
|
||||
babel-template "^6.22.0"
|
||||
babel-types "^6.22.0"
|
||||
|
||||
babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1:
|
||||
version "6.26.2"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz#58a793863a9e7ca870bdc5a881117ffac27db6f3"
|
||||
version "6.26.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz#0d8394029b7dc6abe1a97ef181e00758dd2e5d8a"
|
||||
dependencies:
|
||||
babel-plugin-transform-strict-mode "^6.24.1"
|
||||
babel-runtime "^6.26.0"
|
||||
@@ -724,10 +770,10 @@ babel-plugin-transform-es2015-unicode-regex@^6.22.0:
|
||||
regexpu-core "^2.0.0"
|
||||
|
||||
babel-plugin-transform-exponentiation-operator@^6.22.0:
|
||||
version "6.24.1"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e"
|
||||
version "6.22.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.22.0.tgz#d57c8335281918e54ef053118ce6eb108468084d"
|
||||
dependencies:
|
||||
babel-helper-builder-binary-assignment-operator-visitor "^6.24.1"
|
||||
babel-helper-builder-binary-assignment-operator-visitor "^6.22.0"
|
||||
babel-plugin-syntax-exponentiation-operator "^6.8.0"
|
||||
babel-runtime "^6.22.0"
|
||||
|
||||
@@ -779,6 +825,13 @@ babel-plugin-transform-regenerator@^6.22.0:
|
||||
dependencies:
|
||||
regenerator-transform "^0.10.0"
|
||||
|
||||
babel-plugin-transform-strict-mode@^6.22.0:
|
||||
version "6.22.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.22.0.tgz#e008df01340fdc87e959da65991b7e05970c8c7c"
|
||||
dependencies:
|
||||
babel-runtime "^6.22.0"
|
||||
babel-types "^6.22.0"
|
||||
|
||||
babel-plugin-transform-strict-mode@^6.24.1:
|
||||
version "6.24.1"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758"
|
||||
@@ -795,8 +848,8 @@ babel-polyfill@^6.9.0:
|
||||
regenerator-runtime "^0.10.0"
|
||||
|
||||
babel-preset-env@^1.6.1:
|
||||
version "1.7.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.7.0.tgz#dea79fa4ebeb883cd35dab07e260c1c9c04df77a"
|
||||
version "1.6.1"
|
||||
resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.6.1.tgz#a18b564cc9b9afdf4aae57ae3c1b0d99188e6f48"
|
||||
dependencies:
|
||||
babel-plugin-check-es2015-constants "^6.22.0"
|
||||
babel-plugin-syntax-trailing-function-commas "^6.22.0"
|
||||
@@ -825,7 +878,7 @@ babel-preset-env@^1.6.1:
|
||||
babel-plugin-transform-es2015-unicode-regex "^6.22.0"
|
||||
babel-plugin-transform-exponentiation-operator "^6.22.0"
|
||||
babel-plugin-transform-regenerator "^6.22.0"
|
||||
browserslist "^3.2.6"
|
||||
browserslist "^2.1.2"
|
||||
invariant "^2.2.2"
|
||||
semver "^5.3.0"
|
||||
|
||||
@@ -858,21 +911,31 @@ babel-register@^6.14.0, babel-register@^6.22.0:
|
||||
mkdirp "^0.5.1"
|
||||
source-map-support "^0.4.2"
|
||||
|
||||
babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0:
|
||||
version "6.26.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
|
||||
dependencies:
|
||||
core-js "^2.4.0"
|
||||
regenerator-runtime "^0.11.0"
|
||||
|
||||
babel-runtime@^6.6.1, babel-runtime@^6.9.0:
|
||||
babel-runtime@^6.18.0, babel-runtime@^6.6.1, babel-runtime@^6.9.0:
|
||||
version "6.22.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.22.0.tgz#1cf8b4ac67c77a4ddb0db2ae1f74de52ac4ca611"
|
||||
dependencies:
|
||||
core-js "^2.4.0"
|
||||
regenerator-runtime "^0.10.0"
|
||||
|
||||
babel-template@^6.22.0, babel-template@^6.24.1, babel-template@^6.26.0:
|
||||
babel-runtime@^6.22.0, babel-runtime@^6.26.0:
|
||||
version "6.26.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
|
||||
dependencies:
|
||||
core-js "^2.4.0"
|
||||
regenerator-runtime "^0.11.0"
|
||||
|
||||
babel-template@^6.22.0:
|
||||
version "6.22.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.22.0.tgz#403d110905a4626b317a2a1fcb8f3b73204b2edb"
|
||||
dependencies:
|
||||
babel-runtime "^6.22.0"
|
||||
babel-traverse "^6.22.0"
|
||||
babel-types "^6.22.0"
|
||||
babylon "^6.11.0"
|
||||
lodash "^4.2.0"
|
||||
|
||||
babel-template@^6.24.1, babel-template@^6.26.0:
|
||||
version "6.26.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02"
|
||||
dependencies:
|
||||
@@ -882,7 +945,7 @@ babel-template@^6.22.0, babel-template@^6.24.1, babel-template@^6.26.0:
|
||||
babylon "^6.18.0"
|
||||
lodash "^4.17.4"
|
||||
|
||||
babel-traverse@^6.0.20, babel-traverse@^6.22.1:
|
||||
babel-traverse@^6.0.20, babel-traverse@^6.22.0, babel-traverse@^6.22.1:
|
||||
version "6.22.1"
|
||||
resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.22.1.tgz#3b95cd6b7427d6f1f757704908f2fc9748a5f59f"
|
||||
dependencies:
|
||||
@@ -910,7 +973,7 @@ babel-traverse@^6.24.1, babel-traverse@^6.26.0:
|
||||
invariant "^2.2.2"
|
||||
lodash "^4.17.4"
|
||||
|
||||
babel-types@^6.0.19:
|
||||
babel-types@^6.0.19, babel-types@^6.19.0, babel-types@^6.22.0:
|
||||
version "6.22.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.22.0.tgz#2a447e8d0ea25d2512409e4175479fd78cc8b1db"
|
||||
dependencies:
|
||||
@@ -919,7 +982,7 @@ babel-types@^6.0.19:
|
||||
lodash "^4.2.0"
|
||||
to-fast-properties "^1.0.1"
|
||||
|
||||
babel-types@^6.19.0, babel-types@^6.22.0, babel-types@^6.24.1, babel-types@^6.26.0:
|
||||
babel-types@^6.24.1, babel-types@^6.26.0:
|
||||
version "6.26.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497"
|
||||
dependencies:
|
||||
@@ -932,11 +995,11 @@ babylon@7.0.0-beta.44:
|
||||
version "7.0.0-beta.44"
|
||||
resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.44.tgz#89159e15e6e30c5096e22d738d8c0af8a0e8ca1d"
|
||||
|
||||
babylon@^6.0.18:
|
||||
babylon@^6.0.18, babylon@^6.11.0, babylon@^6.15.0:
|
||||
version "6.15.0"
|
||||
resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.15.0.tgz#ba65cfa1a80e1759b0e89fb562e27dccae70348e"
|
||||
|
||||
babylon@^6.11.0, babylon@^6.15.0, babylon@^6.18.0:
|
||||
babylon@^6.18.0:
|
||||
version "6.18.0"
|
||||
resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3"
|
||||
|
||||
@@ -1007,12 +1070,12 @@ browserslist@^1.7.6:
|
||||
caniuse-db "^1.0.30000639"
|
||||
electron-to-chromium "^1.2.7"
|
||||
|
||||
browserslist@^3.2.6:
|
||||
version "3.2.7"
|
||||
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-3.2.7.tgz#aa488634d320b55e88bab0256184dbbcca1e6de9"
|
||||
browserslist@^2.1.2:
|
||||
version "2.11.3"
|
||||
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-2.11.3.tgz#fe36167aed1bbcde4827ebfe71347a2cc70b99b2"
|
||||
dependencies:
|
||||
caniuse-lite "^1.0.30000835"
|
||||
electron-to-chromium "^1.3.45"
|
||||
caniuse-lite "^1.0.30000792"
|
||||
electron-to-chromium "^1.3.30"
|
||||
|
||||
buffer-from@^1.0.0:
|
||||
version "1.0.0"
|
||||
@@ -1055,9 +1118,9 @@ caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639:
|
||||
version "1.0.30000746"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000746.tgz#501098c66f5fbbf634c02f25508b05e8809910f4"
|
||||
|
||||
caniuse-lite@^1.0.30000835:
|
||||
version "1.0.30000843"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000843.tgz#4fdec258dc641c385744cdd49d23c5459c3d4411"
|
||||
caniuse-lite@^1.0.30000792:
|
||||
version "1.0.30000803"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000803.tgz#9939c37149d38d5f4540430490d240c03106a0f5"
|
||||
|
||||
caseless@~0.11.0:
|
||||
version "0.11.0"
|
||||
@@ -1087,7 +1150,7 @@ chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3:
|
||||
strip-ansi "^3.0.0"
|
||||
supports-color "^2.0.0"
|
||||
|
||||
chalk@^2.0.0:
|
||||
chalk@^2.0.0, chalk@^2.1.0:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.0.tgz#a060a297a6b57e15b61ca63ce84995daa0fe6e52"
|
||||
dependencies:
|
||||
@@ -1095,14 +1158,6 @@ chalk@^2.0.0:
|
||||
escape-string-regexp "^1.0.5"
|
||||
supports-color "^5.3.0"
|
||||
|
||||
chalk@^2.1.0:
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e"
|
||||
dependencies:
|
||||
ansi-styles "^3.2.1"
|
||||
escape-string-regexp "^1.0.5"
|
||||
supports-color "^5.3.0"
|
||||
|
||||
chardet@^0.4.0:
|
||||
version "0.4.2"
|
||||
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2"
|
||||
@@ -1237,19 +1292,20 @@ core-js@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
|
||||
|
||||
core-js@^2.4.0:
|
||||
version "2.5.6"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.6.tgz#0fe6d45bf3cac3ac364a9d72de7576f4eb221b9d"
|
||||
version "2.5.5"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.5.tgz#b14dde936c640c0579a6b50cabcc132dd6127e3b"
|
||||
|
||||
core-util-is@1.0.2, core-util-is@~1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
||||
|
||||
cross-env@^5.1.4:
|
||||
version "5.1.4"
|
||||
resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-5.1.4.tgz#f61c14291f7cc653bb86457002ea80a04699d022"
|
||||
create-react-class@^15.6.0:
|
||||
version "15.6.2"
|
||||
resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.6.2.tgz#cf1ed15f12aad7f14ef5f2dfe05e6c42f91ef02a"
|
||||
dependencies:
|
||||
cross-spawn "^5.1.0"
|
||||
is-windows "^1.0.0"
|
||||
fbjs "^0.8.9"
|
||||
loose-envify "^1.3.1"
|
||||
object-assign "^4.1.1"
|
||||
|
||||
cross-spawn@^5.1.0, cross-spawn@~5.1.0:
|
||||
version "5.1.0"
|
||||
@@ -1259,16 +1315,6 @@ cross-spawn@^5.1.0, cross-spawn@~5.1.0:
|
||||
shebang-command "^1.2.0"
|
||||
which "^1.2.9"
|
||||
|
||||
cross-spawn@^6.0.4:
|
||||
version "6.0.5"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
|
||||
dependencies:
|
||||
nice-try "^1.0.4"
|
||||
path-key "^2.0.1"
|
||||
semver "^5.5.0"
|
||||
shebang-command "^1.2.0"
|
||||
which "^1.2.9"
|
||||
|
||||
cryptiles@2.x.x:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8"
|
||||
@@ -1305,7 +1351,7 @@ debug-log@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/debug-log/-/debug-log-1.0.1.tgz#2307632d4c04382b8df8a32f70b895046d52745f"
|
||||
|
||||
debug@*:
|
||||
debug@*, debug@^2.2.0:
|
||||
version "2.6.8"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc"
|
||||
dependencies:
|
||||
@@ -1317,7 +1363,7 @@ debug@2.2.0:
|
||||
dependencies:
|
||||
ms "0.7.1"
|
||||
|
||||
debug@^2.1.1, debug@^2.2.0, debug@^2.6.8, debug@^2.6.9:
|
||||
debug@^2.1.1, debug@^2.6.8, debug@^2.6.9:
|
||||
version "2.6.9"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
||||
dependencies:
|
||||
@@ -1420,9 +1466,9 @@ electron-to-chromium@^1.2.7:
|
||||
version "1.3.26"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.26.tgz#996427294861a74d9c7c82b9260ea301e8c02d66"
|
||||
|
||||
electron-to-chromium@^1.3.45:
|
||||
version "1.3.47"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.47.tgz#764e887ca9104d01a0ac8eabee7dfc0e2ce14104"
|
||||
electron-to-chromium@^1.3.30:
|
||||
version "1.3.32"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.32.tgz#11d0684c0840e003c4be8928f8ac5f35dbc2b4e6"
|
||||
|
||||
emoji-regex@^6.1.0:
|
||||
version "6.5.1"
|
||||
@@ -1440,7 +1486,16 @@ error-ex@^1.2.0, error-ex@^1.3.1:
|
||||
dependencies:
|
||||
is-arrayish "^0.2.1"
|
||||
|
||||
es-abstract@^1.4.3, es-abstract@^1.7.0:
|
||||
es-abstract@^1.4.3:
|
||||
version "1.7.0"
|
||||
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.7.0.tgz#dfade774e01bfcd97f96180298c449c8623fb94c"
|
||||
dependencies:
|
||||
es-to-primitive "^1.1.1"
|
||||
function-bind "^1.1.0"
|
||||
is-callable "^1.1.3"
|
||||
is-regex "^1.0.3"
|
||||
|
||||
es-abstract@^1.7.0:
|
||||
version "1.11.0"
|
||||
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.11.0.tgz#cce87d518f0496893b1a30cd8461835535480681"
|
||||
dependencies:
|
||||
@@ -1595,22 +1650,7 @@ eslint-plugin-class-property@^1.0.6:
|
||||
dependencies:
|
||||
eslint "^3.19.0"
|
||||
|
||||
eslint-plugin-import@^2.7.0:
|
||||
version "2.12.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.12.0.tgz#dad31781292d6664b25317fd049d2e2b2f02205d"
|
||||
dependencies:
|
||||
contains-path "^0.1.0"
|
||||
debug "^2.6.8"
|
||||
doctrine "1.5.0"
|
||||
eslint-import-resolver-node "^0.3.1"
|
||||
eslint-module-utils "^2.2.0"
|
||||
has "^1.0.1"
|
||||
lodash "^4.17.4"
|
||||
minimatch "^3.0.3"
|
||||
read-pkg-up "^2.0.0"
|
||||
resolve "^1.6.0"
|
||||
|
||||
eslint-plugin-import@^2.9.0:
|
||||
eslint-plugin-import@^2.7.0, eslint-plugin-import@^2.9.0:
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.11.0.tgz#15aeea37a67499d848e8e981806d4627b5503816"
|
||||
dependencies:
|
||||
@@ -1666,16 +1706,7 @@ eslint-plugin-promise@~3.5.0:
|
||||
version "3.5.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-3.5.0.tgz#78fbb6ffe047201627569e85a6c5373af2a68fca"
|
||||
|
||||
eslint-plugin-react@^7.4.0:
|
||||
version "7.8.2"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.8.2.tgz#e95c9c47fece55d2303d1a67c9d01b930b88a51d"
|
||||
dependencies:
|
||||
doctrine "^2.0.2"
|
||||
has "^1.0.1"
|
||||
jsx-ast-utils "^2.0.1"
|
||||
prop-types "^15.6.0"
|
||||
|
||||
eslint-plugin-react@^7.7.0:
|
||||
eslint-plugin-react@^7.4.0, eslint-plugin-react@^7.7.0:
|
||||
version "7.7.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.7.0.tgz#f606c719dbd8a1a2b3d25c16299813878cca0160"
|
||||
dependencies:
|
||||
@@ -1848,7 +1879,7 @@ event-emitter@~0.3.5:
|
||||
|
||||
event-stream@~3.3.0:
|
||||
version "3.3.4"
|
||||
resolved "http://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571"
|
||||
resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571"
|
||||
dependencies:
|
||||
duplexer "~0.1.1"
|
||||
from "~0"
|
||||
@@ -2032,8 +2063,8 @@ form-data@~2.1.1:
|
||||
mime-types "^2.1.12"
|
||||
|
||||
from@~0:
|
||||
version "0.1.7"
|
||||
resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe"
|
||||
version "0.1.3"
|
||||
resolved "https://registry.yarnpkg.com/from/-/from-0.1.3.tgz#ef63ac2062ac32acf7862e0d40b44b896f22f3bc"
|
||||
|
||||
fs-readdir-recursive@^0.1.0:
|
||||
version "0.1.2"
|
||||
@@ -2373,7 +2404,13 @@ interpret@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614"
|
||||
|
||||
invariant@^2.2.0, invariant@^2.2.2:
|
||||
invariant@^2.2.0:
|
||||
version "2.2.2"
|
||||
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360"
|
||||
dependencies:
|
||||
loose-envify "^1.0.0"
|
||||
|
||||
invariant@^2.2.2:
|
||||
version "2.2.4"
|
||||
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
|
||||
dependencies:
|
||||
@@ -2513,7 +2550,7 @@ is-property@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84"
|
||||
|
||||
is-regex@^1.0.4:
|
||||
is-regex@^1.0.3, is-regex@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491"
|
||||
dependencies:
|
||||
@@ -2539,10 +2576,6 @@ is-utf8@^0.2.0:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
|
||||
|
||||
is-windows@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
|
||||
|
||||
isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
|
||||
@@ -2600,8 +2633,8 @@ jsesc@~0.5.0:
|
||||
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
|
||||
|
||||
json-parse-better-errors@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.1.tgz#50183cd1b2d25275de069e9e71b467ac9eab973a"
|
||||
|
||||
json-schema-traverse@^0.3.0:
|
||||
version "0.3.1"
|
||||
@@ -2736,13 +2769,13 @@ lodash.pickby@^4.0.0:
|
||||
version "4.6.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.pickby/-/lodash.pickby-4.6.0.tgz#7dea21d8c18d7703a27c704c15d3b84a67e33aff"
|
||||
|
||||
lodash@^4.0.0, lodash@^4.3.0:
|
||||
lodash@^4.0.0, lodash@^4.17.4, lodash@^4.3.0:
|
||||
version "4.17.5"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511"
|
||||
|
||||
lodash@^4.17.4, lodash@^4.2.0:
|
||||
version "4.17.10"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7"
|
||||
lodash@^4.2.0:
|
||||
version "4.17.4"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
|
||||
|
||||
log-symbols@^1.0.2:
|
||||
version "1.0.2"
|
||||
@@ -2764,8 +2797,8 @@ loud-rejection@^1.0.0:
|
||||
signal-exit "^3.0.0"
|
||||
|
||||
lru-cache@^4.0.1:
|
||||
version "4.1.3"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c"
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.2.tgz#45234b2e6e2f2b33da125624c4664929a0224c3f"
|
||||
dependencies:
|
||||
pseudomap "^1.0.2"
|
||||
yallist "^2.1.2"
|
||||
@@ -2900,10 +2933,6 @@ next-tick@1:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c"
|
||||
|
||||
nice-try@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4"
|
||||
|
||||
node-fetch@^1.0.1:
|
||||
version "1.7.3"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef"
|
||||
@@ -2963,12 +2992,12 @@ normalize-range@^0.1.2:
|
||||
resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942"
|
||||
|
||||
npm-run-all@^4.1.2:
|
||||
version "4.1.3"
|
||||
resolved "https://registry.yarnpkg.com/npm-run-all/-/npm-run-all-4.1.3.tgz#49f15b55a66bb4101664ce270cb18e7103f8f185"
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/npm-run-all/-/npm-run-all-4.1.2.tgz#90d62d078792d20669139e718621186656cea056"
|
||||
dependencies:
|
||||
ansi-styles "^3.2.0"
|
||||
chalk "^2.1.0"
|
||||
cross-spawn "^6.0.4"
|
||||
cross-spawn "^5.1.0"
|
||||
memorystream "^0.3.1"
|
||||
minimatch "^3.0.4"
|
||||
ps-tree "^1.1.0"
|
||||
@@ -3146,10 +3175,6 @@ path-is-inside@^1.0.1, path-is-inside@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
|
||||
|
||||
path-key@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
|
||||
|
||||
path-parse@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1"
|
||||
@@ -3282,8 +3307,8 @@ preserve@^0.2.0:
|
||||
resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
|
||||
|
||||
private@^0.1.6:
|
||||
version "0.1.8"
|
||||
resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff"
|
||||
version "0.1.6"
|
||||
resolved "https://registry.yarnpkg.com/private/-/private-0.1.6.tgz#55c6a976d0f9bafb9924851350fe47b9b5fbb7c1"
|
||||
|
||||
process-nextick-args@~2.0.0:
|
||||
version "2.0.0"
|
||||
@@ -3303,14 +3328,7 @@ promise@^7.1.1:
|
||||
dependencies:
|
||||
asap "~2.0.3"
|
||||
|
||||
prop-types@^15.5.8:
|
||||
version "15.5.10"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.10.tgz#2797dfc3126182e3a95e3dfbb2e893ddd7456154"
|
||||
dependencies:
|
||||
fbjs "^0.8.9"
|
||||
loose-envify "^1.3.1"
|
||||
|
||||
prop-types@^15.6.0:
|
||||
prop-types@^15.5.10, prop-types@^15.6.0:
|
||||
version "15.6.1"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.1.tgz#36644453564255ddda391191fb3a125cbdf654ca"
|
||||
dependencies:
|
||||
@@ -3318,6 +3336,13 @@ prop-types@^15.6.0:
|
||||
loose-envify "^1.3.1"
|
||||
object-assign "^4.1.1"
|
||||
|
||||
prop-types@^15.5.8:
|
||||
version "15.5.10"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.10.tgz#2797dfc3126182e3a95e3dfbb2e893ddd7456154"
|
||||
dependencies:
|
||||
fbjs "^0.8.9"
|
||||
loose-envify "^1.3.1"
|
||||
|
||||
ps-tree@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/ps-tree/-/ps-tree-1.1.0.tgz#b421b24140d6203f1ed3c76996b4427b08e8c014"
|
||||
@@ -3369,14 +3394,14 @@ react-base16-styling@^0.5.1:
|
||||
lodash.flow "^3.3.0"
|
||||
pure-color "^1.2.0"
|
||||
|
||||
react-dom@^16.3.2:
|
||||
version "16.4.1"
|
||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.4.1.tgz#7f8b0223b3a5fbe205116c56deb85de32685dad6"
|
||||
react-dom@^15.4.2:
|
||||
version "15.6.2"
|
||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.6.2.tgz#41cfadf693b757faf2708443a1d1fd5a02bef730"
|
||||
dependencies:
|
||||
fbjs "^0.8.16"
|
||||
fbjs "^0.8.9"
|
||||
loose-envify "^1.1.0"
|
||||
object-assign "^4.1.1"
|
||||
prop-types "^15.6.0"
|
||||
object-assign "^4.1.0"
|
||||
prop-types "^15.5.10"
|
||||
|
||||
react-json-tree@^0.10.9:
|
||||
version "0.10.9"
|
||||
@@ -3386,14 +3411,15 @@ react-json-tree@^0.10.9:
|
||||
prop-types "^15.5.8"
|
||||
react-base16-styling "^0.5.1"
|
||||
|
||||
react@^16.3.2:
|
||||
version "16.3.2"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-16.3.2.tgz#fdc8420398533a1e58872f59091b272ce2f91ea9"
|
||||
react@^15.4.2:
|
||||
version "15.6.2"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-15.6.2.tgz#dba0434ab439cfe82f108f0f511663908179aa72"
|
||||
dependencies:
|
||||
fbjs "^0.8.16"
|
||||
create-react-class "^15.6.0"
|
||||
fbjs "^0.8.9"
|
||||
loose-envify "^1.1.0"
|
||||
object-assign "^4.1.1"
|
||||
prop-types "^15.6.0"
|
||||
object-assign "^4.1.0"
|
||||
prop-types "^15.5.10"
|
||||
|
||||
read-file-stdin@^0.2.0:
|
||||
version "0.2.1"
|
||||
@@ -3482,8 +3508,8 @@ redent@^1.0.0:
|
||||
strip-indent "^1.0.1"
|
||||
|
||||
regenerate@^1.2.1:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11"
|
||||
version "1.3.2"
|
||||
resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260"
|
||||
|
||||
regenerator-runtime@^0.10.0:
|
||||
version "0.10.5"
|
||||
@@ -3649,8 +3675,8 @@ rimraf@2, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.6.1:
|
||||
glob "^7.0.5"
|
||||
|
||||
rollup-plugin-babel@^3.0.3:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/rollup-plugin-babel/-/rollup-plugin-babel-3.0.4.tgz#41b3e762fe64450dd61da3105a2cf7ad76be4edc"
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/rollup-plugin-babel/-/rollup-plugin-babel-3.0.3.tgz#63adedc863130327512a4a9006efc2241c5b7c15"
|
||||
dependencies:
|
||||
rollup-pluginutils "^1.5.0"
|
||||
|
||||
@@ -3756,7 +3782,7 @@ semver-truncate@^1.0.0:
|
||||
dependencies:
|
||||
semver "^5.3.0"
|
||||
|
||||
"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.5.0:
|
||||
"semver@2 || 3 || 4 || 5", semver@^5.3.0:
|
||||
version "5.5.0"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
|
||||
|
||||
@@ -4075,7 +4101,11 @@ tmp@^0.0.33:
|
||||
dependencies:
|
||||
os-tmpdir "~1.0.2"
|
||||
|
||||
to-fast-properties@^1.0.1, to-fast-properties@^1.0.3:
|
||||
to-fast-properties@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320"
|
||||
|
||||
to-fast-properties@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user