Compare commits

..
2 Commits
Author SHA1 Message Date
Tanner Linsley 62cff3d6bc 5.0.3 2017-02-09 10:07:37 -07:00
Tanner Linsley 057a815337 Adjust current page if available pages dips below current page
Fixes #69
2017-02-09 10:07:33 -07:00
89 changed files with 6652 additions and 31645 deletions
-3
View File
@@ -1,3 +0,0 @@
module.exports = {
extends: 'react-tools',
}
-1
View File
@@ -1 +0,0 @@
* text=auto
-38
View File
@@ -1,38 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
---
**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](codesandbox.io/s/X6npLXPRW) 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.
-17
View File
@@ -1,17 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
@@ -1,11 +0,0 @@
---
name: Questions, Support & Help
about: Looking for help? Need a question answered?
---
STOP!!!
Github issues is no place for general support. We encourage you to 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!
-6
View File
@@ -1,11 +1,5 @@
node_modules/
lib/
es/
docs/build
react-table.js
react-table.min.js
react-table.css
*.log
.idea
.DS_Store
.history
+1
View File
@@ -0,0 +1 @@
react-table.js.org
+52
View File
@@ -0,0 +1,52 @@
import React from 'react'
import { configure, storiesOf } from '@kadira/storybook'
import './reset.css'
import './fonts.css'
import './layout.css'
import '../stories/utils/prism.css'
import 'github-markdown-css/github-markdown.css'
import '../react-table.css'
//
import Readme from '../README.md'
//
import Simple from '../stories/Simple.js'
import CellRenderers from '../stories/CellRenderers.js'
import DefaultSorting from '../stories/DefaultSorting.js'
import CustomWidths from '../stories/CustomWidths.js'
import CustomComponentProps from '../stories/CustomComponentProps.js'
import ServerSide from '../stories/ServerSide.js'
import SubComponents from '../stories/SubComponents.js'
import Pivoting from '../stories/Pivoting.js'
import PivotingSubComponents from '../stories/PivotingSubComponents.js'
import OneHundredKRows from '../stories/OneHundredKRows.js'
import FunctionalRendering from '../stories/FunctionalRendering.js'
import CustomExpanderPosition from '../stories/CustomExpanderPosition.js'
//
configure(() => {
storiesOf('1. Docs')
.add('Readme', () => {
const ReadmeCmp = React.createClass({
render () {
return <span className='markdown-body' dangerouslySetInnerHTML={{__html: Readme}} />
},
componentDidMount () {
global.Prism.highlightAll()
}
})
return <ReadmeCmp />
})
storiesOf('2. Demos')
.add('Simple Table', Simple)
.add('Cell Renderers & Custom Components', CellRenderers)
.add('Default Sorting', DefaultSorting)
.add('Custom Column Widths', CustomWidths)
.add('Custom Component Props', CustomComponentProps)
.add('Server-side Data', ServerSide)
.add('Sub Components', SubComponents)
.add('Pivoting & Aggregation', Pivoting)
.add('Pivoting & Aggregation w/ Sub Components', PivotingSubComponents)
.add('100k Rows w/ Pivoting & Sub Components', OneHundredKRows)
.add('Functional Rendering', FunctionalRendering)
.add('Custom Expander Position', CustomExpanderPosition)
}, module)
+6
View File
@@ -0,0 +1,6 @@
@import url("https://fonts.googleapis.com/css?family=Open+Sans:300,600");
body {
background: #fff;
font-family: 'Open Sans', sans-serif;
font-weight: 300;
}
+3
View File
@@ -0,0 +1,3 @@
body{
padding: 20px;
}
+48
View File
@@ -0,0 +1,48 @@
/* http://meyerweb.com/eric/tools/css/reset/
v2.0 | 20110126
License: none (public domain)
*/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
/*ol, ul {
list-style: none;
}*/
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
+27
View File
@@ -0,0 +1,27 @@
const path = require('path')
// load the default config generator.
const genDefaultConfig = require('@kadira/storybook/dist/server/config/defaults/webpack.config.js')
module.exports = (config, env) => {
config = genDefaultConfig(config, env)
Object.assign(config, {
module: Object.assign(config.module, {
loaders: config.module.loaders.concat([{
test: /\.md$/,
loader: 'html!markdown',
include: path.resolve(__dirname, '../')
}, {
test: /\.html$/,
loader: 'html',
query: {
minimize: true
},
include: path.resolve(__dirname, '../')
}])
})
})
return config
}
-187
View File
@@ -1,187 +0,0 @@
## 6.10.1
- Fixed issues with `normalizeComponent` function
## 6.10.0
- Rebased volatile commits out of 6.9.0
- Merged (hopefully) non-breaking fixes after rebasing and reverting.
## 6.9.0
This version has been reverted due to some major bugs that were introduced with it.
## 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
- Allow the `resolveData` prop to alter or materialize new data when the `data` prop changes.
## 6.8.1
#### Fixes & Optimizations
- Updated eslint and code formatting
## 6.7.5
#### Fixes & Optimizations
- Now passes `column` to `getResizerProps` (#667)
- NOTE: `getResizerProps` is now only called if the column is resizable
- Fixes the `className` ordering in defaultProps for ThComponent (#673)
- NOTE: user supplied classNames now come at the end so they can extend the defaults
## 6.7.4
#### Fixes & Optimizations
- Fix Prop types for columns
## 6.7.3
#### Fixes & Optimizations
- Fix the rest of the proptypes
## 6.7.2
#### Fixes & Optimizations
- `getPropTypes` proptype check
## 6.7.1
#### Fixes & Optimizations
- `eslint-config` moved to dev deps
## 6.7.0
## 6.7.0-alpha-0
#### New Features
- Expose page/pageSize to rows/cells
- Supply sort direction to custom sort methods
#### Fixes & Optimizations
- README updates
- Linter cleanup
- Added PropTypes node module
- Deps, linting and style upgrades
## 6.6.0
#### Fixes & Optimizations
- moved repo to react-tools
- Doc examples moved to codesandbox.io
- README updates
- CSS refacting for rt-tfoot to match rt-thead
- CSS more specific for input and select
## 6.5.3
#### Fixes & Optimizations
- `onClick` proxying and eslint
## 6.5.2
#### New Features
- Provide onClick handleOriginal function - #406
#### Fixes & Optimizations
- README updates
- `makePathArray` in utils - #326
- Various fixes: #294, #376, #398, #415,
## 6.5.1
#### Fixes & Optimizations
- `defaultExpanded` now works correctly - #372
- `column.getProps().rest` props are now applied correctly
- `makeTemplateComponent` now supports `displayName` - #289
## 6.5.0
##### New Features
- `column.filterAll` - defaults to `false`, but when set to `true` will provide the entire array of rows to `filterMethod` as opposed to one row at a time. This allows for more fine-grained filtering using any method you can dream up. See the [Custom Filtering example](https://react-table.js.org/#/story/custom-filtering) for more info.
## 6.4.0
##### New Features
- `PadRowComponent` - the content rendered inside of a padding row. Defaults to a react component that renders `&nbsp;`
## 6.3.0
##### New Features
- `defaultSortDesc` - allows you to set the default sorting direction for all columns to descending.
- `column.defaultSortDesc` - allows you to set the default sorting direction for a specific column. Falls back to the global `defaultSortDesc` when not set at all.
## 6.0.0
##### New Features
- New Renderers:
- `Aggregated` - Custom renderer for aggregated cells
- `Pivot` - Custom renderer for Pivoted Cells (utilizes `Expander` and `PivotValue`)
- `PivotValue` - Custom renderer for Pivot cell values (deprecates the undocumented `pivotRender` option)
- `Expander` - Custom renderer for Pivot cell Expander
- Added custom sorting methods per table via `defaultSortMethod` and per column via `column.sortMethod`
- Pivot columns are now visibly separate and sorted/filtered independently.
- Added `column.resizable` to override global table `resizable` option for specific columns.
- Added `column.sortable` to override global table `sortable` option for specific columns.
- Added `column.filterable` to override global table `filterable` option for specific columns.
- Added `defaultExpanded` table option.
- All callbacks can now be utilized without needing to hoist and manage the piece of state they export. That is what their prop counterparts are for, so now the corresponding prop is used instead of the callback to detect a "fully controlled" state.
- Prevent transitions while column resizing for a smoother resize effect.
- Disable text selection while resizing columns.
##### Breaking API Changes
- New Renderers:
- `Cell` - deprecates and replaces `render`
- `Header` - deprecates and replaces `header`
- `Footer` - deprecates and replaces `footer`
- `Filter`- deprecates and replaces `filterRender`
- Callbacks now provide the destination state as the primary parameter(s). This makes hoisting and controlling the state in redux or component state much easier. eg.
- `onSorting` no longer requires you to build your own toggle logic
- `onResize` no longer requires you to build your own resize logic
- Renamed `onChange` callback -> `onFetchData` which will always fire when a new data model needs to be fetched (or if not using `manual`, when new data is materialized internally).
- Renamed `filtering` -> `filtered`
- Renamed `sorting` -> `sorted`
- Renamed `expandedRows` -> `expanded`
- Renamed `resizing` -> `resized`
- Renamed `defaultResizing` -> `defaultResized`
- Renamed `defaultFiltering` -> `defaultFiltered`
- Renamed `defaultSorting` -> `defaultSorted`
- Renamed `onSortingChange` -> `onSortedChange`
- Renamed `onFilteringChange` -> `onFilteredChange`
- Renamed `onResize` -> `onResizedChange`
- Renamed `onExpandRow` -> `onExpandedChange`
- Renamed `showFilters` -> `filterable`
- Renamed `hideFilter` -> `filterable` (Column option. Note the true/false value is now flipped.)
- `cellInfo.row` and `rowInfo.row` now reference the materialize data for the table. To reference the original row, use `cellInfo.original` and `rowInfo.original`
- Removed `pivotRender` column option. You can now control how the value is displayed by overriding the `PivotValueComponent` or the individual column's `PivotValue` renderer. See [Pivoting Options Story](https://react-table.js.org/?selectedKind=2.%20Demos&selectedStory=Pivoting%20Options&full=0&down=1&left=1&panelRight=0&downPanel=kadirahq%2Fstorybook-addon-actions%2Factions-panel) for a reference on how to customize pivot column rendering.
+224 -1044
View File
File diff suppressed because it is too large Load Diff
-77
View File
@@ -1,77 +0,0 @@
module.exports = {
parserOptions: {
ecmaVersion: 8,
ecmaFeatures: {
experimentalObjectRestSpread: true,
jsx: true,
node: false,
classes: true
},
sourceType: 'module'
},
parser: 'babel-eslint',
extends: ['standard'],
plugins: ['react'],
rules: {
// Nozzle
'jsx-quotes': [2, 'prefer-single'],
'comma-dangle': [2, 'always-multiline'],
// // React
'react/jsx-boolean-value': 2,
'react/jsx-curly-spacing': [2, 'never'],
'react/jsx-equals-spacing': [2, 'never'],
// 'react/jsx-indent': 2,
'react/jsx-indent-props': [2, 2],
'react/jsx-no-duplicate-props': 2,
'react/jsx-no-undef': 2,
'react/jsx-tag-spacing': [
2,
{
closingSlash: 'never',
beforeSelfClosing: 'always',
afterOpening: 'never'
}
],
'react/jsx-uses-react': 2,
'react/jsx-uses-vars': 2,
'react/self-closing-comp': 2,
'react/jsx-no-bind': [
2,
{
allowArrowFunctions: true,
allowBind: false,
ignoreRefs: true
}
],
'react/no-did-update-set-state': 2,
'react/no-unknown-property': 2,
'react/react-in-jsx-scope': 2,
'react/jsx-closing-bracket-location': [0, 'tag-aligned'],
'react/jsx-tag-spacing': [2, { beforeSelfClosing: 'always' }],
'react/jsx-wrap-multilines': 2,
'react/self-closing-comp': 2,
'react/jsx-key': 2,
'react/jsx-no-comment-textnodes': 2,
'react/jsx-no-duplicate-props': 2,
'react/jsx-no-target-blank': 2,
'react/jsx-no-undef': 2,
'react/jsx-uses-react': 2,
'react/jsx-uses-vars': 2,
'react/no-danger-with-children': 2,
'react/no-deprecated': 2,
'react/no-direct-mutation-state': 2,
'react/no-find-dom-node': 2,
'react/no-is-mounted': 2,
'react/no-render-return-value': 2,
'react/no-string-refs': 2,
'react/no-unknown-property': 2,
'react/react-in-jsx-scope': 2,
'react/require-render-return': 2
// 'react/jsx-max-props-per-line': [2, { maximum: 1 }]
}
}
+1 -1
View File
@@ -1 +1 @@
react-table.js.org
react-table.js.org
-1628
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

+22
View File
@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script>
if (window.parent !== window) {
window.__REACT_DEVTOOLS_GLOBAL_HOOK__ = window.parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
}
</script>
<title>React Storybook</title>
</head>
<body>
<div id="root"></div>
<div id="error-display"></div>
<script src="static/preview.ee446fa2bd3fbfe7e38a.bundle.js"></script>
</body>
</html>
+44
View File
@@ -0,0 +1,44 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="storybook-version" content="2.35.3">
<title>React Storybook</title>
<style>
/*
When resizing panels, the drag event breaks if the cursor
moves over the iframe. Add the 'dragging' class to the body
at drag start and remove it when the drag ends.
*/
.dragging iframe {
pointer-events: none;
}
/* Styling the fuzzy search box placeholders */
.searchBox::-webkit-input-placeholder { /* Chrome/Opera/Safari */
color: #ddd;
font-size: 16px;
}
.searchBox::-moz-placeholder { /* Firefox 19+ */
color: #ddd;
font-size: 16px;
}
.searchBox:focus{
border-color: #EEE !important;
}
.btn:hover{
background-color: #eee
}
</style>
</head>
<body style="margin: 0;">
<div id="root"></div>
<script src="static/manager.f127c5ae855df8d8558a.bundle.js"></script>
</body>
</html>
-53
View File
@@ -1,53 +0,0 @@
{
"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.

Before

Width:  |  Height:  |  Size: 24 KiB

-31
View File
@@ -1,31 +0,0 @@
<!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>
-120
View File
@@ -1,120 +0,0 @@
/* 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') },
{ name: 'Foldable Table (HOC)', component: CodeSandbox('8pkrj5yorl') },
{ name: 'Advanced Expand Table (HOC)', component: CodeSandbox('y2m39jz8v1') }
];
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}
/>
);
}
}
-21
View File
@@ -1,21 +0,0 @@
import React from "react";
export default id => () => {
return (
<iframe
src={`https://codesandbox.io/embed/${id}?autoresize=1&hidenavigation=1&view=${
global.innerWidth < 1000 ? "preview" : "split"
}`}
style={{
position: "absolute",
top: 0,
left: 0,
width: `100%`,
height: `100%`,
border: 0,
overflow: `hidden`
}}
sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"
/>
);
};
@@ -1,116 +0,0 @@
import React from 'react';
import { render } from 'react-dom';
import { makeData, Logo, Tips } from './Utils';
import { advancedExpandTableHOC } from '../../../../lib/hoc/advancedExpandTable';
// Import React Table
import ReactTable from 'react-table';
import 'react-table/react-table.css';
const columns = [
{
Header: 'First Name',
accessor: 'firstName',
Cell: props => {
const {
// react table props
columnProps: { rest: { showRowSubComponent } },
nestingPath
} = props;
return (
<div>
<button
onClick={e => showRowSubComponent({ nestingPath: nestingPath }, e)}
>
SHOW SUBCOMPONENT {props.value}
</button>
</div>
);
}
},
{
Header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
},
{
Header: 'Info',
columns: [
{
Header: 'Age',
accessor: 'age',
Cell: props => {
const {
// react table props
columnProps: { rest: { toggleRowSubComponent } },
nestingPath
} = props;
return (
<div>
<button
onClick={e =>
toggleRowSubComponent({ nestingPath: nestingPath }, e)
}
>
TOGGLE SUBCOMPONENT {props.value}
</button>
</div>
);
}
},
{
Header: 'Status',
accessor: 'status'
}
]
},
{
Header: 'Stats',
columns: [
{
Header: 'Visits',
accessor: 'visits'
}
]
}
];
const AdvancedExpandReactTable = advancedExpandTableHOC(ReactTable);
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: makeData()
};
}
render() {
const { data } = this.state;
return (
<div>
<AdvancedExpandReactTable
data={data}
columns={columns}
defaultPageSize={10}
className='-striped -highlight'
SubComponent={({ row, nestingPath, toggleRowSubComponent }) => {
return (
<div style={{ padding: '20px' }}>
<button
onClick={e => toggleRowSubComponent({ nestingPath }, e)}
>
CLOSE SUBCOMPONENT {row.firstName} {row.lastName}
</button>
</div>
);
}}
/>
<br />
<Tips />
<Logo />
</div>
);
}
}
render(<App />, document.getElementById('root'));
-94
View File
@@ -1,94 +0,0 @@
import React from "react";
export default Component => {
const wrapper = class RTCheckboxTable extends React.Component {
// we only need a Component so we can get the 'ref' - pure components can't get a 'ref'
rowSelector = row => {
if (!row || !row.hasOwnProperty(this.props.keyField)) return null;
const checked = this.props.isSelected(row[this.props.keyField]);
return (
<input
type="checkbox"
checked={checked}
onClick={e => {
const { shiftKey } = e;
e.stopPropagation();
this.props.toggleSelection(row[this.props.keyField], shiftKey, row);
}}
onChange={() => {}}
value=""
/>
);
};
headSelector = row => {
const checked = this.props.selectAll;
return (
<input
type="checkbox"
checked={checked}
onClick={e => {
e.stopPropagation();
this.props.toggleAll();
}}
onChange={() => {}}
value=""
/>
);
};
// this is so we can expose the underlying ReactTable to get at the sortedData for selectAll
getWrappedInstance = () => this.wrappedInstance;
render() {
const {
columns: originalCols,
isSelected,
toggleSelection,
toggleAll,
keyField,
selectAll,
...rest
} = this.props;
const { rowSelector, headSelector } = this;
const select = {
id: "_selector",
accessor: () => "x", // this value is not important
Header: headSelector,
Cell: ci => {
return rowSelector(ci.original);
},
width: 30,
filterable: false,
sortable: false,
resizable: false,
style: { textAlign: "center" }
};
const columns = [select, ...originalCols];
const extra = {
columns
};
return (
<Component {...rest} {...extra} ref={r => (this.wrappedInstance = r)} />
);
}
};
wrapper.displayName = "RTCheckboxTable";
wrapper.defaultProps = {
keyField: "_id",
isSelected: key => {
console.log("No isSelected handler provided:", { key });
},
selectAll: false,
toggleSelection: (key, shift, row) => {
console.log("No toggleSelection handler provided:", { key, shift, row });
},
toggleAll: () => {
console.log("No toggleAll handler provided.");
}
};
return wrapper;
};
-148
View File
@@ -1,148 +0,0 @@
import React from "react";
import shortid from "shortid";
import ReactTable from "../../../../lib/index";
import "../../../../react-table.css";
import checkboxTableHOC from "./checkboxHOC";
const CheckboxTable = checkboxTableHOC(ReactTable);
async function getData() {
const result = await (await fetch("/au_500_tree.json")).json();
// we are adding a unique ID to the data for tracking the selected records
return result.map(item => {
const _id = shortid.generate();
return {
_id,
...item
};
});
}
function getColumns(data) {
const columns = [];
const sample = data[0];
for (let key in sample) {
if (key === "_id") continue;
columns.push({
accessor: key,
Header: key
});
}
return columns;
}
export class ComponentTest extends React.Component {
constructor(props) {
super(props);
this.state = {
data: null,
columns: null,
selection: [],
selectAll: false
};
}
componentDidMount() {
getData().then(data => {
const columns = getColumns(data);
this.setState({ data, columns });
});
}
toggleSelection = (key, shift, row) => {
/*
Implementation of how to manage the selection state is up to the developer.
This implementation uses an array stored in the component state.
Other implementations could use object keys, a Javascript Set, or Redux... etc.
*/
// start off with the existing state
let selection = [...this.state.selection];
const keyIndex = selection.indexOf(key);
// check to see if the key exists
if (keyIndex >= 0) {
// it does exist so we will remove it using destructing
selection = [
...selection.slice(0, keyIndex),
...selection.slice(keyIndex + 1)
];
} else {
// it does not exist so add it
selection.push(key);
}
// update the state
this.setState({ selection });
};
toggleAll = () => {
/*
'toggleAll' is a tricky concept with any filterable table
do you just select ALL the records that are in your data?
OR
do you only select ALL the records that are in the current filtered data?
The latter makes more sense because 'selection' is a visual thing for the user.
This is especially true if you are going to implement a set of external functions
that act on the selected information (you would not want to DELETE the wrong thing!).
So, to that end, access to the internals of ReactTable are required to get what is
currently visible in the table (either on the current page or any other page).
The HOC provides a method call 'getWrappedInstance' to get a ref to the wrapped
ReactTable and then get the internal state and the 'sortedData'.
That can then be iterrated to get all the currently visible records and set
the selection state.
*/
const selectAll = this.state.selectAll ? false : true;
const selection = [];
if (selectAll) {
// we need to get at the internals of ReactTable
const wrappedInstance = this.checkboxTable.getWrappedInstance();
// the 'sortedData' property contains the currently accessible records based on the filter and sort
const currentRecords = wrappedInstance.getResolvedState().sortedData;
// we just push all the IDs onto the selection array
currentRecords.forEach(item => {
selection.push(item._original._id);
});
}
this.setState({ selectAll, selection });
};
isSelected = key => {
/*
Instead of passing our external selection state we provide an 'isSelected'
callback and detect the selection state ourselves. This allows any implementation
for selection (either an array, object keys, or even a Javascript Set object).
*/
return this.state.selection.includes(key);
};
logSelection = () => {
console.log("selection:", this.state.selection);
};
render() {
const { toggleSelection, toggleAll, isSelected, logSelection } = this;
const { data, columns, selectAll } = this.state;
const extraProps = {
selectAll,
isSelected,
toggleAll,
toggleSelection
};
return (
<div style={{ padding: "10px" }}>
<h1>react-table - Checkbox Table</h1>
<button onClick={logSelection}>Log Selection to Console</button>
{` (${this.state.selection.length}) selected`}
{data ? (
<CheckboxTable
data={data}
columns={columns}
ref={r => (this.checkboxTable = r)}
className="-striped -highlight"
{...extraProps}
/>
) : null}
</div>
);
}
}
// export default treeTableHOC(ComponentTest);
export default ComponentTest;
-60
View File
@@ -1,60 +0,0 @@
import React from "react";
export default class ComponentTest extends React.component {
render() {
return <div>Bozo</div>;
}
}
// import ReactTable from '../../../../lib/index'
// import '../../../../react-table.css'
//
// console.log('ReactTable:',ReactTable)
//
// const data = [
// {one:"1.1",two:"1.2"},
// {one:"2.1",two:"2.2"},
// {one:"3.1",two:"3.2"},
// {one:"4.1",two:"4.2"},
// ]
//
// const columns = [
// {accessor:'one', Header: 'One'},
// {accessor:'two', Header: 'Two'},
// ]
//
// class ExpanderComponent extends React.Component {
// render()
// {
// return (
// <div className={`rt-expander ${this.props.isExpanded ? '-open' : ''}`}>
// &bull;
// </div>
// )
// }
// }
//
// class SubComponent extends React.Component {
// render()
// {
// return <div>Nothing</div>
// }
// }
//
// export default class ComponentTest extends React.Component {
// render()
// {
// const rtProps = {
// data,
// columns,
// // ExpanderComponent: (props, closeExpanded)=><ExpanderComponent {...props, closeExpanded} />,
// // SubComponent: (props)=><SubComponent {...props} />,
// // multiSort: false,
// }
// return (
// <ReactTable
// {...rtProps}
// />
// )
// }
// }
@@ -1,110 +0,0 @@
import React from 'react'
import ReactTable from '../../../../lib/index'
import FoldableTableHOC from '../../../../lib/hoc/foldableTable'
import selectTableHOC from '../../../../lib/hoc/selectTable'
const FoldableTable = FoldableTableHOC(selectTableHOC(ReactTable))
export default class FoldableTableCustomState extends React.Component {
constructor(props, context) {
super(props, context)
this.state = { folded: {}, seleted: {}, selectedAll: false }
}
getData = () => [{
id: 1,
first_name: 'Jeanette',
'last_name': 'Penddreth',
email: 'jpenddreth0@census.gov',
'gender': 'Female',
ip_address: '26.58.193.2',
}, {
'id': 2,
'first_name': 'Giavani',
last_name: 'Frediani',
'email': 'gfrediani1@senate.gov',
'gender': 'Male',
'ip_address': '229.179.4.212',
}, {
'id': 3,
first_name: 'Noell',
last_name: 'Bea',
'email': 'nbea2@imageshack.us',
gender: 'Female',
ip_address: '180.66.162.255',
}, {
'id': 4,
'first_name': 'Willard',
'last_name': 'Valek',
email: 'wvalek3@vk.com',
'gender': 'Male',
ip_address: '67.76.188.26',
}];
toggleSelection = (key, shift, row) => {
const { selected } = this.state
let newSelected = Object.assign({}, selected)
newSelected[key] = !newSelected[key]
this.setState(p => ({ selected: newSelected }))
};
toggleAll = () => {
const { selectedAll } = this.state
if (selectedAll) { this.setState(p => { return { selectedAll: false, seleted: {} } }); }
else {
const data = this.getData()
let newSelected = {}
data.forEach(d => newSelected[d.id] = true)
this.setState(p => ({ selectedAll: true, seleted: newSelected }))
}
}
isSelected = key => this.state.seleted[key];
render() {
return (<FoldableTable
//SelectTable props
keyField='id'
toggleSelection={this.toggleSelection}
toggleAll={this.toggleAll}
isSelected={this.isSelected}
selectAll={this.state.selectedAll}
selectType='checkbox'
onFoldChange={newFolded => this.setState(p => { return { folded: newFolded } })}
folded={this.state.folded}
data={this.getData()}
columns={[{
Header: "Name",
foldable: true,
columns: [
{
Header: "First Name",
accessor: "first_name"
},
{
Header: "Last Name",
accessor: "last_name"
}
]
}, {
Header: "Info",
foldable: true,
columns: [
{
Header: "Email",
accessor: "email"
},
{
Header: "Gender",
accessor: "gender"
}
]
}]
}></FoldableTable>)
}
}
@@ -1,71 +0,0 @@
import React from 'react'
import ReactTable from '../../../../lib/index'
import FoldableTableHOC from '../../../../lib/hoc/foldableTable'
const FoldableTable = FoldableTableHOC(ReactTable)
export default class FoldableTableWithHeader extends React.Component {
getData = () => [{
id: 1,
first_name: 'Jeanette',
last_name: 'Penddreth',
'email': 'jpenddreth0@census.gov',
gender: 'Female',
'ip_address': '26.58.193.2',
}, {
'id': 2,
first_name: 'Giavani',
last_name: 'Frediani',
email: 'gfrediani1@senate.gov',
gender: 'Male',
'ip_address': '229.179.4.212',
}, {
'id': 3,
'first_name': 'Noell',
last_name: 'Bea',
'email': 'nbea2@imageshack.us',
'gender': 'Female',
ip_address: '180.66.162.255',
}, {
'id': 4,
'first_name': 'Willard',
'last_name': 'Valek',
email: 'wvalek3@vk.com',
'gender': 'Male',
ip_address: '67.76.188.26',
}];
render() {
return (<FoldableTable
data={this.getData()}
columns={[{
Header: "Name",
foldable: true,
columns: [
{
Header: "First Name",
accessor: "first_name"
},
{
Header: "Last Name",
accessor: "last_name"
}
]
}, {
Header: "Info",
foldable: true,
columns: [
{
Header: "Email",
accessor: "email"
},
{
Header: "Gender",
accessor: "gender"
}
]
}]
}></FoldableTable>)
}
}
@@ -1,64 +0,0 @@
import React from 'react';
import ReactTable from '../../../../lib/index';
import FoldableTableHOC from '../../../../lib/hoc/foldableTable';
const FoldableTable = FoldableTableHOC(ReactTable);
export default class FoldableTableWithoutHeader extends React.Component {
getData = () => [{
"id": 1,
"first_name": "Jeanette",
"last_name": "Penddreth",
"email": "jpenddreth0@census.gov",
"gender": "Female",
"ip_address": "26.58.193.2"
}, {
"id": 2,
"first_name": "Giavani",
"last_name": "Frediani",
"email": "gfrediani1@senate.gov",
"gender": "Male",
"ip_address": "229.179.4.212"
}, {
"id": 3,
"first_name": "Noell",
"last_name": "Bea",
"email": "nbea2@imageshack.us",
"gender": "Female",
"ip_address": "180.66.162.255"
}, {
"id": 4,
"first_name": "Willard",
"last_name": "Valek",
"email": "wvalek3@vk.com",
"gender": "Male",
"ip_address": "67.76.188.26"
}];
render() {
return <FoldableTable
data={this.getData()}
columns={[
{
Header: "First Name",
accessor: "first_name"
},
{
Header: "Last Name",
accessor: "last_name",
foldable: true,
},
{
Header: "Email",
accessor: "email",
foldable: true,
},
{
Header: "Gender",
accessor: "gender",
foldable: true,
}
]}></FoldableTable>
}
}
-30
View File
@@ -1,30 +0,0 @@
import React from 'react'
import '../../../../react-table.css'
import FoldableTableWithHeader from './FoldableTableWithHeader'
import FoldableTableWithoutHeader from './FoldableTableWithoutHeader'
import FoldableTableCustomState from './FoldableTableCustomState'
class FaldableComponentTest extends React.Component {
render() {
return (
<div>
<p>- Sample With Header Columns</p>
<br />
<FoldableTableWithHeader />
<br /> <br />
<p>- Sample With Normal Columns</p>
<br />
<FoldableTableWithoutHeader />
<br /> <br />
<p>- Custom State and selectedTable</p>
<br />
<FoldableTableCustomState />
</div >
)
}
}
export default FaldableComponentTest
-13
View File
@@ -1,13 +0,0 @@
/* eslint-disable */
import TreeTable from './treetable'
import SelectTable from './selecttable'
import SelectTreeTable from './selecttreetable'
import FoldableTable from './foldabletable';
export {
TreeTable,
SelectTable,
SelectTreeTable,
FoldableTable
}
-173
View File
@@ -1,173 +0,0 @@
import React from "react";
import shortid from "shortid";
import ReactTable from "../../../../lib/index";
import "../../../../react-table.css";
import selectTableHOC from "../../../../lib/hoc/selectTable";
const SelectTable = selectTableHOC(ReactTable);
async function getData() {
const result = await (await fetch("/au_500_tree.json")).json();
// we are adding a unique ID to the data for tracking the selected records
return result.map(item => {
const _id = shortid.generate();
return {
_id,
...item
};
});
}
function getColumns(data) {
const columns = [];
const sample = data[0];
for (let key in sample) {
if (key === "_id") continue;
columns.push({
accessor: key,
Header: key
});
}
return columns;
}
export class ComponentTest extends React.Component {
constructor(props) {
super(props);
this.state = {
data: null,
columns: null,
selection: [],
selectAll: false,
selectType: "checkbox"
};
}
componentDidMount() {
getData().then(data => {
const columns = getColumns(data);
this.setState({ data, columns });
});
}
toggleSelection = (key, shift, row) => {
/*
Implementation of how to manage the selection state is up to the developer.
This implementation uses an array stored in the component state.
Other implementations could use object keys, a Javascript Set, or Redux... etc.
*/
// start off with the existing state
if (this.state.selectType === "radio") {
let selection = [];
if (selection.indexOf(key) < 0) selection.push(key);
this.setState({ selection });
} else {
let selection = [...this.state.selection];
const keyIndex = selection.indexOf(key);
// check to see if the key exists
if (keyIndex >= 0) {
// it does exist so we will remove it using destructing
selection = [
...selection.slice(0, keyIndex),
...selection.slice(keyIndex + 1)
];
} else {
// it does not exist so add it
selection.push(key);
}
// update the state
this.setState({ selection });
}
};
toggleAll = () => {
/*
'toggleAll' is a tricky concept with any filterable table
do you just select ALL the records that are in your data?
OR
do you only select ALL the records that are in the current filtered data?
The latter makes more sense because 'selection' is a visual thing for the user.
This is especially true if you are going to implement a set of external functions
that act on the selected information (you would not want to DELETE the wrong thing!).
So, to that end, access to the internals of ReactTable are required to get what is
currently visible in the table (either on the current page or any other page).
The HOC provides a method call 'getWrappedInstance' to get a ref to the wrapped
ReactTable and then get the internal state and the 'sortedData'.
That can then be iterrated to get all the currently visible records and set
the selection state.
*/
const selectAll = this.state.selectAll ? false : true;
const selection = [];
if (selectAll) {
// we need to get at the internals of ReactTable
const wrappedInstance = this.selectTable.getWrappedInstance();
// the 'sortedData' property contains the currently accessible records based on the filter and sort
const currentRecords = wrappedInstance.getResolvedState().sortedData;
// we just push all the IDs onto the selection array
currentRecords.forEach(item => {
if (item._original) {
selection.push(item._original._id);
}
});
}
this.setState({ selectAll, selection });
};
isSelected = key => {
/*
Instead of passing our external selection state we provide an 'isSelected'
callback and detect the selection state ourselves. This allows any implementation
for selection (either an array, object keys, or even a Javascript Set object).
*/
return this.state.selection.includes(key);
};
logSelection = () => {
console.log("selection:", this.state.selection);
};
toggleType = () => {
this.setState({
selectType: this.state.selectType === "radio" ? "checkbox" : "radio",
selection: [],
selectAll: false
});
};
render() {
const {
toggleSelection,
toggleAll,
isSelected,
logSelection,
toggleType
} = this;
const { data, columns, selectAll, selectType } = this.state;
const extraProps = {
selectAll,
isSelected,
toggleAll,
toggleSelection,
selectType
};
return (
<div style={{ padding: "10px" }}>
<h1>react-table - Select Table</h1>
<button onClick={toggleType}>
Select Type: <strong>{selectType}</strong>
</button>
<button onClick={logSelection}>Log Selection to Console</button>
{` (${this.state.selection.length}) selected`}
{data ? (
<SelectTable
data={data}
columns={columns}
ref={r => (this.selectTable = r)}
className="-striped -highlight"
{...extraProps}
/>
) : null}
</div>
);
}
}
export default ComponentTest;
-238
View File
@@ -1,238 +0,0 @@
import React from "react";
import shortid from "shortid";
import ReactTable from "../../../../lib/index";
import "../../../../react-table.css";
import selectTableHOC from "../../../../lib/hoc/selectTable";
import treeTableHOC from "../../../../lib/hoc/treeTable";
const SelectTreeTable = selectTableHOC(treeTableHOC(ReactTable));
async function getData() {
const result = await (await fetch("/au_500_tree.json")).json();
// we are adding a unique ID to the data for tracking the selected records
return result.map(item => {
const _id = shortid.generate();
return {
_id,
...item
};
});
}
function getColumns(data) {
const columns = [];
const sample = data[0];
for (let key in sample) {
if (key === "_id") continue;
columns.push({
accessor: key,
Header: key
});
}
return columns;
}
function getNodes(data, node = []) {
data.forEach(item => {
if (item.hasOwnProperty("_subRows") && item._subRows) {
node = getNodes(item._subRows, node);
} else {
node.push(item._original);
}
});
return node;
}
export class ComponentTest extends React.Component {
constructor(props) {
super(props);
this.state = {
data: null,
columns: null,
selection: [],
selectAll: false,
selectType: "checkbox"
};
}
componentDidMount() {
getData().then(data => {
const columns = getColumns(data);
const pivotBy = ["state", "post"];
this.setState({ data, columns, pivotBy });
});
}
toggleSelection = (key, shift, row) => {
/*
Implementation of how to manage the selection state is up to the developer.
This implementation uses an array stored in the component state.
Other implementations could use object keys, a Javascript Set, or Redux... etc.
*/
// start off with the existing state
if (this.state.selectType === "radio") {
let selection = [];
if (selection.indexOf(key) < 0) selection.push(key);
this.setState({ selection });
} else {
let selection = [...this.state.selection];
const keyIndex = selection.indexOf(key);
// check to see if the key exists
if (keyIndex >= 0) {
// it does exist so we will remove it using destructing
selection = [
...selection.slice(0, keyIndex),
...selection.slice(keyIndex + 1)
];
} else {
// it does not exist so add it
selection.push(key);
}
// update the state
this.setState({ selection });
}
};
toggleAll = () => {
/*
'toggleAll' is a tricky concept with any filterable table
do you just select ALL the records that are in your data?
OR
do you only select ALL the records that are in the current filtered data?
The latter makes more sense because 'selection' is a visual thing for the user.
This is especially true if you are going to implement a set of external functions
that act on the selected information (you would not want to DELETE the wrong thing!).
So, to that end, access to the internals of ReactTable are required to get what is
currently visible in the table (either on the current page or any other page).
The HOC provides a method call 'getWrappedInstance' to get a ref to the wrapped
ReactTable and then get the internal state and the 'sortedData'.
That can then be iterrated to get all the currently visible records and set
the selection state.
*/
const selectAll = this.state.selectAll ? false : true;
const selection = [];
if (selectAll) {
// we need to get at the internals of ReactTable
const wrappedInstance = this.selectTable.getWrappedInstance();
// the 'sortedData' property contains the currently accessible records based on the filter and sort
const currentRecords = wrappedInstance.getResolvedState().sortedData;
// we need to get all the 'real' (original) records out to get at their IDs
const nodes = getNodes(currentRecords);
// we just push all the IDs onto the selection array
nodes.forEach(item => {
selection.push(item._id);
});
}
this.setState({ selectAll, selection });
};
isSelected = key => {
/*
Instead of passing our external selection state we provide an 'isSelected'
callback and detect the selection state ourselves. This allows any implementation
for selection (either an array, object keys, or even a Javascript Set object).
*/
return this.state.selection.includes(key);
};
logSelection = () => {
console.log("selection:", this.state.selection);
};
toggleType = () => {
this.setState({
selectType: this.state.selectType === "radio" ? "checkbox" : "radio",
selection: [],
selectAll: false
});
};
toggleTree = () => {
if (this.state.pivotBy.length) {
this.setState({ pivotBy: [], expanded: {} });
} else {
this.setState({ pivotBy: ["state", "post"], expanded: {} });
}
};
onExpandedChange = expanded => {
this.setState({ expanded });
};
render() {
const {
toggleSelection,
toggleAll,
isSelected,
logSelection,
toggleType,
toggleTree,
onExpandedChange
} = this;
const {
data,
columns,
selectAll,
selectType,
pivotBy,
expanded
} = this.state;
const extraProps = {
selectAll,
isSelected,
toggleAll,
toggleSelection,
selectType,
pivotBy,
expanded,
onExpandedChange,
pageSize: 5
};
return (
<div style={{ padding: "10px" }}>
<h1>react-table - Select Tree Table</h1>
<p>
This example combines two HOCs (the TreeTable and the SelectTable) to
make a composite component.
</p>
<p>We'll call it SelectTreeTable!</p>
<p>Here is what the buttons do:</p>
<ul>
<li>
<strong>Toggle Tree:</strong> enables or disabled the pivotBy on the
table.
</li>
<li>
<strong>Select Type:</strong> changes from 'checkbox' to 'radio' and
back again.
</li>
<li>
<strong>Log Selection to Console:</strong> open your console to see
what has been selected.
</li>
</ul>
<p>
<strong>NOTE:</strong> the selection is maintained when toggling the
tree on and off but is cleared when switching between select types
(radio, checkbox).
</p>
<button onClick={toggleTree}>
Toggle Tree [{pivotBy && pivotBy.length ? pivotBy.join(", ") : ""}]
</button>
<button onClick={toggleType}>
Select Type: <strong>{selectType}</strong>
</button>
<button onClick={logSelection}>Log Selection to Console</button>
{` (${this.state.selection.length}) selected`}
{data ? (
<SelectTreeTable
data={data}
columns={columns}
ref={r => (this.selectTable = r)}
className="-striped -highlight"
freezeWhenExpanded={true}
{...extraProps}
/>
) : null}
</div>
);
}
}
export default ComponentTest;
-70
View File
@@ -1,70 +0,0 @@
import React from "react";
import ReactTable from "../../../../lib/index";
import "../../../../react-table.css";
import treeTableHOC from "../../../../lib/hoc/treeTable";
async function getData() {
const result = await (await fetch("/au_500_tree.json")).json();
return result;
}
function getColumns(data, pivotBy) {
const columns = [];
const sample = data[0];
for (let key in sample) {
columns.push({
accessor: key,
Header: key
});
}
return columns;
}
export class ComponentTest extends React.Component {
constructor(props) {
super(props);
this.state = {
data: null,
columns: null,
pivotBy: null // ["firstName", "lastName"],
};
}
componentDidMount() {
getData().then(data => {
// console.log('cwm data:',data);
const pivotBy = ["state", "post", "city"];
const columns = getColumns(data, pivotBy);
// console.log('cwm cols:',columns);
this.setState({ data, columns, pivotBy });
});
}
showState = () => {
console.log("state:", this.reactTable.getResolvedState());
};
render() {
const { data, columns, pivotBy } = this.state;
const extraProps = {
data,
columns,
pivotBy
};
const TreeTable = treeTableHOC(ReactTable);
return (
<div style={{ padding: "10px" }}>
<h1>react-table - Tree Table</h1>
{data ? (
<TreeTable
ref={r => (this.reactTable = r)}
className="-striped -highlight"
defaultPageSize={5}
{...extraProps}
/>
) : null}
</div>
);
}
}
export default ComponentTest;
@@ -1,53 +0,0 @@
import React from "react";
export default Component => {
const wrapper = componentProps => {
const TrComponent = props => {
const { ri, ...rest } = props;
if (ri && ri.groupedByPivot) {
const cell = props.children[ri.level];
cell.props.style.flex = "unset";
cell.props.style.width = "100%";
cell.props.style.maxWidth = "unset";
cell.props.style.paddingLeft = `${componentProps.treeTableIndent *
ri.level}px`;
cell.props.style.backgroundColor = "#DDD";
cell.props.style.borderBottom = "1px solid rgba(128,128,128,0.2)";
return <div {...rest}>{cell}</div>;
}
return <Component.defaultProps.TrComponent {...rest} />;
};
const getTrProps = (state, ri, ci, instance) => {
return { ri };
};
const { columns, ...rest } = componentProps;
const extra = {
columns: columns.map(col => {
let column = col;
if (rest.pivotBy && rest.pivotBy.includes(col.accessor)) {
column = {
accessor: col.accessor,
width: `${componentProps.treeTableIndent}px`,
show: false,
Header: ""
};
}
return column;
}),
TrComponent,
getTrProps
};
return <Component {...rest} {...extra} />;
};
wrapper.displayName = "RTTreeTable";
wrapper.defaultProps = {
treeTableRowBackground: "#EEE",
treeTableIndent: 10
};
return wrapper;
};
-35
View File
@@ -1,35 +0,0 @@
import namor from "namor";
const range = len => {
const arr = [];
for (let i = 0; i < len; i++) {
arr.push(i);
}
return arr;
};
const newPerson = () => {
const statusChance = Math.random();
return {
firstName: namor.generate({ words: 1, numbers: 0 }),
lastName: namor.generate({ words: 1, numbers: 0 }),
age: Math.floor(Math.random() * 30),
visits: Math.floor(Math.random() * 100),
progress: Math.floor(Math.random() * 100),
status:
statusChance > 0.66
? "relationship"
: statusChance > 0.33
? "complicated"
: "single"
};
};
export function makeData(len = 5553) {
return range(len).map(d => {
return {
...newPerson(),
children: range(10).map(newPerson)
};
});
}
-10
View File
@@ -1,10 +0,0 @@
html,
body,
#root {
height: 100%;
}
body {
margin: 0;
padding: 0;
font-family: sans-serif;
}
-7
View File
@@ -1,7 +0,0 @@
import React from "react";
import ReactDOM from "react-dom";
//
import "./index.css";
import App from "./App.js";
ReactDOM.render(<App />, document.getElementById("root"));
-23
View File
@@ -1,23 +0,0 @@
/* eslint-disable */
import React from "react";
import marked from "marked";
//
import HOCReadme from "!raw!../../../src/hoc/README.md";
import "github-markdown-css/github-markdown.css";
import "./utils/prism.js";
export default class HOCStory extends React.Component {
render() {
return (
<div style={{ padding: "10px" }}>
<span
className="markdown-body"
dangerouslySetInnerHTML={{ __html: marked(HOCReadme) }}
/>
</div>
);
}
componentDidMount() {
global.Prism && global.Prism.highlightAll();
}
}
-23
View File
@@ -1,23 +0,0 @@
/* 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();
}
}
-27
View File
@@ -1,27 +0,0 @@
import React from "react";
import ReactTable from "../../../lib/index";
import "../../../react-table.css";
const data = [
{ one: "1.1", two: "1.2" },
{ one: "2.1", two: "2.2" },
{ one: "3.1", two: "3.2" },
{ one: "4.1", two: "4.2" }
];
const columns = [
{ accessor: "one", Header: "One" },
{ accessor: "two", Header: "Two" }
];
export default class Story extends React.Component {
render() {
return (
<div>
Test
<ReactTable data={data} columns={columns} />
</div>
);
}
}
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
{"version":3,"file":"static/manager.f127c5ae855df8d8558a.bundle.js","sources":["webpack:///static/manager.f127c5ae855df8d8558a.bundle.js"],"mappings":"AAAA;AAkuDA;AA84DA;AA28DA;AA00DA;AAsyEA;AA89CA;AA8rDA;AAsiDA;AAg6DA;AA2nDA;AA++CA;AAkvDA;AAsnEA;AA2oDA;AAivCA;AA+nDA;AAkpDA;AA6lEA;AAs4DA;AAquDA;AA+pDA;AAqxDA;AAsrDA;AAwyDA;AA88GA;AAj6CA;AAopGA;AAsuFA;AA+zEA;AAtMA;AAizEA","sourceRoot":""}
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
{"version":3,"file":"static/preview.ee446fa2bd3fbfe7e38a.bundle.js","sources":["webpack:///static/preview.ee446fa2bd3fbfe7e38a.bundle.js"],"mappings":"AAAA;AAkuDA;AAiwDA;AAs1EA;AA+gGA;AAo4IA;AAt5NA;AA4udA;AA2hEA;AA2uDA;AA29DA;AA2gDA;AAosDA;AAuhDA;AA+6DA;AAioDA;AA4+CA;AAwpDA;AAisEA;AAqoDA;AAqwCA;AA2oDA;AAowDA;AAokEA;AA0vDA;AA2rDA;AA8nDA;AAwrFA;AAyiGA;AA0/CA;AAqyCA;AA22CA;AAu/CA;AAyGA;AA+jFA","sourceRoot":""}
-7301
View File
File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

-8348
View File
File diff suppressed because it is too large Load Diff
+50 -97
View File
@@ -1,12 +1,12 @@
{
"name": "react-table",
"version": "6.10.2",
"version": "5.0.3",
"description": "A fast, lightweight, opinionated table and datagrid built on React",
"license": "MIT",
"homepage": "https://github.com/react-tools/react-table#readme",
"homepage": "https://github.com/tannerlinsley/react-table#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/react-tools/react-table.git"
"url": "git+https://github.com/tannerlinsley/react-table.git"
},
"keywords": [
"react",
@@ -15,123 +15,76 @@
"datagrid"
],
"main": "lib/index.js",
"module": "es/index.js",
"files": [
"src/",
"es/",
"lib/",
"react-table.js",
"react-table.min.js",
"react-table.css",
"media/*.png"
],
"scripts": {
"build:cjs": "babel src --out-dir lib --source-maps inline --copy-files",
"build:es": "cross-env BABEL_ENV=es babel src --out-dir es --source-maps inline",
"build:umd": "cross-env BABEL_ENV=umd rollup -c",
"build:umd-min": "cross-env 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",
"build:node": "babel src --out-dir lib --source-maps inline",
"build:css": "rm -rf react-table.css && stylus src/index.styl --compress -o react-table.css && yarn run 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"
"watch:node": "onchange 'src/**/*.js' -i -- npm run build:node",
"watch:css": "onchange 'src/**/*.styl' -i -- npm run build:css",
"test": "standard",
"umd": "rm -rf react-table.js && browserify lib/index.js -s reactTable -x react -t babelify -g uglifyify -o react-table.js",
"prepublish": "npm-run-all build:* && npm run umd",
"storybook": "start-storybook -p 8000 -c .storybook",
"docs": "build-storybook -o docs && cp .storybook/CNAME docs/CNAME"
},
"dependencies": {
"classnames": "^2.2.5"
},
"peerDependencies": {
"prop-types": "^15.5.0",
"react": "^15.x.x || ^16.x.x",
"react-dom": "^15.x.x || ^16.x.x"
"react": "^15.x.x"
},
"devDependencies": {
"@kadira/storybook": "^2.35.1",
"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",
"cross-env": "^5.1.4",
"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",
"babel-preset-es2015": "6.14.0",
"babel-preset-react": "6.11.1",
"babel-preset-stage-2": "6.13.0",
"babelify": "^7.3.0",
"browserify": "13.1.0",
"github-markdown-css": "^2.4.1",
"html-loader": "^0.4.4",
"markdown-loader": "^0.1.7",
"namor": "^0.3.0",
"npm-run-all": "^3.1.1",
"onchange": "^3.0.2",
"postcss-cli": "^2.6.0",
"prop-types": "^15.7.2",
"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"
"react": "^15.4.2",
"react-dom": "^15.4.2",
"react-json-tree": "^0.10.1",
"standard": "^8.0.0",
"stylus": "^0.54.5",
"uglifyify": "3.0.3"
},
"browserify-shim": {
"react": "global:React"
},
"standard": {
"parser": "babel-eslint",
"ignore": [
"node_modules",
"dist",
"lib",
"example",
"react-table.js",
"stories",
"docs"
]
},
"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"
]
}
}
"presets": [
"es2015",
"stage-2",
"react"
]
}
}
Binary file not shown.
-42
View File
@@ -1,42 +0,0 @@
import nodeResolve from 'rollup-plugin-node-resolve'
import babel from 'rollup-plugin-babel'
import replace from 'rollup-plugin-replace'
import commonjs from 'rollup-plugin-commonjs'
import uglify from 'rollup-plugin-uglify'
const env = process.env.NODE_ENV
const config = {
input: 'src/index.js',
output: {
file: env === 'production' ? 'react-table.min.js' : 'react-table.js',
format: 'umd',
globals: {
react: 'React',
},
name: 'ReactTable',
exports: 'named',
},
external: ['react'],
plugins: [
nodeResolve(),
babel({
exclude: '**/node_modules/**',
}),
replace({
'process.env.NODE_ENV': JSON.stringify(env),
}),
commonjs(),
],
}
if (env === 'production') {
config.plugins.push(uglify({
compress: {
dead_code: true,
warnings: false,
},
}))
}
export default config
+410
View File
@@ -0,0 +1,410 @@
import _ from './utils'
export default {
getDataModel (nextProps, nextState) {
const {
columns,
pivotBy = [],
data,
pivotIDKey,
pivotValKey,
subRowsKey,
expanderColumnWidth,
SubComponent,
page,
pageSize
} = this.getResolvedState(nextProps, nextState)
// Determine Header Groups
let hasHeaderGroups = false
columns.forEach(column => {
if (column.columns) {
hasHeaderGroups = true
}
})
// Build Header Groups
const headerGroups = []
let currentSpan = []
// A convenience function to add a header and reset the currentSpan
const addHeader = (columns, column = columns[0]) => {
headerGroups.push({
...this.props.column,
...column,
columns: columns
})
currentSpan = []
}
const noSubExpanderColumns = columns.map(col => {
return {
...col,
columns: col.columns ? col.columns.filter(d => !d.expander) : undefined
}
})
let expanderColumnIndex = columns.findIndex(col => col.expander)
const needsExpander = (SubComponent || pivotBy.length) && expanderColumnIndex === -1
const columnsWithExpander = needsExpander ? [{expander: true}, ...noSubExpanderColumns] : noSubExpanderColumns
if (needsExpander) {
expanderColumnIndex = 0
}
const makeDecoratedColumn = (column) => {
const dcol = {
...this.props.column,
...column
}
if (dcol.expander) {
dcol.width = expanderColumnWidth
return dcol
}
if (typeof dcol.accessor === 'string') {
dcol.id = dcol.id || dcol.accessor
const accessorString = dcol.accessor
dcol.accessor = row => _.get(row, accessorString)
return dcol
}
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.')
}
if (!dcol.accessor) {
dcol.accessor = d => undefined
}
// Ensure minWidth is not greater than maxWidth if set
if (dcol.maxWidth < dcol.minWidth) {
dcol.minWidth = dcol.maxWidth
}
return dcol
}
// Decorate the columns
const decorateAndAddToAll = (col) => {
const decoratedColumn = makeDecoratedColumn(col)
allDecoratedColumns.push(decoratedColumn)
return decoratedColumn
}
let allDecoratedColumns = []
const decoratedColumns = columnsWithExpander.map((column, i) => {
if (column.columns) {
return {
...column,
columns: column.columns.map(decorateAndAddToAll)
}
} else {
return decorateAndAddToAll(column)
}
})
// Build the visible columns, headers and flat column list
let visibleColumns = decoratedColumns.slice()
let allVisibleColumns = []
visibleColumns = visibleColumns.map((column, i) => {
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 => {
return column.columns ? column.columns.length : pivotBy.indexOf(column.id) > -1 ? false : _.getFirstDefined(column.show, true)
})
// Move the pivot columns into a single column if needed
if (pivotBy.length) {
const pivotColumns = []
for (var i = 0; i < allDecoratedColumns.length; i++) {
if (pivotBy.indexOf(allDecoratedColumns[i].id) > -1) {
pivotColumns.push(allDecoratedColumns[i])
}
}
const pivotColumn = {
...pivotColumns[0],
pivotColumns,
expander: true
}
visibleColumns[expanderColumnIndex] = pivotColumn
}
// Build flast list of allVisibleColumns and HeaderGroups
visibleColumns.forEach((column, i) => {
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
let resolvedData = data.map((d, i) => {
const row = {
__original: d,
__index: i
}
allDecoratedColumns.forEach(column => {
if (column.expander) return
row[column.id] = column.accessor(d)
})
return row
})
// 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
}
let standardColumns = pivotBy.length ? allVisibleColumns.slice(1) : allVisibleColumns
const aggregatingColumns = standardColumns.filter(d => d.aggregate)
let pivotColumn
if (pivotBy.length) {
pivotColumn = allVisibleColumns[0]
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]) => {
return {
[pivotIDKey]: keys[i],
[pivotValKey]: key,
[keys[i]]: key,
[subRowsKey]: value
}
}
)
// Recurse into the subRows
groupedRows = groupedRows.map(rowGroup => {
let subRows = groupRecursively(rowGroup[subRowsKey], keys, i + 1)
return {
...rowGroup,
[subRowsKey]: subRows,
...aggregate(subRows)
}
})
return groupedRows
}
resolvedData = groupRecursively(resolvedData, pivotBy)
}
const newPages = Math.ceil(resolvedData.length / pageSize)
return {
resolvedData,
pivotColumn,
allVisibleColumns,
headerGroups,
allDecoratedColumns,
hasHeaderGroups,
page: (page + 1) > newPages ? newPages - 1 : page
}
},
getSortedData (nextProps, nextState) {
const {
manual,
sorting,
allDecoratedColumns,
resolvedData
} = this.getResolvedState(nextProps, nextState)
const resolvedSorting = sorting.length ? sorting : this.getInitSorting(allDecoratedColumns)
// Resolve the data from either manual data or sorted data
return {
resolvedSorting,
sortedData: manual ? resolvedData : this.sortData(resolvedData, resolvedSorting)
}
},
fireOnChange () {
this.props.onChange(this.getResolvedState(), this)
},
getPropOrState (key) {
return _.getFirstDefined(this.props[key], this.state[key])
},
getStateOrProp (key) {
return _.getFirstDefined(this.state[key], this.props[key])
},
getInitSorting (columns) {
if (!columns) {
return []
}
const initSorting = columns.filter(d => {
return typeof d.sort !== 'undefined'
}).map(d => {
return {
id: d.id,
asc: d.sort === 'asc'
}
})
return initSorting
// return initSorting.length ? initSorting : [{
// id: columns.find(d => d.id).id,
// asc: true
// }]
},
sortData (data, sorting) {
const sorted = _.orderBy(data, sorting.map(sort => {
return row => {
if (row[sort.id] === null || row[sort.id] === undefined) {
return -Infinity
}
return typeof row[sort.id] === 'string' ? row[sort.id].toLowerCase() : row[sort.id]
}
}), sorting.map(d => d.asc ? 'asc' : 'desc'))
return sorted.map(row => {
if (!row[this.props.subRowsKey]) {
return row
}
return {
...row,
[this.props.subRowsKey]: this.sortData(row[this.props.subRowsKey], sorting)
}
})
},
getMinRows () {
return _.getFirstDefined(this.props.minRows, this.getStateOrProp('pageSize'))
},
// User actions
onPageChange (page) {
const { onPageChange } = this.props
if (onPageChange) {
return onPageChange(page)
}
this.setStateWithData({
expandedRows: {},
page
}, () => {
this.fireOnChange()
})
},
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)
if (onPageSizeChange) {
return onPageSizeChange(newPageSize, newPage)
}
this.setStateWithData({
pageSize: newPageSize,
page: newPage
}, () => {
this.fireOnChange()
})
},
sortColumn (column, additive) {
const { sorting } = this.getResolvedState()
const { onSortingChange } = this.props
if (onSortingChange) {
return onSortingChange(column, additive)
}
let newSorting = _.clone(sorting || [])
if (_.isArray(column)) {
const existingIndex = newSorting.findIndex(d => d.id === column[0].id)
if (existingIndex > -1) {
const existing = newSorting[existingIndex]
if (existing.asc) {
column.forEach((d, i) => {
newSorting[existingIndex + i].asc = false
})
} else {
if (additive) {
newSorting.splice(existingIndex, column.length)
} else {
column.forEach((d, i) => {
newSorting[existingIndex + i].asc = true
})
}
}
if (!additive) {
newSorting = newSorting.slice(existingIndex, column.length)
}
} else {
if (additive) {
newSorting = newSorting.concat(column.map(d => ({
id: d.id,
asc: true
})))
} else {
newSorting = column.map(d => ({
id: d.id,
asc: true
}))
}
}
} else {
const existingIndex = newSorting.findIndex(d => d.id === column.id)
if (existingIndex > -1) {
const existing = newSorting[existingIndex]
if (existing.asc) {
existing.asc = false
if (!additive) {
newSorting = [existing]
}
} else {
if (additive) {
newSorting.splice(existingIndex, 1)
} else {
existing.asc = true
newSorting = [existing]
}
}
} else {
if (additive) {
newSorting.push({
id: column.id,
asc: true
})
} else {
newSorting = [{
id: column.id,
asc: true
}]
}
}
}
this.setStateWithData({
page: ((!sorting.length && newSorting.length) || !additive) ? 0 : this.state.page,
sorting: newSorting
}, () => {
this.fireOnChange()
})
}
}
-270
View File
@@ -1,270 +0,0 @@
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],
defaultPage: 0,
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,
Placeholder: undefined,
// All Columns
sortable: undefined, // use table default
resizable: undefined, // use table default
filterable: undefined, // use table default
show: true,
minWidth: 100,
minResizeWidth: 11,
// 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',
pageJumpText: 'jump to page',
rowsSelectorText: 'rows per page',
// 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, column }) => (
<input
type="text"
style={{
width: '100%',
}}
placeholder={column.Placeholder}
value={filter ? filter.value : ''}
onChange={event => onChange(event.target.value)}
/>
),
ExpanderComponent: ({ isExpanded }) => (
<div className={classnames('rt-expander', isExpanded && '-open')}>&bull;</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>&nbsp;</span>,
}
View File
-199
View File
@@ -1,199 +0,0 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import set from 'lodash.set'
import get from 'lodash.get'
/*
AvancedExpandTableHOC for ReactTable
HOC which allows any Cell in the row to toggle the row's
SubComponent. Also allows the SubComponent to toggle itself.
Expand functions available to any SubComponent or Column Cell:
toggleRowSubComponent
showRowSubComponent
hideRowSubComponent
Each Column Renderer (E.g. Cell ) gets the expand functions in its props
And Each SubComponent gets the expand functions in its props
Expand functions takes the `rowInfo` given to each
Column Renderer and SubComponent already by ReactTable.
*/
export const subComponentWithToggle = (SubComponent, expandFuncs) => props => (
<SubComponent {...props} {...expandFuncs} />
)
// each cell in the column gets passed the function to toggle a sub component
export const columnsWithToggle = (columns, expandFuncs) =>
columns.map(column => {
if (column.columns) {
return {
...column,
columns: columnsWithToggle(column.columns, expandFuncs),
}
}
return {
...column,
getProps () {
return {
...expandFuncs,
}
},
}
})
export const advancedExpandTableHOC = TableComponent =>
class AdvancedExpandTable extends Component {
constructor (props) {
super(props)
this.state = {
expanded: {},
}
this.toggleRowSubComponent = this.toggleRowSubComponent.bind(this)
this.showRowSubComponent = this.showRowSubComponent.bind(this)
this.hideRowSubComponent = this.hideRowSubComponent.bind(this)
this.getTdProps = this.getTdProps.bind(this)
this.fireOnExpandedChange = this.fireOnExpandedChange.bind(this)
this.expandFuncs = {
toggleRowSubComponent: this.toggleRowSubComponent,
showRowSubComponent: this.showRowSubComponent,
hideRowSubComponent: this.hideRowSubComponent,
}
}
// after initial render if we get new
// data, columns, page changes, etc.
// we reset expanded state.
UNSAFE_componentWillReceiveProps () {
this.setState({
expanded: {},
})
}
static propTypes = {
columns: PropTypes.array.isRequired,
SubComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element])
.isRequired,
onExpandedChange: PropTypes.func,
};
static defaultProps = {
onExpandedChange: null,
};
static DisplayName = 'AdvancedExpandTable';
// since we pass the expand functions to each Cell,
// we need to filter it out from being passed as an
// actual DOM attribute. See getProps in columnsWithToggle above.
static TdComponent ({
toggleRowSubComponent,
showRowSubComponent,
hideRowSubComponent,
...rest
}) {
return <TableComponent.defaultProps.TdComponent {...rest} />
}
fireOnExpandedChange (rowInfo, e) {
// fire callback once state has changed.
if (this.props.onExpandedChange) {
this.props.onExpandedChange(rowInfo, e)
}
}
resolveNewTableState (rowInfoOrNestingPath, e, expandType) {
// derive nestingPath if only rowInfo is passed
let nestingPath = rowInfoOrNestingPath
if (rowInfoOrNestingPath.nestingPath) {
nestingPath = rowInfoOrNestingPath.nestingPath
}
this.setState(
prevState => {
const isExpanded = get(prevState.expanded, nestingPath)
// since we do not support nested rows, a shallow clone is okay.
const newExpanded = { ...prevState.expanded }
switch (expandType) {
case 'show':
set(newExpanded, nestingPath, {})
break
case 'hide':
set(newExpanded, nestingPath, false)
break
default:
// toggle
set(newExpanded, nestingPath, isExpanded ? false : {})
}
return {
...prevState,
expanded: newExpanded,
}
},
() => this.fireOnExpandedChange(rowInfoOrNestingPath, e)
)
}
toggleRowSubComponent (rowInfo, e) {
this.resolveNewTableState(rowInfo, e)
}
showRowSubComponent (rowInfo, e) {
this.resolveNewTableState(rowInfo, e, 'show')
}
hideRowSubComponent (rowInfo, e) {
this.resolveNewTableState(rowInfo, e, 'hide')
}
getTdProps (tableState, rowInfo, column) {
const { expander } = column
if (!expander) {
// no overrides
return {}
}
return {
// only override onClick for column Td
onClick: e => {
this.toggleRowSubComponent(rowInfo, e)
},
}
}
getWrappedInstance () {
if (!this.wrappedInstance) { console.warn('AdvancedExpandTable - No wrapped instance') }
if (this.wrappedInstance.getWrappedInstance) {
return this.wrappedInstance.getWrappedInstance()
}
return this.wrappedInstance
}
render () {
const {
columns, SubComponent, onExpandedChange, ...rest
} = this.props
const wrappedColumns = columnsWithToggle(columns, this.expandFuncs)
const WrappedSubComponent = subComponentWithToggle(
SubComponent,
this.expandFuncs
)
return (
<TableComponent
{...rest}
columns={wrappedColumns}
expanded={this.state.expanded}
getTdProps={this.getTdProps}
SubComponent={WrappedSubComponent}
TdComponent={AdvancedExpandTable.TdComponent}
/>
)
}
}
-230
View File
@@ -1,230 +0,0 @@
/* eslint-disable */
import React from 'react'
import left from './left.svg'
import right from './right.svg'
const defaultFoldIconComponent = ({ collapsed }) => {
const style = { width: 25 }
if (collapsed) return <img src={right} style={style} alt="right" />
return <img src={left} style={style} alt="left" />
}
const defaultFoldButtonComponent = ({ header, collapsed, icon, onClick }) => {
const style = {
marginLeft: '0px',
marginTop: '-5px',
marginBottom: '-8px',
float: 'left',
cursor: 'pointer',
}
return (
<div>
<div style={style} onClick={onClick}>
{icon}
</div>
{!collapsed && <div>{header}</div>}
</div>
)
}
export default ReactTable => {
const wrapper = class RTFoldableTable extends React.Component {
constructor(props, context) {
super(props, context)
this.state = {
folded: props.onFoldChange ? undefined : {},
resized: props.resized || [],
}
}
UNSAFE_componentWillReceiveProps(newProps) {
if (this.state.resized !== newProps.resized) {
this.setState(p => ({ resized: newProps.resized }))
}
}
onResizedChange = resized => {
const { onResizedChange } = this.props
if (onResizedChange) onResizedChange(resized)
else {
this.setState(p => ({ resized }))
}
}
removeResized = column => {
const { id } = column
if (!id) return
const { resized } = this.state
if (!resized) return
const rs = resized.find(r => r.id === id)
if (!rs) return
const newResized = resized.filter(r => r !== rs)
this.onResizedChange(newResized)
}
// this is so we can expose the underlying ReactTable.
getWrappedInstance = () => {
if (!this.wrappedInstance) console.warn('RTFoldableTable - No wrapped instance')
if (this.wrappedInstance.getWrappedInstance) return this.wrappedInstance.getWrappedInstance()
return this.wrappedInstance
}
getCopiedKey = key => {
const { foldableOriginalKey } = this.props
return `${foldableOriginalKey}${key}`
}
copyOriginals = column => {
const { FoldedColumn } = this.props
// Stop copy if the column already copied
if (column.original_Header) return
Object.keys(FoldedColumn).forEach(k => {
const copiedKey = this.getCopiedKey(k)
if (k === 'Cell') column[copiedKey] = column[k] ? column[k] : c => c.value
else column[copiedKey] = column[k]
})
// Copy sub Columns
if (column.columns && !column.original_Columns) column.original_Columns = column.columns
// Copy Header
if (!column.original_Header) column.original_Header = column.Header
}
restoreToOriginal = column => {
const { FoldedColumn } = this.props
Object.keys(FoldedColumn).forEach(k => {
// ignore header as handling by foldableHeaderRender
if (k === 'Header') return
const copiedKey = this.getCopiedKey(k)
column[k] = column[copiedKey]
})
if (column.columns && column.original_Columns) column.columns = column.original_Columns
}
getState = () => (this.props.onFoldChange ? this.props.folded : this.state.folded)
isFolded = col => {
const folded = this.getState()
return folded[col.id] === true
}
foldingHandler = col => {
if (!col || !col.id) return
const { onFoldChange } = this.props
const folded = this.getState()
const { id } = col
const newFold = Object.assign({}, folded)
newFold[id] = !newFold[id]
// Remove the Resized if have
this.removeResized(col)
if (onFoldChange) onFoldChange(newFold)
else {
this.setState(previous => ({ folded: newFold }))
}
}
foldableHeaderRender = cell => {
const { FoldButtonComponent, FoldIconComponent } = this.props
const { column } = cell
const collapsed = this.isFolded(column)
const icon = React.createElement(FoldIconComponent, { collapsed })
const onClick = () => this.foldingHandler(column)
return React.createElement(FoldButtonComponent, {
header: column.original_Header,
collapsed,
icon,
onClick,
})
}
applyFoldableForColumn = column => {
const collapsed = this.isFolded(column)
const { FoldedColumn } = this.props
// Handle Column Header
if (column.columns) {
if (collapsed) {
column.columns = [FoldedColumn]
column.width = FoldedColumn.width
column.style = FoldedColumn.style
} else this.restoreToOriginal(column)
}
// Handle Normal Column.
else if (collapsed) column = Object.assign(column, FoldedColumn)
else {
this.restoreToOriginal(column)
}
}
applyFoldableForColumns = columns =>
columns.map((col, index) => {
if (!col.foldable) return col
// If col don't have id then generate id based on index
if (!col.id) col.id = `col_${index}`
this.copyOriginals(col)
// Replace current header with internal header render.
col.Header = c => this.foldableHeaderRender(c)
// apply foldable
this.applyFoldableForColumn(col)
// return the new column out
return col
})
render() {
const {
columns: originalCols,
FoldButtonComponent,
FoldIconComponent,
FoldedColumn,
...rest
} = this.props
const columns = this.applyFoldableForColumns([...originalCols])
const extra = {
columns,
onResizedChange: this.onResizedChange,
resized: this.state.resized,
}
return <ReactTable {...rest} {...extra} ref={r => (this.wrappedInstance = r)} />
}
}
wrapper.displayName = 'RTFoldableTable'
wrapper.defaultProps = {
FoldIconComponent: defaultFoldIconComponent,
FoldButtonComponent: defaultFoldButtonComponent,
foldableOriginalKey: 'original_',
FoldedColumn: {
Cell: c => '',
width: 30,
sortable: false,
resizable: false,
filterable: false,
},
}
return wrapper
}
-1
View File
@@ -1 +0,0 @@
<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'><svg height="512px" id="Layer_1" style="enable-background:new 0 0 512 512;" version="1.1" viewBox="0 0 512 512" width="512px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M327.3,98.9l-2.1,1.8l-156.5,136c-5.3,4.6-8.6,11.5-8.6,19.2c0,7.7,3.4,14.6,8.6,19.2L324.9,411l2.6,2.3 c2.5,1.7,5.5,2.7,8.7,2.7c8.7,0,15.8-7.4,15.8-16.6h0V112.6h0c0-9.2-7.1-16.6-15.8-16.6C332.9,96,329.8,97.1,327.3,98.9z"/></svg>

Before

Width:  |  Height:  |  Size: 583 B

-1
View File
@@ -1 +0,0 @@
<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'><svg height="512px" id="Layer_1" style="enable-background:new 0 0 512 512;" version="1.1" viewBox="0 0 512 512" width="512px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M184.7,413.1l2.1-1.8l156.5-136c5.3-4.6,8.6-11.5,8.6-19.2c0-7.7-3.4-14.6-8.6-19.2L187.1,101l-2.6-2.3 C182,97,179,96,175.8,96c-8.7,0-15.8,7.4-15.8,16.6h0v286.8h0c0,9.2,7.1,16.6,15.8,16.6C179.1,416,182.2,414.9,184.7,413.1z"/></svg>

Before

Width:  |  Height:  |  Size: 585 B

-119
View File
@@ -1,119 +0,0 @@
/* eslint-disable */
import React from 'react'
const defaultSelectInputComponent = props => {
return (
<input
type={props.selectType || 'checkbox'}
aria-label={`${props.checked ? 'Un-select':'Select'} row with id:${props.id}` }
checked={props.checked}
id={props.id}
onClick={e => {
const { shiftKey } = e
e.stopPropagation()
props.onClick(props.id, shiftKey, props.row)
}}
onChange={() => {}}
/>
)
}
export default (Component, options) => {
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,
row,
id: `select-${row[keyField]}`
}
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,
id: 'select-all'
}
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 = (options !== undefined && options.floatingLeft === true) ? [...originalCols, select] : [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: 'checkbox',
SelectInputComponent: defaultSelectInputComponent,
SelectAllInputComponent: defaultSelectInputComponent,
}
return wrapper
}
-79
View File
@@ -1,79 +0,0 @@
/* eslint-disable */
import React from 'react'
export default Component => {
const wrapper = class RTTreeTable extends React.Component {
constructor(props) {
super(props)
this.getWrappedInstance.bind(this)
this.TrComponent.bind(this)
this.getTrProps.bind(this)
}
// this is so we can expose the underlying ReactTable to get at the sortedData for selectAll
getWrappedInstance = () => {
if (!this.wrappedInstance) console.warn('RTTreeTable - No wrapped instance')
if (this.wrappedInstance.getWrappedInstance) return this.wrappedInstance.getWrappedInstance()
else return this.wrappedInstance
}
TrComponent = props => {
const { ri, ...rest } = props
if (ri && ri.groupedByPivot) {
const cell = { ...props.children[ri.level] }
cell.props.style.flex = 'unset'
cell.props.style.width = '100%'
cell.props.style.maxWidth = 'unset'
cell.props.style.paddingLeft = `${this.props.treeTableIndent * ri.level}px`
// cell.props.style.backgroundColor = '#DDD';
cell.props.style.borderBottom = '1px solid rgba(128,128,128,0.2)'
return (
<div className={`rt-tr ${rest.className}`} role="row" 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) || rest.pivotBy.includes(col.id))) {
column = {
id: col.id,
accessor: col.accessor,
width: `${treeTableIndent}px`,
show: false,
Header: '',
Expander: col.Expander,
PivotValue: col.PivotValue,
Pivot: col.Pivot,
}
}
return column
}),
TrComponent,
getTrProps,
}
return <Component {...rest} {...extra} ref={r => (this.wrappedInstance = r)} />
}
}
wrapper.displayName = 'RTTreeTable'
wrapper.defaultProps = {
treeTableIndent: 10,
}
return wrapper
}
+619 -621
View File
File diff suppressed because it is too large Load Diff
+31 -123
View File
@@ -2,24 +2,12 @@ $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-width: 0
.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
@@ -28,28 +16,12 @@ input-select-style()
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)
@@ -58,9 +30,7 @@ input-select-style()
.rt-th
.rt-td
padding: 5px 5px
line-height: normal
position: relative
color: black
border-right: 1px solid alpha(black, .05)
transition box-shadow .3s $easeOutBack
box-shadow:inset 0 0 0 0 transparent
@@ -72,49 +42,9 @@ input-select-style()
cursor: pointer
&:last-child
border-right: 0
.rt-th:focus
outline-width: 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)
@@ -124,16 +54,13 @@ input-select-style()
border-right:1px solid alpha(black, .02)
&:last-child
border-right:0
.rt-expandable
.rt-pivot
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
@@ -174,27 +101,6 @@ input-select-style()
&.-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)
@@ -211,17 +117,12 @@ input-select-style()
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%
height: 100%
border: 0
border-radius: 3px
padding: 6px
@@ -230,7 +131,7 @@ input-select-style()
background: alpha(black, .1)
transition: all .1s ease
cursor: pointer
outline-width: 0
outline:none
&[disabled]
opacity: .5
@@ -269,18 +170,6 @@ input-select-style()
.-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
@@ -291,7 +180,7 @@ input-select-style()
bottom:0
background: alpha(white, .8)
transition: all .3s ease
z-index: -1
z-index: 2
opacity: 0
pointer-events: none
@@ -309,14 +198,33 @@ input-select-style()
&.-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
input
select
appearance: none
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
.select-wrap
position:relative
display:inline-block
select
padding: 5px 15px 5px 7px
min-width:100px
&:after
content: ''
position: absolute
right: 8px
top: 50%
transform: translate(0, -50%)
border-color: #999 transparent transparent
border-style: solid
border-width: 5px 5px 2.5px
-128
View File
@@ -1,128 +0,0 @@
export default Base =>
class extends Base {
UNSAFE_componentWillMount () {
this.setStateWithData(this.getDataModel(this.getResolvedState(), true))
}
componentDidMount () {
this.fireFetchData()
}
UNSAFE_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, oldState.data !== newState.data))
}
}
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 = newResolvedState.manual ? 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()
}
})
}
}
-692
View File
@@ -1,692 +0,0 @@
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, dataChanged) {
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
}
// // If the data hasn't changed, just use the cached data
let resolvedData = this.resolvedData
// If the data has changed, run the data resolver and cache the result
if (!this.resolvedData || dataChanged) {
resolvedData = resolveData(data)
this.resolvedData = resolvedData
}
// Use the resolved data
resolvedData = resolvedData.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,
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, allDecoratedColumns),
sorted,
sortMethodsByColumnID
),
}
}
fireFetchData () {
// determine the current state, preferring certain state values over props
const currentState = {
...this.getResolvedState(),
page: this.getStateOrProp('page'),
pageSize: this.getStateOrProp('pageSize'),
filtered: this.getStateOrProp('filtered'),
}
this.props.onFetchData(currentState, 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, column } = this.props
const { resized, currentlyResizing, columns } = this.getResolvedState()
const currentColumn = columns.find(
c => c.accessor === currentlyResizing.id || c.id === currentlyResizing.id
)
const minResizeWidth =
currentColumn && currentColumn.minResizeWidth != null
? currentColumn.minResizeWidth
: column.minResizeWidth
// 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
}
const newWidth = Math.max(
currentlyResizing.parentWidth + pageX - currentlyResizing.startX,
minResizeWidth
)
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,
})
}
}
}
+71 -129
View File
@@ -1,119 +1,34 @@
import React, { Component } from 'react'
import React from 'react'
import classnames from 'classnames'
//
// import _ from './utils'
const defaultButton = props => (
<button type="button" {...props} className="-btn">
{props.children}
</button>
const defaultButton = (props) => (
<button {...props} className='-btn'>{props.children}</button>
)
export default class ReactTablePagination extends Component {
static defaultProps = {
PreviousComponent: defaultButton,
NextComponent: defaultButton,
renderPageJump: ({
onChange, value, onBlur, onKeyPress, inputType, pageJumpText,
}) => (
<div className="-pageJump">
<input
aria-label={pageJumpText}
type={inputType}
onChange={onChange}
value={value}
onBlur={onBlur}
onKeyPress={onKeyPress}
/>
</div>
),
renderCurrentPage: page => <span className="-currentPage">{page + 1}</span>,
renderTotalPagesCount: pages => <span className="-totalPages">{pages || 1}</span>,
renderPageSizeOptions: ({
pageSize,
pageSizeOptions,
rowsSelectorText,
onPageSizeChange,
rowsText,
}) => (
<span className="select-wrap -pageSizeOptions">
<select
aria-label={rowsSelectorText}
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} ${rowsText}`}
</option>
))}
</select>
</span>
),
}
constructor (props) {
super(props)
this.getSafePage = this.getSafePage.bind(this)
this.changePage = this.changePage.bind(this)
this.applyPage = this.applyPage.bind(this)
this.state = {
page: props.page,
export default React.createClass({
getInitialState () {
return {
page: this.props.page
}
}
UNSAFE_componentWillReceiveProps (nextProps) {
if (this.props.page !== nextProps.page) {
this.setState({ page: nextProps.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)
}
}
this.setState({page})
this.props.onPageChange(page)
},
applyPage (e) {
if (e) {
e.preventDefault()
}
e && e.preventDefault()
const page = this.state.page
this.changePage(page === '' ? this.props.page : page)
}
getPageJumpProperties () {
return {
onKeyPress: e => {
if (e.which === 13 || e.keyCode === 13) {
this.applyPage()
}
},
onBlur: this.applyPage,
value: this.state.page === '' ? '' : this.state.page + 1,
onChange: e => {
const val = e.target.value
const page = val - 1
if (val === '') {
return this.setState({ page: val })
}
this.setState({ page: this.getSafePage(page) })
},
inputType: this.state.page === '' ? 'text' : 'number',
pageJumpText: this.props.pageJumpText,
}
}
},
render () {
const {
// Computed
@@ -128,19 +43,18 @@ export default class ReactTablePagination extends Component {
canNext,
onPageSizeChange,
className,
PreviousComponent,
NextComponent,
renderPageJump,
renderCurrentPage,
renderTotalPagesCount,
renderPageSizeOptions,
PreviousComponent = defaultButton,
NextComponent = defaultButton
} = this.props
return (
<div className={classnames(className, '-pagination')} style={this.props.style}>
<div className="-previous">
<div
className={classnames(className, '-pagination')}
style={this.props.paginationStyle}
>
<div className='-previous'>
<PreviousComponent
onClick={() => {
onClick={(e) => {
if (!canPrevious) return
this.changePage(page - 1)
}}
@@ -149,24 +63,52 @@ export default class ReactTablePagination extends Component {
{this.props.previousText}
</PreviousComponent>
</div>
<div className="-center">
<span className="-pageInfo">
{this.props.pageText}{' '}
{showPageJump ? renderPageJump(this.getPageJumpProperties()) : renderCurrentPage(page)}{' '}
{this.props.ofText} {renderTotalPagesCount(pages)}
<div className='-center'>
<span className='-pageInfo'>
{this.props.pageText} {showPageJump ? (
<form className='-pageJump'
onSubmit={this.applyPage}
>
<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}
/>
</form>
) : (
<span className='-currentPage'>{page + 1}</span>
)} {this.props.ofText} <span className='-totalPages'>{pages}</span>
</span>
{showPageSizeOptions &&
renderPageSizeOptions({
pageSize,
rowsSelectorText: this.props.rowsSelectorText,
pageSizeOptions,
onPageSizeChange,
rowsText: this.props.rowsText,
})}
{showPageSizeOptions && (
<span className='select-wrap -pageSizeOptions'>
<select
onChange={(e) => onPageSizeChange(Number(e.target.value))}
value={pageSize}
>
{pageSizeOptions.map((option, i) => {
return (
<option
key={i}
value={option}>
{option} {this.props.rowsText}
</option>
)
})}
</select>
</span>
)}
</div>
<div className="-next">
<div className='-next'>
<NextComponent
onClick={() => {
onClick={(e) => {
if (!canNext) return
this.changePage(page + 1)
}}
@@ -178,4 +120,4 @@ export default class ReactTablePagination extends Component {
</div>
)
}
}
})
-169
View File
@@ -1,169 +0,0 @@
import PropTypes from 'prop-types'
export default {
// General
data: PropTypes.any,
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,
minResizeWidth: 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.func,
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,
pageJumpText: PropTypes.node,
rowsSelectorText: PropTypes.node,
// Components
TableComponent: PropTypes.elementType,
TheadComponent: PropTypes.elementType,
TbodyComponent: PropTypes.elementType,
TrGroupComponent: PropTypes.elementType,
TrComponent: PropTypes.elementType,
ThComponent: PropTypes.elementType,
TdComponent: PropTypes.elementType,
TfootComponent: PropTypes.elementType,
FilterComponent: PropTypes.elementType,
ExpanderComponent: PropTypes.elementType,
PivotValueComponent: PropTypes.elementType,
AggregatedComponent: PropTypes.elementType,
// this is a computed default generated using
PivotComponent: PropTypes.elementType,
// the ExpanderComponent and PivotValueComponent at run-time in methods.js
PaginationComponent: PropTypes.elementType,
PreviousComponent: PropTypes.elementType,
NextComponent: PropTypes.elementType,
LoadingComponent: PropTypes.elementType,
NoDataComponent: PropTypes.elementType,
ResizerComponent: PropTypes.elementType,
PadRowComponent: PropTypes.elementType,
}
+41 -103
View File
@@ -15,11 +15,7 @@ export default {
makeTemplateComponent,
groupBy,
isArray,
splitProps,
compactObject,
isSortingDesc,
normalizeComponent,
asPx,
splitProps
}
function get (obj, path, def) {
@@ -30,9 +26,7 @@ function get (obj, path, def) {
let val
try {
val = pathObj.reduce((current, pathPart) => current[pathPart], obj)
} catch (e) {
// continue regardless of error
}
} catch (e) {}
return typeof val !== 'undefined' ? val : def
}
@@ -61,30 +55,35 @@ function last (arr) {
function range (n) {
const arr = []
for (let i = 0; i < n; i += 1) {
for (let i = 0; i < n; i++) {
arr.push(n)
}
return arr
}
function orderBy (arr, funcs, dirs, indexKey) {
return arr.sort((rowA, rowB) => {
for (let i = 0; i < funcs.length; i += 1) {
function orderBy (arr, funcs, dirs) {
return arr.sort((a, b) => {
for (let i = 0; i < funcs.length; i++) {
const comp = funcs[i]
const ca = comp(a)
const cb = comp(b)
const desc = dirs[i] === false || dirs[i] === 'desc'
const sortInt = comp(rowA, rowB)
if (sortInt) {
return desc ? -sortInt : sortInt
if (ca > cb) {
return desc ? -1 : 1
}
if (ca < cb) {
return desc ? 1 : -1
}
}
// Use the row index for tie breakers
return dirs[0] ? rowA[indexKey] - rowB[indexKey] : rowB[indexKey] - rowA[indexKey]
return dirs[0]
? a.__index - b.__index
: b.__index - b.__index
})
}
function remove (a, b) {
return a.filter((o, i) => {
const r = b(o)
return a.filter(function (o, i) {
var r = b(o)
if (r) {
a.splice(i, 1)
return true
@@ -95,21 +94,19 @@ function remove (a, b) {
function clone (a) {
try {
return JSON.parse(
JSON.stringify(a, (key, value) => {
if (typeof value === 'function') {
return value.toString()
}
return value
})
)
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) {
for (var i = 0; i < args.length; i++) {
if (typeof args[i] !== 'undefined') {
return args[i]
}
@@ -117,20 +114,20 @@ function getFirstDefined (...args) {
}
function sum (arr) {
return arr.reduce((a, b) => a + b, 0)
return arr.reduce((a, b) => {
return a + b
}, 0)
}
function makeTemplateComponent (compClass, displayName) {
if (!displayName) {
throw new Error('No displayName found for template component:', compClass)
}
const cmp = ({ children, className, ...rest }) => (
<div className={classnames(compClass, className)} {...rest}>
function makeTemplateComponent (compClass) {
return ({children, className, ...rest}) => (
<div
className={classnames(compClass, className)}
{...rest}
>
{children}
</div>
)
cmp.displayName = displayName
return cmp
}
function groupBy (xs, key) {
@@ -142,11 +139,6 @@ function groupBy (xs, key) {
}, {})
}
function asPx (value) {
value = Number(value)
return Number.isNaN(value) ? null : `${value}px`
}
function isArray (a) {
return Array.isArray(a)
}
@@ -157,81 +149,27 @@ function isArray (a) {
function makePathArray (obj) {
return flattenDeep(obj)
.join('.')
.replace(/\[/g, '.')
.replace(/\]/g, '')
.split('.')
.join('.')
.replace('[', '.')
.replace(']', '')
.split('.')
}
function flattenDeep (arr, newArr = []) {
if (!isArray(arr)) {
newArr.push(arr)
} else {
for (let i = 0; i < arr.length; i += 1) {
for (var i = 0; i < arr.length; i++) {
flattenDeep(arr[i], newArr)
}
}
return newArr
}
function splitProps ({ className, style, ...rest }) {
function splitProps ({className, style, ...rest}) {
return {
className,
style,
rest: rest || {},
rest
}
}
function compactObject (obj) {
const newObj = {}
if (obj) {
Object.keys(obj).map(key => {
if (
Object.prototype.hasOwnProperty.call(obj, key) &&
obj[key] !== undefined &&
typeof obj[key] !== 'undefined'
) {
newObj[key] = obj[key]
}
return true
})
}
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' ? (
isReactComponent(Comp) ? (
<Comp {...params} />
) : (
Comp(params)
)
) : (
fallback
)
}
function isClassComponent (component) {
return !!((
typeof component === 'function' &&
!!Object.getPrototypeOf(component).isReactComponent
))
}
function isFunctionComponent (component) {
return !!((
typeof component === 'function' &&
String(component).includes('return React.createElement')
))
}
function isReactComponent (component) {
return !!((
isClassComponent(component) ||
isFunctionComponent(component)
))
}
+170
View File
@@ -0,0 +1,170 @@
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
export default () => {
const data = _.map(_.range(5553), d => {
const statusChance = Math.random()
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
progress: Math.floor(Math.random() * 100),
status: statusChance > 0.66 ? 'relationship'
: statusChance > 0.33 ? 'complicated'
: 'single'
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Profile Progress',
accessor: 'progress',
render: row => (
<div
style={{
width: '100%',
height: '100%',
backgroundColor: '#dadada',
borderRadius: '2px'
}}
>
<div
style={{
width: `${row.value}%`,
height: '100%',
backgroundColor: row.value > 66 ? '#85cc00'
: row.value > 33 ? '#ffbf00'
: '#ff2e00',
borderRadius: '2px',
transition: 'all .2s ease-out'
}}
/>
</div>
)
}, {
header: 'Status',
accessor: 'status',
render: row => (
<span>
<span style={{
color: row.value === 'relationship' ? '#ff2e00'
: row.value === 'complicated' ? '#ffbf00'
: '#57d500',
transition: 'all .3s ease'
}}>
&#x25cf;
</span> {
row.value === 'relationship' ? 'In a relationship'
: row.value === 'complicated' ? `It's complicated`
: 'Single'
}
</span>
)
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
<CodeHighlight>{() => getCode()}</CodeHighlight>
</div>
)
}
function getCode () {
return `
import ReactTable from 'react-table'
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Profile Progress',
accessor: 'progress',
render: row => (
<div
style={{
width: '100%',
height: '100%',
backgroundColor: '#dadada',
borderRadius: '2px'
}}
>
<div
style={{
width: \`$\{row.value}%\`,
height: '100%',
backgroundColor: row.value > 66 ? '#85cc00'
: row.value > 33 ? '#ffbf00'
: '#ff2e00',
borderRadius: '2px',
transition: 'all .2s ease-out'
}}
/>
</div>
)
}, {
header: 'Status',
accessor: 'status',
render: row => (
<span>
<span style={{
color: row.value === 'relationship' ? '#ff2e00'
: row.value === 'complicated' ? '#ffbf00'
: '#57d500',
transition: 'all .3s ease'
}}>
&#x25cf;
</span> {
row.value === 'relationship' ? 'In a relationship'
: row.value === 'complicated' ? \`It's complicated\`
: 'Single'
}
</span>
)
}]
}]
return (
<ReactTable
data={data}
columns={columns}
defaultPageSize={10}
/>
)
`
}
+86
View File
@@ -0,0 +1,86 @@
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
export default () => {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30)
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
<CodeHighlight>{() => getCode()}</CodeHighlight>
</div>
)
}
function getCode () {
return `
import ReactTable from 'react-table'
// Create some column definitions
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
}]
}]
// Display your table!
return (
<ReactTable
data={data}
columns={columns}
defaultPageSize={10}
/>
)
`
}
+107
View File
@@ -0,0 +1,107 @@
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
export default () => {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30)
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName',
render: row => {
return <span>{row.aggregated ? '...' : row.value}</span>
}
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age',
aggregate: vals => _.round(_.mean(vals)),
render: row => {
return <span>{row.aggregated ? `${row.value} (avg)` : row.value}</span>
}
}]
}, {
expander: true
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
SubComponent={() => <span>Hello</span>}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
<CodeHighlight>{() => getCode()}</CodeHighlight>
</div>
)
}
function getCode () {
return `
import ReactTable from 'react-table'
// Create some column definitions
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName',
render: row => {
return <span>{row.aggregated ? '...' : row.value}</span>
}
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
expander: true
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age',
aggregate: vals => _.round(_.mean(vals)),
render: row => {
return <span>{row.aggregated ? \`$\{row.value} (avg)\` : row.value}</span>
}
}]
}]
return (
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
SubComponent={() => <span>Hello</span>}
pivotBy={['lastName']}
/>
)
`
}
+91
View File
@@ -0,0 +1,91 @@
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
export default () => {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30)
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName',
maxWidth: 200
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName,
width: 300
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age',
minWidth: 400
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
<CodeHighlight>{() => getCode()}</CodeHighlight>
</div>
)
}
function getCode () {
return `
import ReactTable from 'react-table'
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName',
maxWidth: 200
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName,
width: 300
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age',
minWidth: 400
}]
}]
return (
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
/>
)
`
}
+87
View File
@@ -0,0 +1,87 @@
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
export default () => {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30)
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age',
sort: 'desc'
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
<CodeHighlight>{() => getCode()}</CodeHighlight>
</div>
)
}
function getCode () {
return `
import ReactTable from 'react-table'
// Create some column definitions
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
}]
}]
// Display your table!
return (
<ReactTable
data={data}
columns={columns}
defaultPageSize={10}
/>
)
`
}
+140
View File
@@ -0,0 +1,140 @@
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import JSONTree from 'react-json-tree'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
const JSONtheme = {
scheme: 'monokai',
author: 'wimer hazenberg (http://www.monokai.nl)',
base00: '#272822',
base01: '#383830',
base02: '#49483e',
base03: '#75715e',
base04: '#a59f85',
base05: '#f8f8f2',
base06: '#f5f4f1',
base07: '#f9f8f5',
base08: '#f92672',
base09: '#fd971f',
base0A: '#f4bf75',
base0B: '#a6e22e',
base0C: '#a1efe4',
base0D: '#66d9ef',
base0E: '#ae81ff',
base0F: '#cc6633'
}
export default () => {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30)
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
>
{(state, makeTable, instance) => {
console.log(state)
return (
<div>
Look! This is the entire table state and component instance at your disposal!
<JSONTree
data={Object.assign({}, state, {children: 'function () {...}'})}
theme={JSONtheme}
invertTheme
/>
<br />
<br />
{makeTable()}
</div>
)
}}
</ReactTable>
</div>
<br />
<CodeHighlight>{() => getCode()}</CodeHighlight>
</div>
)
}
function getCode () {
return `
import ReactTable from 'react-table'
// Create some column definitions
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
}]
}]
// Display your table!
return (
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
>
{(state, makeTable, instance) => {
console.log(state)
return (
<div>
Look! This is the entire table state and component instance at your disposal!
<JSONTree
data={Object.assign({}, state, {children: 'function () {...}'})}
theme={JSONtheme}
invertTheme
/>
<br />
<br />
{makeTable()}
</div>
)
}}
</ReactTable>
)
`
}
+139
View File
@@ -0,0 +1,139 @@
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
export default () => {
const data = _.map(_.range(100000), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30),
visits: Math.floor(Math.random() * 100)
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age',
aggregate: vals => _.round(_.mean(vals)),
render: row => {
return <span>{row.aggregated ? `${row.value} (avg)` : row.value}</span>
}
}, {
header: 'Visits',
accessor: 'visits',
aggregate: vals => _.sum(vals)
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
data={data}
columns={columns}
className='-striped -highlight'
defaultPageSize={10}
pivotBy={['firstName', 'lastName']}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>You can put any component you want here, even another React Table!</em>
<br />
<br />
<ReactTable
data={data}
columns={columns}
defaultPageSize={3}
showPagination={false}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>It even has access to the row data: </em>
<CodeHighlight>{() => JSON.stringify(row, null, 2)}</CodeHighlight>
</div>
)
}}
/>
</div>
)
}}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
<CodeHighlight>{() => getCode()}</CodeHighlight>
</div>
)
}
function getCode () {
return `
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
}]
}]
export default (
<ReactTable
data={data}
columns={columns}
defaultPageSize={10}
pivotBy={['firstName', 'lastName']}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>You can put any component you want here, even another React Table!</em>
<br />
<br />
<ReactTable
data={data}
columns={columns}
defaultPageSize={3}
showPagination={false}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>It even has access to the row data: </em>
<CodeHighlight>{() => JSON.stringify(row, null, 2)}</CodeHighlight>
</div>
)
}}
/>
</div>
)
}}
/>
)
`
}
+121
View File
@@ -0,0 +1,121 @@
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
export default () => {
const data = _.map(_.range(10000), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30),
visits: Math.floor(Math.random() * 100)
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age',
aggregate: vals => _.round(_.mean(vals)),
render: row => {
return <span>{row.aggregated ? `${row.value} (avg)` : row.value}</span>
}
}, {
header: 'Visits',
accessor: 'visits',
aggregate: vals => _.sum(vals)
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
data={data}
columns={columns}
className='-striped -highlight'
defaultPageSize={10}
pivotBy={['firstName', 'lastName']}
// expandedRows={{
// 2: true,
// 3: {
// 2: true
// }
// }}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
<CodeHighlight>{() => getCode()}</CodeHighlight>
</div>
)
}
function getCode () {
return `
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
}]
}]
export default (
<ReactTable
data={data}
columns={columns}
defaultPageSize={10}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>You can put any component you want here, even another React Table!</em>
<br />
<br />
<ReactTable
data={data}
columns={columns}
defaultPageSize={3}
showPagination={false}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>It even has access to the row data: </em>
<CodeHighlight>{() => JSON.stringify(row, null, 2)}</CodeHighlight>
</div>
)
}}
/>
</div>
)
}}
/>
)
`
}
+139
View File
@@ -0,0 +1,139 @@
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
export default () => {
const data = _.map(_.range(1000), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30),
visits: Math.floor(Math.random() * 100)
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age',
aggregate: vals => _.round(_.mean(vals)),
render: row => {
return <span>{row.aggregated ? `${row.value} (avg)` : row.value}</span>
}
}, {
header: 'Visits',
accessor: 'visits',
aggregate: vals => _.sum(vals)
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
data={data}
columns={columns}
defaultPageSize={10}
className='-striped -highlight'
pivotBy={['firstName', 'lastName']}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>You can put any component you want here, even another React Table!</em>
<br />
<br />
<ReactTable
data={data}
columns={columns}
defaultPageSize={3}
showPagination={false}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>It even has access to the row data: </em>
<CodeHighlight>{() => JSON.stringify(row, null, 2)}</CodeHighlight>
</div>
)
}}
/>
</div>
)
}}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
<CodeHighlight>{() => getCode()}</CodeHighlight>
</div>
)
}
function getCode () {
return `
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
}]
}]
export default (
<ReactTable
data={data}
columns={columns}
defaultPageSize={10}
pivotBy={['firstName', 'lastName']}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>You can put any component you want here, even another React Table!</em>
<br />
<br />
<ReactTable
data={data}
columns={columns}
defaultPageSize={3}
showPagination={false}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>It even has access to the row data: </em>
<CodeHighlight>{() => JSON.stringify(row, null, 2)}</CodeHighlight>
</div>
)
}}
/>
</div>
)
}}
/>
)
`
}
+162
View File
@@ -0,0 +1,162 @@
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
const rawData = _.map(_.range(3424), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30)
}
})
// Now let's mock the server. It's job is simple: use the table model to sort and return the page data
const requestData = (pageSize, page, sorting) => {
return new Promise((resolve, reject) => {
// On the server, you'll likely use SQL or noSQL or some other query language to do this.
// For this mock, we'll just use lodash
const sortedData = _.orderBy(rawData, sorting.map(sort => {
return row => {
if (row[sort.id] === null || row[sort.id] === undefined) {
return -Infinity
}
return typeof row[sort.id] === 'string' ? row[sort.id].toLowerCase() : row[sort.id]
}
}), sorting.map(d => d.asc ? 'asc' : 'desc'))
// Be sure to send back the rows to be displayed and any other pertinent information, like how many pages there are total.
const res = {
rows: sortedData.slice(pageSize * page, (pageSize * page) + pageSize),
pages: Math.ceil(rawData.length / pageSize)
}
// Here we'll simulate a server response with 500ms of delay.
setTimeout(() => resolve(res), 500)
})
}
const ServerSide = React.createClass({
getInitialState () {
// To handle our data server-side, we need a few things in the state to help us out:
return {
data: [],
pages: null,
loading: true
}
},
fetchData (state, instance) {
console.log(state, instance)
// Whenever the table model changes, or the user sorts or changes pages, this method gets called and passed the current table model.
// You can set the `loading` prop of the table to true to use the built-in one or show you're own loading bar if you want.
this.setState({loading: true})
// Request the data however you want. Here, we'll use our mocked service we created earlier
requestData(state.pageSize, state.page, state.sorting)
.then((res) => {
// Now just get the rows of data to your React Table (and update anything else like total pages or loading)
this.setState({
data: res.rows,
pages: res.pages,
loading: false
})
})
},
render () {
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
columns={[{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}, {
header: 'Age',
accessor: 'age'
}]}
manual // Forces table not to paginate or sort automatically, so we can handle it server-side
defaultPageSize={10}
data={this.state.data} // Set the rows to be displayed
pages={this.state.pages} // Display the total number of pages
loading={this.state.loading} // Display the loading overlay when we need it
onChange={this.fetchData} // Request new data when things change
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
<CodeHighlight>{() => getCode()}</CodeHighlight>
</div>
)
}
})
export default () => (
<ServerSide />
)
function getCode () {
return `
import ReactTable from 'react-table'
import Axios from 'axios'
export default React.createClass({
getInitialState () {
// To handle our data server-side, we need to keep track of our table state
return {
data: [],
pages: null,
loading: true
}
},
fetchData (state, instance) {
// Whenever the table model changes (sorting, pagination, etc), this method gets called and passed the current table model.
// You can set the 'loading' prop of the table to true to use the built-in loading notice, or show you're own loading bar if you want.
this.setState({loading: true})
// Request the data from a server however you want! Be sure to send the bits of the table model that it may neeed.
Axios.post('mysite.com/data', {
pageSize: state.pageSize,
page: state.page,
sorting: state.sorting
})
.then((res) => {
// Now update your state!
this.setState({
data: res.rows,
pages: res.pages,
loading: false
})
})
},
render () {
return (
<ReactTable
columns={[{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}, {
header: 'Age',
accessor: 'age'
}]}
manual // Forces table not to paginate or sort automatically, so we can handle it server-side
defaultPageSize={10}
data={this.state.data} // Set the rows to be displayed
pages={this.state.pages} // Display the total number of pages
loading={this.state.loading} // Display the loading overlay when we need it
onChange={this.fetchData} // Request new data when things change
/>
}
})
`
}
+86
View File
@@ -0,0 +1,86 @@
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
export default () => {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30)
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
<CodeHighlight>{() => getCode()}</CodeHighlight>
</div>
)
}
function getCode () {
return `
import ReactTable from 'react-table'
// Create some column definitions
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
}]
}]
// Display your table!
return (
<ReactTable
data={data}
columns={columns}
defaultPageSize={10}
/>
)
`
}
+128
View File
@@ -0,0 +1,128 @@
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
export default () => {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30)
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>You can put any component you want here, even another React Table!</em>
<br />
<br />
<ReactTable
data={data}
columns={columns}
defaultPageSize={3}
showPagination={false}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>It even has access to the row data: </em>
<CodeHighlight>{() => JSON.stringify(row, null, 2)}</CodeHighlight>
</div>
)
}}
/>
</div>
)
}}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
<CodeHighlight>{() => getCode()}</CodeHighlight>
</div>
)
}
function getCode () {
return `
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
}]
}]
export default (
<ReactTable
data={data}
columns={columns}
defaultPageSize={10}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>You can put any component you want here, even another React Table!</em>
<br />
<br />
<ReactTable
data={data}
columns={columns}
defaultPageSize={3}
showPagination={false}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>It even has access to the row data: </em>
<CodeHighlight>{() => JSON.stringify(row, null, 2)}</CodeHighlight>
</div>
)
}}
/>
</div>
)
}}
/>
)
`
}
+21
View File
@@ -0,0 +1,21 @@
import React from 'react'
import '../utils/prism'
export default React.createClass({
render () {
const { language, children } = this.props
return (
<pre>
<code className={'language-' + (language || 'jsx')}>
{children()}
</code>
</pre>
)
},
componentDidMount () {
window.Prism.highlightAll()
},
componentDidUpdate () {
window.Prism.highlightAll()
}
})
File diff suppressed because one or more lines are too long
-1
View File
@@ -1 +0,0 @@
* https://github.com/tannerlinsley/react-table
+3453 -1885
View File
File diff suppressed because it is too large Load Diff