Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a4d2245fd | ||
|
|
2c2d2aa092 | ||
|
|
92321b6d0a | ||
|
|
0c15308d7a | ||
|
|
8cde0cafbf | ||
|
|
afab8a34cc | ||
|
|
969407254f | ||
|
|
a5a49709d4 | ||
|
|
71c25f571b | ||
|
|
b75055ef38 | ||
|
|
1079914996 | ||
|
|
5301355192 | ||
|
|
4c7e493f41 | ||
|
|
928233713e | ||
|
|
feda66196e | ||
|
|
c1b399d603 | ||
|
|
d59d7e4fba | ||
|
|
168a8e3f93 | ||
|
|
221164484f | ||
|
|
c7d2c36454 | ||
|
|
26961d0994 | ||
|
|
de6389cafc | ||
|
|
e0f9d98819 | ||
|
|
0365057446 | ||
|
|
ec25bfbb5a | ||
|
|
0a1c12faca | ||
|
|
1fddb1b97d | ||
|
|
1e04377de7 | ||
|
|
555c4fae9d | ||
|
|
0d8ca53b76 | ||
|
|
64db8e09d4 | ||
|
|
c5233c4404 | ||
|
|
d0d862f1e8 | ||
|
|
dd3f30b099 | ||
|
|
d5fc894dd7 | ||
|
|
dc771ff25f | ||
|
|
d38021d4b0 | ||
|
|
06648b2577 | ||
|
|
836f256031 | ||
|
|
188fc51336 | ||
|
|
474244ce41 | ||
|
|
b6074a9ab1 | ||
|
|
3278e1b05e | ||
|
|
2352cac4b8 | ||
|
|
d94f59a5fa | ||
|
|
7876a3876c | ||
|
|
02e65b4388 | ||
|
|
d9d49fa3de | ||
|
|
41784cd52d | ||
|
|
9048835bcc | ||
|
|
b12fc8fc88 | ||
|
|
76fde77b0f | ||
|
|
f50b0a47cf | ||
|
|
ac8b497671 | ||
|
|
c79806090a | ||
|
|
f55ce62041 | ||
|
|
4c9b44ab48 | ||
|
|
48869a65e7 | ||
|
|
3246336120 | ||
|
|
b12238d535 | ||
|
|
1f92ed8d4f | ||
|
|
cf59c644b4 | ||
|
|
a7e8e26c00 | ||
|
|
dd4c1e2df6 | ||
|
|
621c3bf092 | ||
|
|
72afabbd03 | ||
|
|
4aa07c33da | ||
|
|
d430d51888 | ||
|
|
4824b4c8cc | ||
|
|
60766cf261 | ||
|
|
fcdc3d88bc | ||
|
|
24a9efd670 | ||
|
|
bdb7d44438 | ||
|
|
7a6ed50b81 | ||
|
|
8f062550aa | ||
|
|
4e9eec3578 | ||
|
|
35b92567b5 | ||
|
|
a1f5b462d5 | ||
|
|
9e479e4d4c | ||
|
|
9fe806d8a7 | ||
|
|
083534149c | ||
|
|
8bd3daafcb | ||
|
|
6649b21abe | ||
|
|
3a8a037ee6 | ||
|
|
9e0361e511 | ||
|
|
0a62d86e5e | ||
|
|
3ff988861e | ||
|
|
f4067b86dd | ||
|
|
f70d453caa | ||
|
|
54f3cc791c | ||
|
|
05c56f0da4 | ||
|
|
ddf877bcac | ||
|
|
928ad11a07 | ||
|
|
0783837786 | ||
|
|
cf0f8bb729 | ||
|
|
1e849df999 | ||
|
|
62da8880e6 | ||
|
|
656522eb71 | ||
|
|
b0c50509ee | ||
|
|
01ca4518fc | ||
|
|
cdf806b3f6 | ||
|
|
0443644ccd | ||
|
|
f74ba3cc16 | ||
|
|
2e8596618a | ||
|
|
b2db31c9bd | ||
|
|
6a5400b247 | ||
|
|
ed6dd5af4c | ||
|
|
80aa2ea7f4 | ||
|
|
b310a2ebc4 | ||
|
|
bcfa658257 | ||
|
|
ad151b5ff0 | ||
|
|
3f1b0d36ed | ||
|
|
a6036004af | ||
|
|
913d214e94 | ||
|
|
2fbd0d49db | ||
|
|
fc47d4f258 | ||
|
|
6df336215d | ||
|
|
feec96359b | ||
|
|
33252adfab | ||
|
|
1cf9e49952 | ||
|
|
b585c4b8db | ||
|
|
710891f0c0 | ||
|
|
cb0000e588 | ||
|
|
d0bd56729b | ||
|
|
e4c819039f | ||
|
|
adc07de817 | ||
|
|
e94e88849a | ||
|
|
2dcfef884f | ||
|
|
d798584208 | ||
|
|
5759885983 | ||
|
|
e59ddc1f8d | ||
|
|
35e8636fd1 | ||
|
|
bb2f969db9 | ||
|
|
cd0222fcd2 | ||
|
|
93ceffbf26 | ||
|
|
879a6ac273 | ||
|
|
b285288849 | ||
|
|
05f4aaef2e | ||
|
|
2b9c546132 | ||
|
|
55ef8a9e7d | ||
|
|
189ee436f9 | ||
|
|
225a74770b | ||
|
|
fa425a162a | ||
|
|
e42b7bbd7d | ||
|
|
9efee144a8 | ||
|
|
56b721c185 | ||
|
|
e91bb91ea1 | ||
|
|
dadfcc121c | ||
|
|
8cec156d13 | ||
|
|
5c531095a9 | ||
|
|
8d4deb3496 | ||
|
|
646b701f93 | ||
|
|
3043cbe4b4 | ||
|
|
fcb82694bb | ||
|
|
e8c557d70e | ||
|
|
ff95c21440 | ||
|
|
2630161222 | ||
|
|
e67072edae | ||
|
|
fb569ad592 | ||
|
|
b957503612 | ||
|
|
3d9b7b1186 | ||
|
|
e3528fef38 | ||
|
|
6b192bd363 | ||
|
|
0725f2159d | ||
|
|
5d2deda246 | ||
|
|
2961eb8a18 | ||
|
|
d170adb6a7 | ||
|
|
d8aec06496 | ||
|
|
8efeef3b8b | ||
|
|
8004e7a85f | ||
|
|
84af88916a | ||
|
|
9846bf1905 | ||
|
|
bf88dda5dc | ||
|
|
7f5779a833 | ||
|
|
8792bd95a0 | ||
|
|
098b1fec51 | ||
|
|
750cfe3ac4 | ||
|
|
370f443347 | ||
|
|
67f8c9adf1 | ||
|
|
867cc25899 | ||
|
|
639630946c | ||
|
|
688afd2947 | ||
|
|
bbebf02a55 | ||
|
|
f4d3c2d7bb | ||
|
|
f8634e771e | ||
|
|
ba74ab3ce8 | ||
|
|
30ed0c82fc | ||
|
|
62f19aecf0 | ||
|
|
8dc4caff45 | ||
|
|
c2e935d75b | ||
|
|
f9a1cfae1e | ||
|
|
5ac2c1779d | ||
|
|
3b2432f535 | ||
|
|
7aa98887ef | ||
|
|
d26d82ecfb | ||
|
|
b76f9c956d | ||
|
|
2e3743b75f | ||
|
|
fdb3e77b00 | ||
|
|
d9248cef2b | ||
|
|
f4704b146c | ||
|
|
004186af24 | ||
|
|
0d0e239baa | ||
|
|
f61b19cb8a | ||
|
|
e1a46fb77e | ||
|
|
a9db5b1ac6 | ||
|
|
846fc0d84d | ||
|
|
87610c83fa | ||
|
|
a58f5c4de2 | ||
|
|
1995bba652 | ||
|
|
680747d1d0 | ||
|
|
e70b29066b | ||
|
|
9d82cee707 | ||
|
|
db1edf119d | ||
|
|
c5fa476b6d | ||
|
|
550a1f7107 | ||
|
|
42e1a12ea9 | ||
|
|
15945d28a1 | ||
|
|
eaa7215674 | ||
|
|
d2835b9e14 | ||
|
|
5691fa2e7a | ||
|
|
f4aba6a008 | ||
|
|
7bce5a8958 | ||
|
|
875d3d93d6 | ||
|
|
a0ede1593b | ||
|
|
0d43b6d601 | ||
|
|
9dbd485cad |
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
extends: 'react-tools',
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
* text=auto
|
||||
@@ -0,0 +1,38 @@
|
||||
---
|
||||
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.
|
||||
@@ -0,0 +1,17 @@
|
||||
---
|
||||
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.
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
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!
|
||||
@@ -1,7 +1,11 @@
|
||||
node_modules/
|
||||
lib/
|
||||
es/
|
||||
docs/build
|
||||
react-table.js
|
||||
react-table.min.js
|
||||
react-table.css
|
||||
*.log
|
||||
.idea
|
||||
.DS_Store
|
||||
.history
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
react-table.js.org
|
||||
@@ -1,68 +0,0 @@
|
||||
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 CustomSorting from '../stories/CustomSorting.js'
|
||||
import CustomWidths from '../stories/CustomWidths.js'
|
||||
import CustomComponentProps from '../stories/CustomComponentProps.js'
|
||||
import ServerSide from '../stories/ServerSide.js'
|
||||
import SubComponents from '../stories/SubComponents.js'
|
||||
import Pivoting from '../stories/Pivoting.js'
|
||||
import PivotingSubComponents from '../stories/PivotingSubComponents.js'
|
||||
import OneHundredKRows from '../stories/OneHundredKRows.js'
|
||||
import FunctionalRendering from '../stories/FunctionalRendering.js'
|
||||
import CustomExpanderPosition from '../stories/CustomExpanderPosition.js'
|
||||
import NoDataText from '../stories/NoDataText.js'
|
||||
import Footers from '../stories/Footers.js'
|
||||
import Filtering from '../stories/Filtering.js'
|
||||
import ControlledTable from '../stories/ControlledTable.js'
|
||||
import PivotingOptions from '../stories/PivotingOptions.js'
|
||||
import EditableTable from '../stories/EditableTable.js'
|
||||
import SubRows from '../stories/SubRows.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 Sorting', CustomSorting)
|
||||
.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('Pivoting Options', PivotingOptions)
|
||||
.add('Functional Rendering', FunctionalRendering)
|
||||
.add('Custom Expander Position', CustomExpanderPosition)
|
||||
.add('Custom "No Data" Text', NoDataText)
|
||||
.add('Footers', Footers)
|
||||
.add('Custom Filtering', Filtering)
|
||||
.add('Controlled Component', ControlledTable)
|
||||
.add('Editable table', EditableTable)
|
||||
// .add('Sub Rows', SubRows)
|
||||
}, module)
|
||||
@@ -1,18 +0,0 @@
|
||||
@import url("https://fonts.googleapis.com/css?family=Open+Sans:300,600");
|
||||
body {
|
||||
background: #fff;
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 15px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-bottom: 15px;
|
||||
line-height: 22px;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
body{
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
strong {
|
||||
font-weight: bold
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/* 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;
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
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
|
||||
}
|
||||
@@ -1,6 +1,144 @@
|
||||
## 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 ` `
|
||||
|
||||
## 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`)
|
||||
@@ -16,8 +154,8 @@
|
||||
- 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`
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
## Problem Description
|
||||
include a detailed explanation of the problem here...
|
||||
|
||||
## Code Snippet(s) or Codepen (http://codepen.io/tannerlinsley/pen/QpeZBa?editors=0010)
|
||||
|
||||
## Steps to Reproduce
|
||||
1. list the steps
|
||||
2. to reproduce the issue
|
||||
|
||||
## System Information
|
||||
* **Browser & Browser Version:**
|
||||
* **Node Version:**
|
||||
* **OS Version:**
|
||||
* **NPM Version:**
|
||||
* **Yarn Version:**
|
||||
@@ -0,0 +1,77 @@
|
||||
module.exports = {
|
||||
parserOptions: {
|
||||
ecmaVersion: 8,
|
||||
ecmaFeatures: {
|
||||
experimentalObjectRestSpread: true,
|
||||
jsx: true,
|
||||
node: false,
|
||||
classes: true
|
||||
},
|
||||
sourceType: 'module'
|
||||
},
|
||||
|
||||
parser: 'babel-eslint',
|
||||
|
||||
extends: ['standard'],
|
||||
|
||||
plugins: ['react'],
|
||||
|
||||
rules: {
|
||||
// Nozzle
|
||||
'jsx-quotes': [2, 'prefer-single'],
|
||||
'comma-dangle': [2, 'always-multiline'],
|
||||
|
||||
// // React
|
||||
'react/jsx-boolean-value': 2,
|
||||
'react/jsx-curly-spacing': [2, 'never'],
|
||||
'react/jsx-equals-spacing': [2, 'never'],
|
||||
// 'react/jsx-indent': 2,
|
||||
'react/jsx-indent-props': [2, 2],
|
||||
'react/jsx-no-duplicate-props': 2,
|
||||
'react/jsx-no-undef': 2,
|
||||
'react/jsx-tag-spacing': [
|
||||
2,
|
||||
{
|
||||
closingSlash: 'never',
|
||||
beforeSelfClosing: 'always',
|
||||
afterOpening: 'never'
|
||||
}
|
||||
],
|
||||
'react/jsx-uses-react': 2,
|
||||
'react/jsx-uses-vars': 2,
|
||||
'react/self-closing-comp': 2,
|
||||
'react/jsx-no-bind': [
|
||||
2,
|
||||
{
|
||||
allowArrowFunctions: true,
|
||||
allowBind: false,
|
||||
ignoreRefs: true
|
||||
}
|
||||
],
|
||||
'react/no-did-update-set-state': 2,
|
||||
'react/no-unknown-property': 2,
|
||||
'react/react-in-jsx-scope': 2,
|
||||
'react/jsx-closing-bracket-location': [0, 'tag-aligned'],
|
||||
'react/jsx-tag-spacing': [2, { beforeSelfClosing: 'always' }],
|
||||
'react/jsx-wrap-multilines': 2,
|
||||
'react/self-closing-comp': 2,
|
||||
'react/jsx-key': 2,
|
||||
'react/jsx-no-comment-textnodes': 2,
|
||||
'react/jsx-no-duplicate-props': 2,
|
||||
'react/jsx-no-target-blank': 2,
|
||||
'react/jsx-no-undef': 2,
|
||||
'react/jsx-uses-react': 2,
|
||||
'react/jsx-uses-vars': 2,
|
||||
'react/no-danger-with-children': 2,
|
||||
'react/no-deprecated': 2,
|
||||
'react/no-direct-mutation-state': 2,
|
||||
'react/no-find-dom-node': 2,
|
||||
'react/no-is-mounted': 2,
|
||||
'react/no-render-return-value': 2,
|
||||
'react/no-string-refs': 2,
|
||||
'react/no-unknown-property': 2,
|
||||
'react/react-in-jsx-scope': 2,
|
||||
'react/require-render-return': 2
|
||||
// 'react/jsx-max-props-per-line': [2, { maximum: 1 }]
|
||||
}
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
react-table.js.org
|
||||
react-table.js.org
|
||||
|
Before Width: | Height: | Size: 7.1 KiB |
@@ -1,22 +0,0 @@
|
||||
|
||||
<!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.b8deff9f16f0debf5b04.bundle.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
|
||||
<!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.4dc6928017acc8856e42.bundle.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"name": "new",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^6.7.0",
|
||||
"babel-cli": "6.14.0",
|
||||
"babel-eslint": "6.1.2",
|
||||
"babel-preset-es2015": "6.14.0",
|
||||
"babel-preset-react": "6.11.1",
|
||||
"babel-preset-stage-2": "6.13.0",
|
||||
"eslint": "^4.1.1",
|
||||
"eslint-config-standard": "^10.2.1",
|
||||
"eslint-plugin-class-property": "^1.0.6",
|
||||
"eslint-plugin-import": "^2.8.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.0.2",
|
||||
"eslint-plugin-node": "^5.2.1",
|
||||
"eslint-plugin-promise": "^3.6.0",
|
||||
"eslint-plugin-react": "^7.4.0",
|
||||
"eslint-plugin-standard": "^3.0.1",
|
||||
"html-element-attributes": "^1.3.0",
|
||||
"match-sorter": "^1.8.0",
|
||||
"npm-run-all": "^3.1.1",
|
||||
"onchange": "^3.0.2",
|
||||
"postcss-cli": "^2.6.0",
|
||||
"react": "^15.4.2",
|
||||
"react-dom": "^15.4.2",
|
||||
"react-json-tree": "^0.10.9",
|
||||
"rimraf": "^2.6.1",
|
||||
"standard": "^10.0.2",
|
||||
"stylus": "^0.54.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"eslint-config-react-tools": "^1.0.10",
|
||||
"github-markdown-css": "^2.6.0",
|
||||
"marked": "^0.3.6",
|
||||
"namor": "^1.0.1",
|
||||
"raw-loader": "^0.5.1",
|
||||
"react": "^15.5.4",
|
||||
"react-dom": "^15.5.4",
|
||||
"react-json-tree": "^0.10.9",
|
||||
"react-script": "^2.0.5",
|
||||
"react-scripts": "^0.9.5",
|
||||
"react-story": "^0.0.10",
|
||||
"shortid": "^2.2.8"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test --env=jsdom",
|
||||
"eject": "react-scripts eject"
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 24 KiB |
@@ -0,0 +1,31 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tag above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React Table - A lightweight, fast and extendable datagrid built for React</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start`.
|
||||
To create a production bundle, use `npm run build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,120 @@
|
||||
/* 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}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import React from "react";
|
||||
|
||||
export default id => () => {
|
||||
return (
|
||||
<iframe
|
||||
src={`https://codesandbox.io/embed/${id}?autoresize=1&hidenavigation=1&view=${
|
||||
global.innerWidth < 1000 ? "preview" : "split"
|
||||
}`}
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: `100%`,
|
||||
height: `100%`,
|
||||
border: 0,
|
||||
overflow: `hidden`
|
||||
}}
|
||||
sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,116 @@
|
||||
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'));
|
||||
@@ -0,0 +1,94 @@
|
||||
import React from "react";
|
||||
|
||||
export default Component => {
|
||||
const wrapper = class RTCheckboxTable extends React.Component {
|
||||
// we only need a Component so we can get the 'ref' - pure components can't get a 'ref'
|
||||
|
||||
rowSelector = row => {
|
||||
if (!row || !row.hasOwnProperty(this.props.keyField)) return null;
|
||||
const checked = this.props.isSelected(row[this.props.keyField]);
|
||||
return (
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={checked}
|
||||
onClick={e => {
|
||||
const { shiftKey } = e;
|
||||
e.stopPropagation();
|
||||
this.props.toggleSelection(row[this.props.keyField], shiftKey, row);
|
||||
}}
|
||||
onChange={() => {}}
|
||||
value=""
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
headSelector = row => {
|
||||
const checked = this.props.selectAll;
|
||||
return (
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={checked}
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
this.props.toggleAll();
|
||||
}}
|
||||
onChange={() => {}}
|
||||
value=""
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
// this is so we can expose the underlying ReactTable to get at the sortedData for selectAll
|
||||
getWrappedInstance = () => this.wrappedInstance;
|
||||
|
||||
render() {
|
||||
const {
|
||||
columns: originalCols,
|
||||
isSelected,
|
||||
toggleSelection,
|
||||
toggleAll,
|
||||
keyField,
|
||||
selectAll,
|
||||
...rest
|
||||
} = this.props;
|
||||
const { rowSelector, headSelector } = this;
|
||||
const select = {
|
||||
id: "_selector",
|
||||
accessor: () => "x", // this value is not important
|
||||
Header: headSelector,
|
||||
Cell: ci => {
|
||||
return rowSelector(ci.original);
|
||||
},
|
||||
width: 30,
|
||||
filterable: false,
|
||||
sortable: false,
|
||||
resizable: false,
|
||||
style: { textAlign: "center" }
|
||||
};
|
||||
const columns = [select, ...originalCols];
|
||||
const extra = {
|
||||
columns
|
||||
};
|
||||
return (
|
||||
<Component {...rest} {...extra} ref={r => (this.wrappedInstance = r)} />
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
wrapper.displayName = "RTCheckboxTable";
|
||||
wrapper.defaultProps = {
|
||||
keyField: "_id",
|
||||
isSelected: key => {
|
||||
console.log("No isSelected handler provided:", { key });
|
||||
},
|
||||
selectAll: false,
|
||||
toggleSelection: (key, shift, row) => {
|
||||
console.log("No toggleSelection handler provided:", { key, shift, row });
|
||||
},
|
||||
toggleAll: () => {
|
||||
console.log("No toggleAll handler provided.");
|
||||
}
|
||||
};
|
||||
|
||||
return wrapper;
|
||||
};
|
||||
@@ -0,0 +1,148 @@
|
||||
import React from "react";
|
||||
import shortid from "shortid";
|
||||
|
||||
import ReactTable from "../../../../lib/index";
|
||||
import "../../../../react-table.css";
|
||||
|
||||
import checkboxTableHOC from "./checkboxHOC";
|
||||
|
||||
const CheckboxTable = checkboxTableHOC(ReactTable);
|
||||
|
||||
async function getData() {
|
||||
const result = await (await fetch("/au_500_tree.json")).json();
|
||||
// we are adding a unique ID to the data for tracking the selected records
|
||||
return result.map(item => {
|
||||
const _id = shortid.generate();
|
||||
return {
|
||||
_id,
|
||||
...item
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function getColumns(data) {
|
||||
const columns = [];
|
||||
const sample = data[0];
|
||||
for (let key in sample) {
|
||||
if (key === "_id") continue;
|
||||
columns.push({
|
||||
accessor: key,
|
||||
Header: key
|
||||
});
|
||||
}
|
||||
return columns;
|
||||
}
|
||||
|
||||
export class ComponentTest extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
data: null,
|
||||
columns: null,
|
||||
selection: [],
|
||||
selectAll: false
|
||||
};
|
||||
}
|
||||
componentDidMount() {
|
||||
getData().then(data => {
|
||||
const columns = getColumns(data);
|
||||
this.setState({ data, columns });
|
||||
});
|
||||
}
|
||||
toggleSelection = (key, shift, row) => {
|
||||
/*
|
||||
Implementation of how to manage the selection state is up to the developer.
|
||||
This implementation uses an array stored in the component state.
|
||||
Other implementations could use object keys, a Javascript Set, or Redux... etc.
|
||||
*/
|
||||
// start off with the existing state
|
||||
let selection = [...this.state.selection];
|
||||
const keyIndex = selection.indexOf(key);
|
||||
// check to see if the key exists
|
||||
if (keyIndex >= 0) {
|
||||
// it does exist so we will remove it using destructing
|
||||
selection = [
|
||||
...selection.slice(0, keyIndex),
|
||||
...selection.slice(keyIndex + 1)
|
||||
];
|
||||
} else {
|
||||
// it does not exist so add it
|
||||
selection.push(key);
|
||||
}
|
||||
// update the state
|
||||
this.setState({ selection });
|
||||
};
|
||||
toggleAll = () => {
|
||||
/*
|
||||
'toggleAll' is a tricky concept with any filterable table
|
||||
do you just select ALL the records that are in your data?
|
||||
OR
|
||||
do you only select ALL the records that are in the current filtered data?
|
||||
|
||||
The latter makes more sense because 'selection' is a visual thing for the user.
|
||||
This is especially true if you are going to implement a set of external functions
|
||||
that act on the selected information (you would not want to DELETE the wrong thing!).
|
||||
|
||||
So, to that end, access to the internals of ReactTable are required to get what is
|
||||
currently visible in the table (either on the current page or any other page).
|
||||
|
||||
The HOC provides a method call 'getWrappedInstance' to get a ref to the wrapped
|
||||
ReactTable and then get the internal state and the 'sortedData'.
|
||||
That can then be iterrated to get all the currently visible records and set
|
||||
the selection state.
|
||||
*/
|
||||
const selectAll = this.state.selectAll ? false : true;
|
||||
const selection = [];
|
||||
if (selectAll) {
|
||||
// we need to get at the internals of ReactTable
|
||||
const wrappedInstance = this.checkboxTable.getWrappedInstance();
|
||||
// the 'sortedData' property contains the currently accessible records based on the filter and sort
|
||||
const currentRecords = wrappedInstance.getResolvedState().sortedData;
|
||||
// we just push all the IDs onto the selection array
|
||||
currentRecords.forEach(item => {
|
||||
selection.push(item._original._id);
|
||||
});
|
||||
}
|
||||
this.setState({ selectAll, selection });
|
||||
};
|
||||
isSelected = key => {
|
||||
/*
|
||||
Instead of passing our external selection state we provide an 'isSelected'
|
||||
callback and detect the selection state ourselves. This allows any implementation
|
||||
for selection (either an array, object keys, or even a Javascript Set object).
|
||||
*/
|
||||
return this.state.selection.includes(key);
|
||||
};
|
||||
logSelection = () => {
|
||||
console.log("selection:", this.state.selection);
|
||||
};
|
||||
render() {
|
||||
const { toggleSelection, toggleAll, isSelected, logSelection } = this;
|
||||
const { data, columns, selectAll } = this.state;
|
||||
const extraProps = {
|
||||
selectAll,
|
||||
isSelected,
|
||||
toggleAll,
|
||||
toggleSelection
|
||||
};
|
||||
return (
|
||||
<div style={{ padding: "10px" }}>
|
||||
<h1>react-table - Checkbox Table</h1>
|
||||
<button onClick={logSelection}>Log Selection to Console</button>
|
||||
{` (${this.state.selection.length}) selected`}
|
||||
{data ? (
|
||||
<CheckboxTable
|
||||
data={data}
|
||||
columns={columns}
|
||||
ref={r => (this.checkboxTable = r)}
|
||||
className="-striped -highlight"
|
||||
{...extraProps}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// export default treeTableHOC(ComponentTest);
|
||||
export default ComponentTest;
|
||||
@@ -0,0 +1,60 @@
|
||||
import React from "react";
|
||||
|
||||
export default class ComponentTest extends React.component {
|
||||
render() {
|
||||
return <div>Bozo</div>;
|
||||
}
|
||||
}
|
||||
|
||||
// import ReactTable from '../../../../lib/index'
|
||||
// import '../../../../react-table.css'
|
||||
//
|
||||
// console.log('ReactTable:',ReactTable)
|
||||
//
|
||||
// const data = [
|
||||
// {one:"1.1",two:"1.2"},
|
||||
// {one:"2.1",two:"2.2"},
|
||||
// {one:"3.1",two:"3.2"},
|
||||
// {one:"4.1",two:"4.2"},
|
||||
// ]
|
||||
//
|
||||
// const columns = [
|
||||
// {accessor:'one', Header: 'One'},
|
||||
// {accessor:'two', Header: 'Two'},
|
||||
// ]
|
||||
//
|
||||
// class ExpanderComponent extends React.Component {
|
||||
// render()
|
||||
// {
|
||||
// return (
|
||||
// <div className={`rt-expander ${this.props.isExpanded ? '-open' : ''}`}>
|
||||
// •
|
||||
// </div>
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// class SubComponent extends React.Component {
|
||||
// render()
|
||||
// {
|
||||
// return <div>Nothing</div>
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// export default class ComponentTest extends React.Component {
|
||||
// render()
|
||||
// {
|
||||
// const rtProps = {
|
||||
// data,
|
||||
// columns,
|
||||
// // ExpanderComponent: (props, closeExpanded)=><ExpanderComponent {...props, closeExpanded} />,
|
||||
// // SubComponent: (props)=><SubComponent {...props} />,
|
||||
// // multiSort: false,
|
||||
// }
|
||||
// return (
|
||||
// <ReactTable
|
||||
// {...rtProps}
|
||||
// />
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
@@ -0,0 +1,110 @@
|
||||
import React from 'react'
|
||||
import ReactTable from '../../../../lib/index'
|
||||
import FoldableTableHOC from '../../../../lib/hoc/foldableTable'
|
||||
import selectTableHOC from '../../../../lib/hoc/selectTable'
|
||||
|
||||
const FoldableTable = FoldableTableHOC(selectTableHOC(ReactTable))
|
||||
|
||||
export default class FoldableTableCustomState extends React.Component {
|
||||
constructor(props, context) {
|
||||
super(props, context)
|
||||
|
||||
this.state = { folded: {}, seleted: {}, selectedAll: false }
|
||||
}
|
||||
|
||||
getData = () => [{
|
||||
id: 1,
|
||||
first_name: 'Jeanette',
|
||||
'last_name': 'Penddreth',
|
||||
email: 'jpenddreth0@census.gov',
|
||||
'gender': 'Female',
|
||||
ip_address: '26.58.193.2',
|
||||
}, {
|
||||
'id': 2,
|
||||
'first_name': 'Giavani',
|
||||
last_name: 'Frediani',
|
||||
'email': 'gfrediani1@senate.gov',
|
||||
'gender': 'Male',
|
||||
'ip_address': '229.179.4.212',
|
||||
}, {
|
||||
'id': 3,
|
||||
first_name: 'Noell',
|
||||
last_name: 'Bea',
|
||||
'email': 'nbea2@imageshack.us',
|
||||
gender: 'Female',
|
||||
ip_address: '180.66.162.255',
|
||||
}, {
|
||||
'id': 4,
|
||||
'first_name': 'Willard',
|
||||
'last_name': 'Valek',
|
||||
email: 'wvalek3@vk.com',
|
||||
'gender': 'Male',
|
||||
ip_address: '67.76.188.26',
|
||||
}];
|
||||
|
||||
toggleSelection = (key, shift, row) => {
|
||||
const { selected } = this.state
|
||||
let newSelected = Object.assign({}, selected)
|
||||
newSelected[key] = !newSelected[key]
|
||||
this.setState(p => ({ selected: newSelected }))
|
||||
};
|
||||
|
||||
toggleAll = () => {
|
||||
const { selectedAll } = this.state
|
||||
|
||||
if (selectedAll) { this.setState(p => { return { selectedAll: false, seleted: {} } }); }
|
||||
else {
|
||||
const data = this.getData()
|
||||
|
||||
let newSelected = {}
|
||||
data.forEach(d => newSelected[d.id] = true)
|
||||
this.setState(p => ({ selectedAll: true, seleted: newSelected }))
|
||||
}
|
||||
}
|
||||
|
||||
isSelected = key => this.state.seleted[key];
|
||||
|
||||
render() {
|
||||
return (<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>)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
import React from 'react'
|
||||
import ReactTable from '../../../../lib/index'
|
||||
import FoldableTableHOC from '../../../../lib/hoc/foldableTable'
|
||||
|
||||
const FoldableTable = FoldableTableHOC(ReactTable)
|
||||
|
||||
export default class FoldableTableWithHeader extends React.Component {
|
||||
|
||||
getData = () => [{
|
||||
id: 1,
|
||||
first_name: 'Jeanette',
|
||||
last_name: 'Penddreth',
|
||||
'email': 'jpenddreth0@census.gov',
|
||||
gender: 'Female',
|
||||
'ip_address': '26.58.193.2',
|
||||
}, {
|
||||
'id': 2,
|
||||
first_name: 'Giavani',
|
||||
last_name: 'Frediani',
|
||||
email: 'gfrediani1@senate.gov',
|
||||
gender: 'Male',
|
||||
'ip_address': '229.179.4.212',
|
||||
}, {
|
||||
'id': 3,
|
||||
'first_name': 'Noell',
|
||||
last_name: 'Bea',
|
||||
'email': 'nbea2@imageshack.us',
|
||||
'gender': 'Female',
|
||||
ip_address: '180.66.162.255',
|
||||
}, {
|
||||
'id': 4,
|
||||
'first_name': 'Willard',
|
||||
'last_name': 'Valek',
|
||||
email: 'wvalek3@vk.com',
|
||||
'gender': 'Male',
|
||||
ip_address: '67.76.188.26',
|
||||
}];
|
||||
|
||||
render() {
|
||||
return (<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>)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
import React from 'react';
|
||||
import ReactTable from '../../../../lib/index';
|
||||
import FoldableTableHOC from '../../../../lib/hoc/foldableTable';
|
||||
|
||||
const FoldableTable = FoldableTableHOC(ReactTable);
|
||||
|
||||
export default class FoldableTableWithoutHeader extends React.Component {
|
||||
|
||||
getData = () => [{
|
||||
"id": 1,
|
||||
"first_name": "Jeanette",
|
||||
"last_name": "Penddreth",
|
||||
"email": "jpenddreth0@census.gov",
|
||||
"gender": "Female",
|
||||
"ip_address": "26.58.193.2"
|
||||
}, {
|
||||
"id": 2,
|
||||
"first_name": "Giavani",
|
||||
"last_name": "Frediani",
|
||||
"email": "gfrediani1@senate.gov",
|
||||
"gender": "Male",
|
||||
"ip_address": "229.179.4.212"
|
||||
}, {
|
||||
"id": 3,
|
||||
"first_name": "Noell",
|
||||
"last_name": "Bea",
|
||||
"email": "nbea2@imageshack.us",
|
||||
"gender": "Female",
|
||||
"ip_address": "180.66.162.255"
|
||||
}, {
|
||||
"id": 4,
|
||||
"first_name": "Willard",
|
||||
"last_name": "Valek",
|
||||
"email": "wvalek3@vk.com",
|
||||
"gender": "Male",
|
||||
"ip_address": "67.76.188.26"
|
||||
}];
|
||||
|
||||
render() {
|
||||
return <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>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
|
||||
import React from 'react'
|
||||
import '../../../../react-table.css'
|
||||
|
||||
import FoldableTableWithHeader from './FoldableTableWithHeader'
|
||||
import FoldableTableWithoutHeader from './FoldableTableWithoutHeader'
|
||||
import FoldableTableCustomState from './FoldableTableCustomState'
|
||||
|
||||
class FaldableComponentTest extends React.Component {
|
||||
render() {
|
||||
|
||||
return (
|
||||
<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
|
||||
@@ -0,0 +1,13 @@
|
||||
/* eslint-disable */
|
||||
|
||||
import TreeTable from './treetable'
|
||||
import SelectTable from './selecttable'
|
||||
import SelectTreeTable from './selecttreetable'
|
||||
import FoldableTable from './foldabletable';
|
||||
|
||||
export {
|
||||
TreeTable,
|
||||
SelectTable,
|
||||
SelectTreeTable,
|
||||
FoldableTable
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
import React from "react";
|
||||
import shortid from "shortid";
|
||||
|
||||
import ReactTable from "../../../../lib/index";
|
||||
import "../../../../react-table.css";
|
||||
|
||||
import selectTableHOC from "../../../../lib/hoc/selectTable";
|
||||
|
||||
const SelectTable = selectTableHOC(ReactTable);
|
||||
|
||||
async function getData() {
|
||||
const result = await (await fetch("/au_500_tree.json")).json();
|
||||
// we are adding a unique ID to the data for tracking the selected records
|
||||
return result.map(item => {
|
||||
const _id = shortid.generate();
|
||||
return {
|
||||
_id,
|
||||
...item
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function getColumns(data) {
|
||||
const columns = [];
|
||||
const sample = data[0];
|
||||
for (let key in sample) {
|
||||
if (key === "_id") continue;
|
||||
columns.push({
|
||||
accessor: key,
|
||||
Header: key
|
||||
});
|
||||
}
|
||||
return columns;
|
||||
}
|
||||
|
||||
export class ComponentTest extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
data: null,
|
||||
columns: null,
|
||||
selection: [],
|
||||
selectAll: false,
|
||||
selectType: "checkbox"
|
||||
};
|
||||
}
|
||||
componentDidMount() {
|
||||
getData().then(data => {
|
||||
const columns = getColumns(data);
|
||||
this.setState({ data, columns });
|
||||
});
|
||||
}
|
||||
toggleSelection = (key, shift, row) => {
|
||||
/*
|
||||
Implementation of how to manage the selection state is up to the developer.
|
||||
This implementation uses an array stored in the component state.
|
||||
Other implementations could use object keys, a Javascript Set, or Redux... etc.
|
||||
*/
|
||||
// start off with the existing state
|
||||
if (this.state.selectType === "radio") {
|
||||
let selection = [];
|
||||
if (selection.indexOf(key) < 0) selection.push(key);
|
||||
this.setState({ selection });
|
||||
} else {
|
||||
let selection = [...this.state.selection];
|
||||
const keyIndex = selection.indexOf(key);
|
||||
// check to see if the key exists
|
||||
if (keyIndex >= 0) {
|
||||
// it does exist so we will remove it using destructing
|
||||
selection = [
|
||||
...selection.slice(0, keyIndex),
|
||||
...selection.slice(keyIndex + 1)
|
||||
];
|
||||
} else {
|
||||
// it does not exist so add it
|
||||
selection.push(key);
|
||||
}
|
||||
// update the state
|
||||
this.setState({ selection });
|
||||
}
|
||||
};
|
||||
toggleAll = () => {
|
||||
/*
|
||||
'toggleAll' is a tricky concept with any filterable table
|
||||
do you just select ALL the records that are in your data?
|
||||
OR
|
||||
do you only select ALL the records that are in the current filtered data?
|
||||
|
||||
The latter makes more sense because 'selection' is a visual thing for the user.
|
||||
This is especially true if you are going to implement a set of external functions
|
||||
that act on the selected information (you would not want to DELETE the wrong thing!).
|
||||
|
||||
So, to that end, access to the internals of ReactTable are required to get what is
|
||||
currently visible in the table (either on the current page or any other page).
|
||||
|
||||
The HOC provides a method call 'getWrappedInstance' to get a ref to the wrapped
|
||||
ReactTable and then get the internal state and the 'sortedData'.
|
||||
That can then be iterrated to get all the currently visible records and set
|
||||
the selection state.
|
||||
*/
|
||||
const selectAll = this.state.selectAll ? false : true;
|
||||
const selection = [];
|
||||
if (selectAll) {
|
||||
// we need to get at the internals of ReactTable
|
||||
const wrappedInstance = this.selectTable.getWrappedInstance();
|
||||
// the 'sortedData' property contains the currently accessible records based on the filter and sort
|
||||
const currentRecords = wrappedInstance.getResolvedState().sortedData;
|
||||
// we just push all the IDs onto the selection array
|
||||
currentRecords.forEach(item => {
|
||||
if (item._original) {
|
||||
selection.push(item._original._id);
|
||||
}
|
||||
});
|
||||
}
|
||||
this.setState({ selectAll, selection });
|
||||
};
|
||||
isSelected = key => {
|
||||
/*
|
||||
Instead of passing our external selection state we provide an 'isSelected'
|
||||
callback and detect the selection state ourselves. This allows any implementation
|
||||
for selection (either an array, object keys, or even a Javascript Set object).
|
||||
*/
|
||||
return this.state.selection.includes(key);
|
||||
};
|
||||
logSelection = () => {
|
||||
console.log("selection:", this.state.selection);
|
||||
};
|
||||
toggleType = () => {
|
||||
this.setState({
|
||||
selectType: this.state.selectType === "radio" ? "checkbox" : "radio",
|
||||
selection: [],
|
||||
selectAll: false
|
||||
});
|
||||
};
|
||||
render() {
|
||||
const {
|
||||
toggleSelection,
|
||||
toggleAll,
|
||||
isSelected,
|
||||
logSelection,
|
||||
toggleType
|
||||
} = this;
|
||||
const { data, columns, selectAll, selectType } = this.state;
|
||||
const extraProps = {
|
||||
selectAll,
|
||||
isSelected,
|
||||
toggleAll,
|
||||
toggleSelection,
|
||||
selectType
|
||||
};
|
||||
return (
|
||||
<div style={{ padding: "10px" }}>
|
||||
<h1>react-table - Select Table</h1>
|
||||
<button onClick={toggleType}>
|
||||
Select Type: <strong>{selectType}</strong>
|
||||
</button>
|
||||
<button onClick={logSelection}>Log Selection to Console</button>
|
||||
{` (${this.state.selection.length}) selected`}
|
||||
{data ? (
|
||||
<SelectTable
|
||||
data={data}
|
||||
columns={columns}
|
||||
ref={r => (this.selectTable = r)}
|
||||
className="-striped -highlight"
|
||||
{...extraProps}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ComponentTest;
|
||||
@@ -0,0 +1,238 @@
|
||||
import React from "react";
|
||||
import shortid from "shortid";
|
||||
|
||||
import ReactTable from "../../../../lib/index";
|
||||
import "../../../../react-table.css";
|
||||
|
||||
import selectTableHOC from "../../../../lib/hoc/selectTable";
|
||||
import treeTableHOC from "../../../../lib/hoc/treeTable";
|
||||
|
||||
const SelectTreeTable = selectTableHOC(treeTableHOC(ReactTable));
|
||||
|
||||
async function getData() {
|
||||
const result = await (await fetch("/au_500_tree.json")).json();
|
||||
// we are adding a unique ID to the data for tracking the selected records
|
||||
return result.map(item => {
|
||||
const _id = shortid.generate();
|
||||
return {
|
||||
_id,
|
||||
...item
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function getColumns(data) {
|
||||
const columns = [];
|
||||
const sample = data[0];
|
||||
for (let key in sample) {
|
||||
if (key === "_id") continue;
|
||||
columns.push({
|
||||
accessor: key,
|
||||
Header: key
|
||||
});
|
||||
}
|
||||
return columns;
|
||||
}
|
||||
|
||||
function getNodes(data, node = []) {
|
||||
data.forEach(item => {
|
||||
if (item.hasOwnProperty("_subRows") && item._subRows) {
|
||||
node = getNodes(item._subRows, node);
|
||||
} else {
|
||||
node.push(item._original);
|
||||
}
|
||||
});
|
||||
return node;
|
||||
}
|
||||
|
||||
export class ComponentTest extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
data: null,
|
||||
columns: null,
|
||||
selection: [],
|
||||
selectAll: false,
|
||||
selectType: "checkbox"
|
||||
};
|
||||
}
|
||||
componentDidMount() {
|
||||
getData().then(data => {
|
||||
const columns = getColumns(data);
|
||||
const pivotBy = ["state", "post"];
|
||||
this.setState({ data, columns, pivotBy });
|
||||
});
|
||||
}
|
||||
toggleSelection = (key, shift, row) => {
|
||||
/*
|
||||
Implementation of how to manage the selection state is up to the developer.
|
||||
This implementation uses an array stored in the component state.
|
||||
Other implementations could use object keys, a Javascript Set, or Redux... etc.
|
||||
*/
|
||||
// start off with the existing state
|
||||
if (this.state.selectType === "radio") {
|
||||
let selection = [];
|
||||
if (selection.indexOf(key) < 0) selection.push(key);
|
||||
this.setState({ selection });
|
||||
} else {
|
||||
let selection = [...this.state.selection];
|
||||
const keyIndex = selection.indexOf(key);
|
||||
// check to see if the key exists
|
||||
if (keyIndex >= 0) {
|
||||
// it does exist so we will remove it using destructing
|
||||
selection = [
|
||||
...selection.slice(0, keyIndex),
|
||||
...selection.slice(keyIndex + 1)
|
||||
];
|
||||
} else {
|
||||
// it does not exist so add it
|
||||
selection.push(key);
|
||||
}
|
||||
// update the state
|
||||
this.setState({ selection });
|
||||
}
|
||||
};
|
||||
toggleAll = () => {
|
||||
/*
|
||||
'toggleAll' is a tricky concept with any filterable table
|
||||
do you just select ALL the records that are in your data?
|
||||
OR
|
||||
do you only select ALL the records that are in the current filtered data?
|
||||
|
||||
The latter makes more sense because 'selection' is a visual thing for the user.
|
||||
This is especially true if you are going to implement a set of external functions
|
||||
that act on the selected information (you would not want to DELETE the wrong thing!).
|
||||
|
||||
So, to that end, access to the internals of ReactTable are required to get what is
|
||||
currently visible in the table (either on the current page or any other page).
|
||||
|
||||
The HOC provides a method call 'getWrappedInstance' to get a ref to the wrapped
|
||||
ReactTable and then get the internal state and the 'sortedData'.
|
||||
That can then be iterrated to get all the currently visible records and set
|
||||
the selection state.
|
||||
*/
|
||||
const selectAll = this.state.selectAll ? false : true;
|
||||
const selection = [];
|
||||
if (selectAll) {
|
||||
// we need to get at the internals of ReactTable
|
||||
const wrappedInstance = this.selectTable.getWrappedInstance();
|
||||
// the 'sortedData' property contains the currently accessible records based on the filter and sort
|
||||
const currentRecords = wrappedInstance.getResolvedState().sortedData;
|
||||
// we need to get all the 'real' (original) records out to get at their IDs
|
||||
const nodes = getNodes(currentRecords);
|
||||
// we just push all the IDs onto the selection array
|
||||
nodes.forEach(item => {
|
||||
selection.push(item._id);
|
||||
});
|
||||
}
|
||||
this.setState({ selectAll, selection });
|
||||
};
|
||||
isSelected = key => {
|
||||
/*
|
||||
Instead of passing our external selection state we provide an 'isSelected'
|
||||
callback and detect the selection state ourselves. This allows any implementation
|
||||
for selection (either an array, object keys, or even a Javascript Set object).
|
||||
*/
|
||||
return this.state.selection.includes(key);
|
||||
};
|
||||
logSelection = () => {
|
||||
console.log("selection:", this.state.selection);
|
||||
};
|
||||
toggleType = () => {
|
||||
this.setState({
|
||||
selectType: this.state.selectType === "radio" ? "checkbox" : "radio",
|
||||
selection: [],
|
||||
selectAll: false
|
||||
});
|
||||
};
|
||||
toggleTree = () => {
|
||||
if (this.state.pivotBy.length) {
|
||||
this.setState({ pivotBy: [], expanded: {} });
|
||||
} else {
|
||||
this.setState({ pivotBy: ["state", "post"], expanded: {} });
|
||||
}
|
||||
};
|
||||
onExpandedChange = expanded => {
|
||||
this.setState({ expanded });
|
||||
};
|
||||
render() {
|
||||
const {
|
||||
toggleSelection,
|
||||
toggleAll,
|
||||
isSelected,
|
||||
logSelection,
|
||||
toggleType,
|
||||
toggleTree,
|
||||
onExpandedChange
|
||||
} = this;
|
||||
const {
|
||||
data,
|
||||
columns,
|
||||
selectAll,
|
||||
selectType,
|
||||
pivotBy,
|
||||
expanded
|
||||
} = this.state;
|
||||
const extraProps = {
|
||||
selectAll,
|
||||
isSelected,
|
||||
toggleAll,
|
||||
toggleSelection,
|
||||
selectType,
|
||||
pivotBy,
|
||||
expanded,
|
||||
onExpandedChange,
|
||||
pageSize: 5
|
||||
};
|
||||
return (
|
||||
<div style={{ padding: "10px" }}>
|
||||
<h1>react-table - Select Tree Table</h1>
|
||||
<p>
|
||||
This example combines two HOCs (the TreeTable and the SelectTable) to
|
||||
make a composite component.
|
||||
</p>
|
||||
<p>We'll call it SelectTreeTable!</p>
|
||||
<p>Here is what the buttons do:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<strong>Toggle Tree:</strong> enables or disabled the pivotBy on the
|
||||
table.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Select Type:</strong> changes from 'checkbox' to 'radio' and
|
||||
back again.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Log Selection to Console:</strong> open your console to see
|
||||
what has been selected.
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
<strong>NOTE:</strong> the selection is maintained when toggling the
|
||||
tree on and off but is cleared when switching between select types
|
||||
(radio, checkbox).
|
||||
</p>
|
||||
<button onClick={toggleTree}>
|
||||
Toggle Tree [{pivotBy && pivotBy.length ? pivotBy.join(", ") : ""}]
|
||||
</button>
|
||||
<button onClick={toggleType}>
|
||||
Select Type: <strong>{selectType}</strong>
|
||||
</button>
|
||||
<button onClick={logSelection}>Log Selection to Console</button>
|
||||
{` (${this.state.selection.length}) selected`}
|
||||
{data ? (
|
||||
<SelectTreeTable
|
||||
data={data}
|
||||
columns={columns}
|
||||
ref={r => (this.selectTable = r)}
|
||||
className="-striped -highlight"
|
||||
freezeWhenExpanded={true}
|
||||
{...extraProps}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ComponentTest;
|
||||
@@ -0,0 +1,70 @@
|
||||
import React from "react";
|
||||
|
||||
import ReactTable from "../../../../lib/index";
|
||||
import "../../../../react-table.css";
|
||||
|
||||
import treeTableHOC from "../../../../lib/hoc/treeTable";
|
||||
|
||||
async function getData() {
|
||||
const result = await (await fetch("/au_500_tree.json")).json();
|
||||
return result;
|
||||
}
|
||||
|
||||
function getColumns(data, pivotBy) {
|
||||
const columns = [];
|
||||
const sample = data[0];
|
||||
for (let key in sample) {
|
||||
columns.push({
|
||||
accessor: key,
|
||||
Header: key
|
||||
});
|
||||
}
|
||||
return columns;
|
||||
}
|
||||
|
||||
export class ComponentTest extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
data: null,
|
||||
columns: null,
|
||||
pivotBy: null // ["firstName", "lastName"],
|
||||
};
|
||||
}
|
||||
componentDidMount() {
|
||||
getData().then(data => {
|
||||
// console.log('cwm data:',data);
|
||||
const pivotBy = ["state", "post", "city"];
|
||||
const columns = getColumns(data, pivotBy);
|
||||
// console.log('cwm cols:',columns);
|
||||
this.setState({ data, columns, pivotBy });
|
||||
});
|
||||
}
|
||||
showState = () => {
|
||||
console.log("state:", this.reactTable.getResolvedState());
|
||||
};
|
||||
render() {
|
||||
const { data, columns, pivotBy } = this.state;
|
||||
const extraProps = {
|
||||
data,
|
||||
columns,
|
||||
pivotBy
|
||||
};
|
||||
const TreeTable = treeTableHOC(ReactTable);
|
||||
return (
|
||||
<div style={{ padding: "10px" }}>
|
||||
<h1>react-table - Tree Table</h1>
|
||||
{data ? (
|
||||
<TreeTable
|
||||
ref={r => (this.reactTable = r)}
|
||||
className="-striped -highlight"
|
||||
defaultPageSize={5}
|
||||
{...extraProps}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ComponentTest;
|
||||
@@ -0,0 +1,53 @@
|
||||
import React from "react";
|
||||
|
||||
export default Component => {
|
||||
const wrapper = componentProps => {
|
||||
const TrComponent = props => {
|
||||
const { ri, ...rest } = props;
|
||||
if (ri && ri.groupedByPivot) {
|
||||
const cell = props.children[ri.level];
|
||||
|
||||
cell.props.style.flex = "unset";
|
||||
cell.props.style.width = "100%";
|
||||
cell.props.style.maxWidth = "unset";
|
||||
cell.props.style.paddingLeft = `${componentProps.treeTableIndent *
|
||||
ri.level}px`;
|
||||
cell.props.style.backgroundColor = "#DDD";
|
||||
cell.props.style.borderBottom = "1px solid rgba(128,128,128,0.2)";
|
||||
|
||||
return <div {...rest}>{cell}</div>;
|
||||
}
|
||||
return <Component.defaultProps.TrComponent {...rest} />;
|
||||
};
|
||||
|
||||
const getTrProps = (state, ri, ci, instance) => {
|
||||
return { ri };
|
||||
};
|
||||
|
||||
const { columns, ...rest } = componentProps;
|
||||
const extra = {
|
||||
columns: columns.map(col => {
|
||||
let column = col;
|
||||
if (rest.pivotBy && rest.pivotBy.includes(col.accessor)) {
|
||||
column = {
|
||||
accessor: col.accessor,
|
||||
width: `${componentProps.treeTableIndent}px`,
|
||||
show: false,
|
||||
Header: ""
|
||||
};
|
||||
}
|
||||
return column;
|
||||
}),
|
||||
TrComponent,
|
||||
getTrProps
|
||||
};
|
||||
|
||||
return <Component {...rest} {...extra} />;
|
||||
};
|
||||
wrapper.displayName = "RTTreeTable";
|
||||
wrapper.defaultProps = {
|
||||
treeTableRowBackground: "#EEE",
|
||||
treeTableIndent: 10
|
||||
};
|
||||
return wrapper;
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
import namor from "namor";
|
||||
|
||||
const range = len => {
|
||||
const arr = [];
|
||||
for (let i = 0; i < len; i++) {
|
||||
arr.push(i);
|
||||
}
|
||||
return arr;
|
||||
};
|
||||
|
||||
const newPerson = () => {
|
||||
const statusChance = Math.random();
|
||||
return {
|
||||
firstName: namor.generate({ words: 1, numbers: 0 }),
|
||||
lastName: namor.generate({ words: 1, numbers: 0 }),
|
||||
age: Math.floor(Math.random() * 30),
|
||||
visits: Math.floor(Math.random() * 100),
|
||||
progress: Math.floor(Math.random() * 100),
|
||||
status:
|
||||
statusChance > 0.66
|
||||
? "relationship"
|
||||
: statusChance > 0.33
|
||||
? "complicated"
|
||||
: "single"
|
||||
};
|
||||
};
|
||||
|
||||
export function makeData(len = 5553) {
|
||||
return range(len).map(d => {
|
||||
return {
|
||||
...newPerson(),
|
||||
children: range(10).map(newPerson)
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
html,
|
||||
body,
|
||||
#root {
|
||||
height: 100%;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
//
|
||||
import "./index.css";
|
||||
import App from "./App.js";
|
||||
|
||||
ReactDOM.render(<App />, document.getElementById("root"));
|
||||
@@ -0,0 +1,23 @@
|
||||
/* eslint-disable */
|
||||
import React from "react";
|
||||
import marked from "marked";
|
||||
//
|
||||
import HOCReadme from "!raw!../../../src/hoc/README.md";
|
||||
import "github-markdown-css/github-markdown.css";
|
||||
import "./utils/prism.js";
|
||||
|
||||
export default class HOCStory extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div style={{ padding: "10px" }}>
|
||||
<span
|
||||
className="markdown-body"
|
||||
dangerouslySetInnerHTML={{ __html: marked(HOCReadme) }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
componentDidMount() {
|
||||
global.Prism && global.Prism.highlightAll();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/* eslint-disable import/no-webpack-loader-syntax */
|
||||
import React from "react";
|
||||
import marked from "marked";
|
||||
//
|
||||
import Readme from "!raw!../../../README.md";
|
||||
import "github-markdown-css/github-markdown.css";
|
||||
import "./utils/prism.js";
|
||||
|
||||
export default class Story extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div style={{ padding: "10px" }}>
|
||||
<span
|
||||
className="markdown-body"
|
||||
dangerouslySetInnerHTML={{ __html: marked(Readme) }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
componentDidMount() {
|
||||
global.Prism && global.Prism.highlightAll();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import React from "react";
|
||||
|
||||
import ReactTable from "../../../lib/index";
|
||||
import "../../../react-table.css";
|
||||
|
||||
const data = [
|
||||
{ one: "1.1", two: "1.2" },
|
||||
{ one: "2.1", two: "2.2" },
|
||||
{ one: "3.1", two: "3.2" },
|
||||
{ one: "4.1", two: "4.2" }
|
||||
];
|
||||
|
||||
const columns = [
|
||||
{ accessor: "one", Header: "One" },
|
||||
{ accessor: "two", Header: "Two" }
|
||||
];
|
||||
|
||||
export default class Story extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
Test
|
||||
<ReactTable data={data} columns={columns} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{"version":3,"file":"static/manager.4dc6928017acc8856e42.bundle.js","sources":["webpack:///static/manager.4dc6928017acc8856e42.bundle.js"],"mappings":"AAAA;AAmuDA;AA64DA;AA28DA;AA00DA;AAsvEA;AAuhDA;AAsrDA;AAsiDA;AAg6DA;AA2nDA;AA++CA;AAkvDA;AAsnEA;AA2oDA;AAivCA;AA+nDA;AAkpDA;AA6lEA;AAs4DA;AAquDA;AA+pDA;AAoxDA;AAsrDA;AAkzDA;AA88GA;AAj6CA;AAopGA;AAsuFA;AA+zEA;AAtMA;AAo0EA","sourceRoot":""}
|
||||
@@ -1 +0,0 @@
|
||||
{"version":3,"file":"static/preview.b8deff9f16f0debf5b04.bundle.js","sources":["webpack:///static/preview.b8deff9f16f0debf5b04.bundle.js"],"mappings":"AAAA;AAsnDA;AAg2EA;AA48EA;AA2lFA;AAmhQA;AA2/DA;AAguDA;AA8kEA;AA4xDA;AAo2DA;AAkwDA;AAunDA;AAsiDA;AA84DA;AA+nDA;AA69CA;AAunDA;AAqlEA;AA48DA;AAqgCA;AA+uDA;AAwmDA;AAiqEA;AA80DA;AAg2DA;AAwxCA;AAwqFA;AAmjGA;AA+mDA;AAk9CA;AA0xCA;AA60CA;AA8tCA;AAmmDA;AAiiBA;AAWA;AAmsEA;AAwEA;AAq9BA","sourceRoot":""}
|
||||
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 152 KiB |
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "react-table",
|
||||
"version": "6.0.1",
|
||||
"version": "6.10.0",
|
||||
"description": "A fast, lightweight, opinionated table and datagrid built on React",
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/tannerlinsley/react-table#readme",
|
||||
"homepage": "https://github.com/react-tools/react-table#readme",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/tannerlinsley/react-table.git"
|
||||
"url": "git+https://github.com/react-tools/react-table.git"
|
||||
},
|
||||
"keywords": [
|
||||
"react",
|
||||
@@ -15,76 +15,123 @@
|
||||
"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:node": "babel src --out-dir lib --source-maps inline",
|
||||
"build:css": "rimraf react-table.css && stylus src/index.styl --compress -o react-table.css && yarn run css:autoprefix",
|
||||
"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",
|
||||
"css:autoprefix": "postcss --use autoprefixer react-table.css -r",
|
||||
"watch": "npm-run-all --parallel watch:*",
|
||||
"watch:node": "onchange 'src/**/*.js' -i -- npm run build:node",
|
||||
"watch:css": "onchange 'src/**/*.styl' -i -- npm run build:css",
|
||||
"test": "standard",
|
||||
"umd": "rimraf react-table.js && webpack --config umd.webpack.js",
|
||||
"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": "npm run build && npm run umd",
|
||||
"prepublish": "yarn build",
|
||||
"postpublish": "git push --tags",
|
||||
"storybook": "start-storybook -p 8000 -c .storybook",
|
||||
"docs": "build-storybook -o docs && cp .storybook/CNAME docs/CNAME"
|
||||
"docs": "yarn watch & cd docs && yarn && yarn start",
|
||||
"docs:build": "yarn build && cd docs && yarn && yarn build"
|
||||
},
|
||||
"dependencies": {
|
||||
"classnames": "^2.2.5",
|
||||
"raw-loader": "^0.5.1"
|
||||
"classnames": "^2.2.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^15.x.x"
|
||||
"prop-types": "^15.5.0",
|
||||
"react": "^15.x.x || ^16.x.x",
|
||||
"react-dom": "^15.x.x || ^16.x.x"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@kadira/storybook": "^2.35.1",
|
||||
"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",
|
||||
"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",
|
||||
"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",
|
||||
"onchange": "^3.0.2",
|
||||
"postcss-cli": "^2.6.0",
|
||||
"react": "^15.4.2",
|
||||
"react-dom": "^15.4.2",
|
||||
"react-json-tree": "^0.10.1",
|
||||
"prop-types": "^15.6.0",
|
||||
"react": "^16.3.2",
|
||||
"react-dom": "^16.3.2",
|
||||
"react-json-tree": "^0.10.9",
|
||||
"rimraf": "^2.6.1",
|
||||
"standard": "^8.0.0",
|
||||
"storybook": "^0.0.0",
|
||||
"stylus": "^0.54.5",
|
||||
"webpack": "^2.4.1"
|
||||
},
|
||||
"standard": {
|
||||
"parser": "babel-eslint",
|
||||
"ignore": [
|
||||
"node_modules",
|
||||
"dist",
|
||||
"lib",
|
||||
"example",
|
||||
"react-table.js",
|
||||
"stories",
|
||||
"docs"
|
||||
]
|
||||
"rollup": "^0.55.3",
|
||||
"rollup-plugin-babel": "^3.0.3",
|
||||
"rollup-plugin-commonjs": "^8.3.0",
|
||||
"rollup-plugin-node-resolve": "^3.0.2",
|
||||
"rollup-plugin-replace": "^2.0.0",
|
||||
"rollup-plugin-uglify": "^3.0.0",
|
||||
"standard": "^10.0.2",
|
||||
"stylus": "^0.54.5"
|
||||
},
|
||||
"babel": {
|
||||
"presets": [
|
||||
"es2015",
|
||||
"stage-2",
|
||||
"react"
|
||||
]
|
||||
"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"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
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
|
||||
@@ -9,10 +9,14 @@ 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,
|
||||
@@ -20,20 +24,24 @@ export default {
|
||||
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
|
||||
},
|
||||
defaultSortMethod: (a, b) => {
|
||||
// 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
|
||||
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
|
||||
@@ -44,7 +52,8 @@ export default {
|
||||
if (a < b) {
|
||||
return -1
|
||||
}
|
||||
// returning 0, undefined or any falsey value will use subsequent sorts or the index as a tiebreaker
|
||||
// returning 0, undefined or any falsey value will use subsequent sorts or
|
||||
// the index as a tiebreaker
|
||||
return 0
|
||||
},
|
||||
|
||||
@@ -119,12 +128,14 @@ export default {
|
||||
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: {},
|
||||
@@ -140,7 +151,8 @@ export default {
|
||||
footerStyle: {},
|
||||
getFooterProps: emptyObj,
|
||||
filterMethod: undefined,
|
||||
sortMethod: undefined
|
||||
filterAll: false,
|
||||
sortMethod: undefined,
|
||||
},
|
||||
|
||||
// Global Expander Column Defaults
|
||||
@@ -148,7 +160,7 @@ export default {
|
||||
sortable: false,
|
||||
resizable: false,
|
||||
filterable: false,
|
||||
width: 35
|
||||
width: 35,
|
||||
},
|
||||
|
||||
pivotDefaults: {
|
||||
@@ -163,73 +175,96 @@ export default {
|
||||
pageText: 'Page',
|
||||
ofText: 'of',
|
||||
rowsText: 'rows',
|
||||
pageJumpText: 'jump to page',
|
||||
rowsSelectorText: 'rows per page',
|
||||
|
||||
// Components
|
||||
TableComponent: _.makeTemplateComponent('rt-table'),
|
||||
TheadComponent: _.makeTemplateComponent('rt-thead'),
|
||||
TbodyComponent: _.makeTemplateComponent('rt-tbody'),
|
||||
TrGroupComponent: _.makeTemplateComponent('rt-tr-group'),
|
||||
TrComponent: _.makeTemplateComponent('rt-tr'),
|
||||
ThComponent: ({toggleSort, className, children, ...rest}) => {
|
||||
return (
|
||||
<div
|
||||
className={classnames(className, 'rt-th')}
|
||||
onClick={e => {
|
||||
toggleSort && toggleSort(e)
|
||||
}}
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
},
|
||||
TdComponent: _.makeTemplateComponent('rt-td'),
|
||||
TfootComponent: _.makeTemplateComponent('rt-tfoot'),
|
||||
FilterComponent: ({filter, onChange}) => (
|
||||
<input type='text'
|
||||
style={{
|
||||
width: '100%'
|
||||
}}
|
||||
value={filter ? filter.value : ''}
|
||||
onChange={(event) => onChange(event.target.value)}
|
||||
/>
|
||||
),
|
||||
ExpanderComponent: ({isExpanded}) => (
|
||||
<div className={classnames('rt-expander', isExpanded && '-open')}>
|
||||
•
|
||||
TableComponent: ({ children, className, ...rest }) => (
|
||||
<div
|
||||
className={classnames('rt-table', className)}
|
||||
role="grid"
|
||||
// tabIndex='0'
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
),
|
||||
PivotValueComponent: ({subRows, value}) => (
|
||||
<span>{value} {subRows && `(${subRows.length})`}</span>
|
||||
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>
|
||||
),
|
||||
AggregatedComponent: ({subRows, column}) => {
|
||||
const previewValues = subRows
|
||||
.filter(d => typeof d[column.id] !== 'undefined')
|
||||
.map((row, i) => (
|
||||
<span key={i}>{row[column.id]}{i < subRows.length - 1 ? ', ' : ''}</span>
|
||||
))
|
||||
return (
|
||||
<span>{previewValues}</span>
|
||||
)
|
||||
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')}>•</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>
|
||||
LoadingComponent: ({
|
||||
className, loading, loadingText, ...rest
|
||||
}) => (
|
||||
<div className={classnames('-loading', { '-active': loading }, className)} {...rest}>
|
||||
<div className="-loading-inner">{loadingText}</div>
|
||||
</div>
|
||||
),
|
||||
NoDataComponent: _.makeTemplateComponent('rt-noData'),
|
||||
ResizerComponent: _.makeTemplateComponent('rt-resizer')
|
||||
NoDataComponent: _.makeTemplateComponent('rt-noData', 'NoData'),
|
||||
ResizerComponent: _.makeTemplateComponent('rt-resizer', 'Resizer'),
|
||||
PadRowComponent: () => <span> </span>,
|
||||
}
|
||||
|
||||
@@ -0,0 +1,199 @@
|
||||
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.
|
||||
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}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
/* 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 || [],
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<?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>
|
||||
|
After Width: | Height: | Size: 583 B |
@@ -0,0 +1 @@
|
||||
<?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>
|
||||
|
After Width: | Height: | Size: 585 B |
@@ -0,0 +1,119 @@
|
||||
/* 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
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/* 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
|
||||
}
|
||||
@@ -2,12 +2,24 @@ $easeOutQuad = cubic-bezier(0.250, 0.460, 0.450, 0.940)
|
||||
$easeOutBack = cubic-bezier(0.175, 0.885, 0.320, 1.275)
|
||||
$expandSize = 7px
|
||||
|
||||
input-select-style()
|
||||
border: 1px solid rgba(0,0,0,0.1)
|
||||
background: white
|
||||
padding: 5px 7px
|
||||
font-size: inherit
|
||||
border-radius: 3px
|
||||
font-weight: normal
|
||||
outline:none
|
||||
|
||||
.ReactTable
|
||||
position:relative
|
||||
display: flex
|
||||
flex-direction: column
|
||||
border: 1px solid alpha(black, .1)
|
||||
*
|
||||
box-sizing: border-box
|
||||
.rt-table
|
||||
flex: auto 1
|
||||
display: flex
|
||||
flex-direction: column
|
||||
align-items: stretch
|
||||
@@ -16,6 +28,7 @@ $expandSize = 7px
|
||||
overflow: auto
|
||||
|
||||
.rt-thead
|
||||
flex: 1 0 auto
|
||||
display: flex
|
||||
flex-direction: column
|
||||
-webkit-user-select: none;
|
||||
@@ -30,6 +43,10 @@ $expandSize = 7px
|
||||
&.-filters
|
||||
border-bottom: 1px solid alpha(black, 0.05)
|
||||
|
||||
input
|
||||
select
|
||||
input-select-style();
|
||||
|
||||
.rt-th
|
||||
border-right: 1px solid alpha(black, 0.02)
|
||||
|
||||
@@ -56,6 +73,9 @@ $expandSize = 7px
|
||||
&:last-child
|
||||
border-right: 0
|
||||
|
||||
.rt-th:focus
|
||||
outline: none
|
||||
|
||||
.rt-resizable-header
|
||||
overflow: visible
|
||||
&:last-child
|
||||
@@ -91,8 +111,10 @@ $expandSize = 7px
|
||||
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)
|
||||
@@ -104,11 +126,14 @@ $expandSize = 7px
|
||||
border-right:0
|
||||
.rt-expandable
|
||||
cursor: pointer
|
||||
text-overflow: clip
|
||||
.rt-tr-group
|
||||
flex: 1 0 auto
|
||||
display: flex
|
||||
flex-direction: column
|
||||
align-items: stretch
|
||||
.rt-tr
|
||||
flex: 1 0 auto
|
||||
display: inline-flex
|
||||
.rt-th
|
||||
.rt-td
|
||||
@@ -160,6 +185,7 @@ $expandSize = 7px
|
||||
z-index: 10
|
||||
|
||||
.rt-tfoot
|
||||
flex: 1 0 auto
|
||||
display: flex
|
||||
flex-direction: column
|
||||
box-shadow: 0 0px 15px 0px alpha(black, .15)
|
||||
@@ -187,11 +213,15 @@ $expandSize = 7px
|
||||
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
|
||||
@@ -261,7 +291,7 @@ $expandSize = 7px
|
||||
bottom:0
|
||||
background: alpha(white, .8)
|
||||
transition: all .3s ease
|
||||
z-index: 2
|
||||
z-index: -1
|
||||
opacity: 0
|
||||
pointer-events: none
|
||||
|
||||
@@ -279,40 +309,11 @@ $expandSize = 7px
|
||||
|
||||
&.-active
|
||||
opacity: 1
|
||||
z-index: 2
|
||||
pointer-events: all
|
||||
> div
|
||||
transform: translateY(50%)
|
||||
|
||||
input
|
||||
select
|
||||
border: 1px solid rgba(0,0,0,0.1)
|
||||
background: white
|
||||
padding: 5px 7px
|
||||
font-size: inherit
|
||||
border-radius: 3px
|
||||
font-weight: normal
|
||||
outline:none
|
||||
|
||||
input:not([type="checkbox"]):not([type="radio"])
|
||||
select
|
||||
appearance: none
|
||||
|
||||
.select-wrap
|
||||
position:relative
|
||||
display:inline-block
|
||||
select
|
||||
padding: 5px 15px 5px 7px
|
||||
min-width:100px
|
||||
&:after
|
||||
content: ''
|
||||
position: absolute
|
||||
right: 8px
|
||||
top: 50%
|
||||
transform: translate(0, -50%)
|
||||
border-color: #999 transparent transparent
|
||||
border-style: solid
|
||||
border-width: 5px 5px 2.5px
|
||||
|
||||
.rt-resizing
|
||||
.rt-th
|
||||
.rt-td
|
||||
|
||||
@@ -1,101 +1,128 @@
|
||||
export default Base => class extends Base {
|
||||
|
||||
componentWillMount () {
|
||||
this.setStateWithData(this.getDataModel(this.getResolvedState()))
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
this.fireFetchData()
|
||||
}
|
||||
|
||||
componentWillReceiveProps (nextProps, nextState) {
|
||||
const oldState = this.getResolvedState()
|
||||
const newState = this.getResolvedState(nextProps, nextState)
|
||||
|
||||
// Do a deep compare of new and old `defaultOption` and
|
||||
// if they are different reset `option = defaultOption`
|
||||
const defaultableOptions = ['sorted', 'filtered', 'resized', 'expanded']
|
||||
defaultableOptions.forEach(x => {
|
||||
const defaultName = `default${x.charAt(0).toUpperCase() + x.slice(1)}`
|
||||
if (JSON.stringify(oldState[defaultName]) !== JSON.stringify(newState[defaultName])) {
|
||||
newState[x] = newState[defaultName]
|
||||
}
|
||||
})
|
||||
|
||||
// If they change these table options, we need to reset defaults
|
||||
// or else we could get into a state where the user has changed the UI
|
||||
// and then disabled the ability to change it back.
|
||||
// e.g. If `filterable` has changed, set `filtered = defaultFiltered`
|
||||
const resettableOptions = ['sortable', 'filterable', 'resizable']
|
||||
resettableOptions.forEach(x => {
|
||||
if (oldState[x] !== newState[x]) {
|
||||
const baseName = x.replace('able', '')
|
||||
const optionName = `${baseName}ed`
|
||||
const defaultName = `default${optionName.charAt(0).toUpperCase() + optionName.slice(1)}`
|
||||
newState[optionName] = newState[defaultName]
|
||||
}
|
||||
})
|
||||
|
||||
// Props that trigger a data update
|
||||
if (
|
||||
oldState.data !== newState.data ||
|
||||
oldState.columns !== newState.columns ||
|
||||
oldState.pivotBy !== newState.pivotBy ||
|
||||
oldState.sorted !== newState.sorted ||
|
||||
oldState.filtered !== newState.filtered
|
||||
) {
|
||||
this.setStateWithData(this.getDataModel(newState))
|
||||
export default Base =>
|
||||
class extends Base {
|
||||
componentWillMount () {
|
||||
this.setStateWithData(this.getDataModel(this.getResolvedState(), true))
|
||||
}
|
||||
}
|
||||
|
||||
setStateWithData (newState, cb) {
|
||||
const oldState = this.getResolvedState()
|
||||
const newResolvedState = this.getResolvedState({}, newState)
|
||||
const {freezeWhenExpanded} = newResolvedState
|
||||
componentDidMount () {
|
||||
this.fireFetchData()
|
||||
}
|
||||
|
||||
// Default to unfrozen state
|
||||
newResolvedState.frozen = false
|
||||
componentWillReceiveProps (nextProps, nextState) {
|
||||
const oldState = this.getResolvedState()
|
||||
const newState = this.getResolvedState(nextProps, nextState)
|
||||
|
||||
// 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 (var i = 0; i < keys.length; i++) {
|
||||
if (newResolvedState.expanded[keys[i]]) {
|
||||
newResolvedState.frozen = true
|
||||
break
|
||||
// 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 the data isn't frozen and either the data or
|
||||
// sorting model has changed, update the data
|
||||
if (
|
||||
(oldState.sorted !== newResolvedState.sorted && this.props.collapseOnSortingChange) ||
|
||||
(oldState.filtered !== newResolvedState.filtered) ||
|
||||
(oldState.showFilters !== newResolvedState.showFilters) ||
|
||||
(!newResolvedState.frozen && oldState.resolvedData !== newResolvedState.resolvedData && this.props.collapseOnDataChange)
|
||||
(oldState.frozen && !newResolvedState.frozen) ||
|
||||
oldState.sorted !== newResolvedState.sorted ||
|
||||
oldState.filtered !== newResolvedState.filtered ||
|
||||
oldState.showFilters !== newResolvedState.showFilters ||
|
||||
(!newResolvedState.frozen && oldState.resolvedData !== newResolvedState.resolvedData)
|
||||
) {
|
||||
newResolvedState.expanded = {}
|
||||
// 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))
|
||||
}
|
||||
|
||||
Object.assign(newResolvedState, this.getSortedData(newResolvedState))
|
||||
}
|
||||
// Set page to 0 if filters change
|
||||
if (oldState.filtered !== newResolvedState.filtered) {
|
||||
newResolvedState.page = 0
|
||||
}
|
||||
|
||||
// Calculate pageSize all the time
|
||||
if (newResolvedState.sortedData) {
|
||||
newResolvedState.pages = newResolvedState.manual ? newResolvedState.pages : Math.ceil(newResolvedState.sortedData.length / newResolvedState.pageSize)
|
||||
newResolvedState.page = Math.max(newResolvedState.page >= newResolvedState.pages ? newResolvedState.pages - 1 : newResolvedState.page, 0)
|
||||
}
|
||||
// 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, cb)
|
||||
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()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,31 +1,76 @@
|
||||
import React, { Component } 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 type="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()
|
||||
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
|
||||
page: props.page,
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
this.setState({page: nextProps.page})
|
||||
if (this.props.page !== nextProps.page) {
|
||||
this.setState({ page: nextProps.page })
|
||||
}
|
||||
}
|
||||
|
||||
getSafePage (page) {
|
||||
if (isNaN(page)) {
|
||||
if (Number.isNaN(page)) {
|
||||
page = this.props.page
|
||||
}
|
||||
return Math.min(Math.max(page, 0), this.props.pages - 1)
|
||||
@@ -33,18 +78,42 @@ export default class ReactTablePagination extends Component {
|
||||
|
||||
changePage (page) {
|
||||
page = this.getSafePage(page)
|
||||
this.setState({page})
|
||||
this.setState({ page })
|
||||
if (this.props.page !== page) {
|
||||
this.props.onPageChange(page)
|
||||
}
|
||||
}
|
||||
|
||||
applyPage (e) {
|
||||
e && e.preventDefault()
|
||||
if (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
|
||||
@@ -59,18 +128,19 @@ export default class ReactTablePagination extends Component {
|
||||
canNext,
|
||||
onPageSizeChange,
|
||||
className,
|
||||
PreviousComponent = defaultButton,
|
||||
NextComponent = defaultButton
|
||||
PreviousComponent,
|
||||
NextComponent,
|
||||
renderPageJump,
|
||||
renderCurrentPage,
|
||||
renderTotalPagesCount,
|
||||
renderPageSizeOptions,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classnames(className, '-pagination')}
|
||||
style={this.props.paginationStyle}
|
||||
>
|
||||
<div className='-previous'>
|
||||
<div className={classnames(className, '-pagination')} style={this.props.style}>
|
||||
<div className="-previous">
|
||||
<PreviousComponent
|
||||
onClick={(e) => {
|
||||
onClick={() => {
|
||||
if (!canPrevious) return
|
||||
this.changePage(page - 1)
|
||||
}}
|
||||
@@ -79,55 +149,24 @@ export default class ReactTablePagination extends Component {
|
||||
{this.props.previousText}
|
||||
</PreviousComponent>
|
||||
</div>
|
||||
<div className='-center'>
|
||||
<span className='-pageInfo'>
|
||||
{this.props.pageText} {showPageJump ? (
|
||||
<div className='-pageJump'>
|
||||
<input
|
||||
type={this.state.page === '' ? 'text' : 'number'}
|
||||
onChange={e => {
|
||||
const val = e.target.value
|
||||
const page = val - 1
|
||||
if (val === '') {
|
||||
return this.setState({page: val})
|
||||
}
|
||||
this.setState({page: this.getSafePage(page)})
|
||||
}}
|
||||
value={this.state.page === '' ? '' : this.state.page + 1}
|
||||
onBlur={this.applyPage}
|
||||
onKeyPress={e => {
|
||||
if (e.which === 13 || e.keyCode === 13) {
|
||||
this.applyPage()
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<span className='-currentPage'>{page + 1}</span>
|
||||
)} {this.props.ofText} <span className='-totalPages'>{pages || 1}</span>
|
||||
<div className="-center">
|
||||
<span className="-pageInfo">
|
||||
{this.props.pageText}{' '}
|
||||
{showPageJump ? renderPageJump(this.getPageJumpProperties()) : renderCurrentPage(page)}{' '}
|
||||
{this.props.ofText} {renderTotalPagesCount(pages)}
|
||||
</span>
|
||||
{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>
|
||||
)}
|
||||
{showPageSizeOptions &&
|
||||
renderPageSizeOptions({
|
||||
pageSize,
|
||||
rowsSelectorText: this.props.rowsSelectorText,
|
||||
pageSizeOptions,
|
||||
onPageSizeChange,
|
||||
rowsText: this.props.rowsText,
|
||||
})}
|
||||
</div>
|
||||
<div className='-next'>
|
||||
<div className="-next">
|
||||
<NextComponent
|
||||
onClick={(e) => {
|
||||
onClick={() => {
|
||||
if (!canNext) return
|
||||
this.changePage(page + 1)
|
||||
}}
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
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.oneOfType([PropTypes.func, PropTypes.element]),
|
||||
TheadComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
|
||||
TbodyComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
|
||||
TrGroupComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
|
||||
TrComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
|
||||
ThComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
|
||||
TdComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
|
||||
TfootComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
|
||||
FilterComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
|
||||
ExpanderComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
|
||||
PivotValueComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
|
||||
AggregatedComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
|
||||
// this is a computed default generated using
|
||||
PivotComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
|
||||
// the ExpanderComponent and PivotValueComponent at run-time in methods.js
|
||||
PaginationComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
|
||||
PreviousComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
|
||||
NextComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
|
||||
LoadingComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
|
||||
NoDataComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
|
||||
ResizerComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
|
||||
PadRowComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
|
||||
}
|
||||
@@ -18,7 +18,8 @@ export default {
|
||||
splitProps,
|
||||
compactObject,
|
||||
isSortingDesc,
|
||||
normalizeComponent
|
||||
normalizeComponent,
|
||||
asPx,
|
||||
}
|
||||
|
||||
function get (obj, path, def) {
|
||||
@@ -29,7 +30,9 @@ function get (obj, path, def) {
|
||||
let val
|
||||
try {
|
||||
val = pathObj.reduce((current, pathPart) => current[pathPart], obj)
|
||||
} catch (e) {}
|
||||
} catch (e) {
|
||||
// continue regardless of error
|
||||
}
|
||||
return typeof val !== 'undefined' ? val : def
|
||||
}
|
||||
|
||||
@@ -58,7 +61,7 @@ function last (arr) {
|
||||
|
||||
function range (n) {
|
||||
const arr = []
|
||||
for (let i = 0; i < n; i++) {
|
||||
for (let i = 0; i < n; i += 1) {
|
||||
arr.push(n)
|
||||
}
|
||||
return arr
|
||||
@@ -66,7 +69,7 @@ function range (n) {
|
||||
|
||||
function orderBy (arr, funcs, dirs, indexKey) {
|
||||
return arr.sort((rowA, rowB) => {
|
||||
for (let i = 0; i < funcs.length; i++) {
|
||||
for (let i = 0; i < funcs.length; i += 1) {
|
||||
const comp = funcs[i]
|
||||
const desc = dirs[i] === false || dirs[i] === 'desc'
|
||||
const sortInt = comp(rowA, rowB)
|
||||
@@ -75,15 +78,13 @@ function orderBy (arr, funcs, dirs, indexKey) {
|
||||
}
|
||||
}
|
||||
// Use the row index for tie breakers
|
||||
return dirs[0]
|
||||
? rowA[indexKey] - rowB[indexKey]
|
||||
: rowB[indexKey] - rowA[indexKey]
|
||||
return dirs[0] ? rowA[indexKey] - rowB[indexKey] : rowB[indexKey] - rowA[indexKey]
|
||||
})
|
||||
}
|
||||
|
||||
function remove (a, b) {
|
||||
return a.filter(function (o, i) {
|
||||
var r = b(o)
|
||||
return a.filter((o, i) => {
|
||||
const r = b(o)
|
||||
if (r) {
|
||||
a.splice(i, 1)
|
||||
return true
|
||||
@@ -94,19 +95,21 @@ 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 (var i = 0; i < args.length; i++) {
|
||||
for (let i = 0; i < args.length; i += 1) {
|
||||
if (typeof args[i] !== 'undefined') {
|
||||
return args[i]
|
||||
}
|
||||
@@ -114,20 +117,20 @@ function getFirstDefined (...args) {
|
||||
}
|
||||
|
||||
function sum (arr) {
|
||||
return arr.reduce((a, b) => {
|
||||
return a + b
|
||||
}, 0)
|
||||
return arr.reduce((a, b) => a + b, 0)
|
||||
}
|
||||
|
||||
function makeTemplateComponent (compClass) {
|
||||
return ({children, className, ...rest}) => (
|
||||
<div
|
||||
className={classnames(compClass, className)}
|
||||
{...rest}
|
||||
>
|
||||
function makeTemplateComponent (compClass, displayName) {
|
||||
if (!displayName) {
|
||||
throw new Error('No displayName found for template component:', compClass)
|
||||
}
|
||||
const cmp = ({ children, className, ...rest }) => (
|
||||
<div className={classnames(compClass, className)} {...rest}>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
cmp.displayName = displayName
|
||||
return cmp
|
||||
}
|
||||
|
||||
function groupBy (xs, key) {
|
||||
@@ -139,6 +142,11 @@ function groupBy (xs, key) {
|
||||
}, {})
|
||||
}
|
||||
|
||||
function asPx (value) {
|
||||
value = Number(value)
|
||||
return Number.isNaN(value) ? null : `${value}px`
|
||||
}
|
||||
|
||||
function isArray (a) {
|
||||
return Array.isArray(a)
|
||||
}
|
||||
@@ -149,37 +157,44 @@ function isArray (a) {
|
||||
|
||||
function makePathArray (obj) {
|
||||
return flattenDeep(obj)
|
||||
.join('.')
|
||||
.replace('[', '.')
|
||||
.replace(']', '')
|
||||
.split('.')
|
||||
.join('.')
|
||||
.replace(/\[/g, '.')
|
||||
.replace(/\]/g, '')
|
||||
.split('.')
|
||||
}
|
||||
|
||||
function flattenDeep (arr, newArr = []) {
|
||||
if (!isArray(arr)) {
|
||||
newArr.push(arr)
|
||||
} else {
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
for (let i = 0; i < arr.length; i += 1) {
|
||||
flattenDeep(arr[i], newArr)
|
||||
}
|
||||
}
|
||||
return newArr
|
||||
}
|
||||
|
||||
function splitProps ({className, style, ...rest}) {
|
||||
function splitProps ({ className, style, ...rest }) {
|
||||
return {
|
||||
className,
|
||||
style,
|
||||
rest
|
||||
rest: rest || {},
|
||||
}
|
||||
}
|
||||
|
||||
function compactObject (obj) {
|
||||
const newObj = {}
|
||||
for (var key in obj) {
|
||||
if (obj.hasOwnProperty(key) && obj[key] !== undefined && typeof obj[key] !== 'undefined') {
|
||||
newObj[key] = obj[key]
|
||||
}
|
||||
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
|
||||
}
|
||||
@@ -189,11 +204,5 @@ function isSortingDesc (d) {
|
||||
}
|
||||
|
||||
function normalizeComponent (Comp, params = {}, fallback = Comp) {
|
||||
return typeof Comp === 'function' ? (
|
||||
Object.getPrototypeOf(Comp).isReactComponent ? (
|
||||
<Comp
|
||||
{...params}
|
||||
/>
|
||||
) : Comp(params)
|
||||
) : fallback
|
||||
return typeof Comp === 'function' ? <Comp {...params} /> : fallback
|
||||
}
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
import React from 'react'
|
||||
import _ from 'lodash'
|
||||
import namor from 'namor'
|
||||
|
||||
import ReactTable from '../src/index'
|
||||
|
||||
class Story extends React.Component {
|
||||
render () {
|
||||
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',
|
||||
Cell: row => (
|
||||
<div
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
backgroundColor: '#dadada',
|
||||
borderRadius: '2px'
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
width: `${row.value}%`,
|
||||
height: '100%',
|
||||
backgroundColor: row.value > 66 ? '#85cc00'
|
||||
: row.value > 33 ? '#ffbf00'
|
||||
: '#ff2e00',
|
||||
borderRadius: '2px',
|
||||
transition: 'all .2s ease-out'
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}, {
|
||||
Header: 'Status',
|
||||
accessor: 'status',
|
||||
Cell: row => (
|
||||
<span>
|
||||
<span style={{
|
||||
color: row.value === 'relationship' ? '#ff2e00'
|
||||
: row.value === 'complicated' ? '#ffbf00'
|
||||
: '#57d500',
|
||||
transition: 'all .3s ease'
|
||||
}}>
|
||||
●
|
||||
</span> {
|
||||
row.value === 'relationship' ? 'In a relationship'
|
||||
: row.value === 'complicated' ? `It's complicated`
|
||||
: 'Single'
|
||||
}
|
||||
</span>
|
||||
)
|
||||
}]
|
||||
}]
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className='table-wrap'>
|
||||
<ReactTable
|
||||
className='-striped -highlight'
|
||||
data={data}
|
||||
columns={columns}
|
||||
defaultPageSize={10}
|
||||
/>
|
||||
</div>
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<br />
|
||||
<em>Tip: Hold shift when sorting to multi-sort!</em>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Source Code
|
||||
const CodeHighlight = require('./components/codeHighlight').default
|
||||
const source = require('!raw-loader!./CellRenderers')
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<Story />
|
||||
<CodeHighlight>{() => source}</CodeHighlight>
|
||||
</div>
|
||||
)
|
||||
@@ -1,88 +0,0 @@
|
||||
import React from 'react'
|
||||
import _ from 'lodash'
|
||||
import namor from 'namor'
|
||||
|
||||
import ReactTable from '../src/index'
|
||||
|
||||
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'
|
||||
}]
|
||||
}]
|
||||
|
||||
class Story extends React.Component {
|
||||
constructor () {
|
||||
super()
|
||||
this.state = {
|
||||
sorted: [],
|
||||
page: 0,
|
||||
pageSize: 10,
|
||||
expanded: {},
|
||||
resized: [],
|
||||
filtered: []
|
||||
}
|
||||
}
|
||||
render () {
|
||||
return (
|
||||
<div>
|
||||
<div className='table-wrap'>
|
||||
<ReactTable
|
||||
className='-striped -highlight'
|
||||
data={data}
|
||||
columns={columns}
|
||||
pivotBy={['lastName']}
|
||||
filterable
|
||||
// Controlled Props
|
||||
sorted={this.state.sorted}
|
||||
page={this.state.page}
|
||||
pageSize={this.state.pageSize}
|
||||
expanded={this.state.expanded}
|
||||
resized={this.state.resized}
|
||||
filtered={this.state.filtered}
|
||||
// Callbacks
|
||||
onSortedChange={sorted => this.setState({sorted})}
|
||||
onPageChange={page => this.setState({page})}
|
||||
onPageSizeChange={(pageSize, page) => this.setState({page, pageSize})}
|
||||
onExpandedChange={expanded => this.setState({expanded})}
|
||||
onResizedChange={resized => this.setState({resized})}
|
||||
onFilteredChange={filtered => this.setState({filtered})}
|
||||
/>
|
||||
</div>
|
||||
<br />
|
||||
<pre><code><strong>this.state ===</strong> {JSON.stringify(this.state, null, 2)}</code></pre>
|
||||
<br />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Source Code
|
||||
const CodeHighlight = require('./components/codeHighlight').default
|
||||
const source = require('!raw-loader!./ControlledTable')
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<Story />
|
||||
<CodeHighlight>{() => source}</CodeHighlight>
|
||||
</div>
|
||||
)
|
||||
@@ -1,75 +0,0 @@
|
||||
import React from 'react'
|
||||
import _ from 'lodash'
|
||||
import namor from 'namor'
|
||||
|
||||
import ReactTable from '../src/index'
|
||||
|
||||
class Story extends React.Component {
|
||||
render () {
|
||||
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>
|
||||
<strong>Hey!</strong> Open your console! :)
|
||||
<div className='table-wrap'>
|
||||
<ReactTable
|
||||
className='-striped -highlight'
|
||||
data={data}
|
||||
columns={columns}
|
||||
defaultPageSize={10}
|
||||
getTdProps={(state, rowInfo, column, instance) => {
|
||||
return {
|
||||
onMouseEnter: e => console.log('Cell - onMouseEnter', {
|
||||
state,
|
||||
rowInfo,
|
||||
column,
|
||||
instance,
|
||||
event: e
|
||||
})
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<br />
|
||||
<em>Tip: Hold shift when sorting to multi-sort!</em>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Source Code
|
||||
const CodeHighlight = require('./components/codeHighlight').default
|
||||
const source = require('!raw-loader!./CustomComponentProps')
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<Story />
|
||||
<CodeHighlight>{() => source}</CodeHighlight>
|
||||
</div>
|
||||
)
|
||||
@@ -1,80 +0,0 @@
|
||||
import React from 'react'
|
||||
import _ from 'lodash'
|
||||
import namor from 'namor'
|
||||
|
||||
import ReactTable from '../src/index'
|
||||
|
||||
class Story extends React.Component {
|
||||
render () {
|
||||
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',
|
||||
Footer: () => <div style={{textAlign: 'center'}}>First Name</div>
|
||||
}, {
|
||||
Header: 'Last Name',
|
||||
accessor: 'lastName',
|
||||
Footer: () => <div style={{textAlign: 'center'}}>Last Name</div>
|
||||
}]
|
||||
}, {
|
||||
Header: 'Info',
|
||||
columns: [{
|
||||
Header: 'Age',
|
||||
accessor: 'age',
|
||||
Footer: () => <div style={{textAlign: 'center'}}>Age</div>
|
||||
}]
|
||||
}, {
|
||||
Header: 'Expand',
|
||||
columns: [{
|
||||
expander: true,
|
||||
Header: () => (<strong>More</strong>),
|
||||
width: 65,
|
||||
Expander: ({isExpanded, ...rest}) => (
|
||||
<div>
|
||||
{isExpanded ? <span>⊙</span> : <span>⊕</span>}
|
||||
</div>
|
||||
),
|
||||
style: {cursor: 'pointer', fontSize: 25, padding: '0', textAlign: 'center', userSelect: 'none'},
|
||||
Footer: () => <span>♥</span>
|
||||
}]
|
||||
}]
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className='table-wrap'>
|
||||
<ReactTable
|
||||
className='-striped -highlight'
|
||||
data={data}
|
||||
columns={columns}
|
||||
defaultPageSize={10}
|
||||
SubComponent={() => <span>Hello</span>}
|
||||
/>
|
||||
</div>
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<br />
|
||||
<em>Tip: Hold shift when sorting to multi-sort!</em>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Source Code
|
||||
const CodeHighlight = require('./components/codeHighlight').default
|
||||
const source = require('!raw-loader!./CustomExpanderPosition')
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<Story />
|
||||
<CodeHighlight>{() => source}</CodeHighlight>
|
||||
</div>
|
||||
)
|
||||
@@ -1,77 +0,0 @@
|
||||
import React from 'react'
|
||||
import _ from 'lodash'
|
||||
import namor from 'namor'
|
||||
|
||||
import ReactTable from '../src/index'
|
||||
|
||||
class Story extends React.Component {
|
||||
render () {
|
||||
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 (Sorted by Length, A-Z)',
|
||||
accessor: 'firstName',
|
||||
sortMethod: (a, b) => {
|
||||
if (a.length === b.length) {
|
||||
return a > b ? 1 : -1
|
||||
}
|
||||
return a.length > b.length ? 1 : -1
|
||||
}
|
||||
}, {
|
||||
Header: 'Last Name (Sorted in reverse, A-Z)',
|
||||
id: 'lastName',
|
||||
accessor: d => d.lastName,
|
||||
sortMethod: (a, b) => {
|
||||
if (a === b) {
|
||||
return 0
|
||||
}
|
||||
const aReverse = a.split('').reverse().join('')
|
||||
const bReverse = b.split('').reverse().join('')
|
||||
return aReverse > bReverse ? 1 : -1
|
||||
}
|
||||
}]
|
||||
}, {
|
||||
Header: 'Info',
|
||||
columns: [{
|
||||
Header: 'Age',
|
||||
accessor: 'age'
|
||||
}]
|
||||
}]
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className='table-wrap'>
|
||||
<ReactTable
|
||||
className='-striped -highlight'
|
||||
data={data}
|
||||
columns={columns}
|
||||
defaultPageSize={10}
|
||||
/>
|
||||
</div>
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<br />
|
||||
<em>Tip: Hold shift when sorting to multi-sort!</em>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Source Code
|
||||
const CodeHighlight = require('./components/codeHighlight').default
|
||||
const source = require('!raw-loader!./CustomSorting')
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<Story />
|
||||
<CodeHighlight>{() => source}</CodeHighlight>
|
||||
</div>
|
||||
)
|
||||
@@ -1,66 +0,0 @@
|
||||
import React from 'react'
|
||||
import _ from 'lodash'
|
||||
import namor from 'namor'
|
||||
|
||||
import ReactTable from '../src/index'
|
||||
|
||||
class Story extends React.Component {
|
||||
render () {
|
||||
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>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Source Code
|
||||
const CodeHighlight = require('./components/codeHighlight').default
|
||||
const source = require('!raw-loader!./CustomWidths')
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<Story />
|
||||
<CodeHighlight>{() => source}</CodeHighlight>
|
||||
</div>
|
||||
)
|
||||
@@ -1,67 +0,0 @@
|
||||
import React from 'react'
|
||||
import _ from 'lodash'
|
||||
import namor from 'namor'
|
||||
|
||||
import ReactTable from '../src/index'
|
||||
|
||||
class Story extends React.Component {
|
||||
render () {
|
||||
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}
|
||||
defaultSorted={[{
|
||||
id: 'age',
|
||||
desc: true
|
||||
}]}
|
||||
/>
|
||||
</div>
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<br />
|
||||
<em>Tip: Hold shift when sorting to multi-sort!</em>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Source Code
|
||||
const CodeHighlight = require('./components/codeHighlight').default
|
||||
const source = require('!raw-loader!./DefaultSorting')
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<Story />
|
||||
<CodeHighlight>{() => source}</CodeHighlight>
|
||||
</div>
|
||||
)
|
||||
@@ -1,69 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
import ReactTable from '../src/index'
|
||||
|
||||
class Story extends React.Component {
|
||||
constructor (props, context) {
|
||||
super(props, context)
|
||||
this.renderEditable = this.renderEditable.bind(this)
|
||||
|
||||
this.state = {
|
||||
data: [
|
||||
{ firstName: 'Lucy', lastName: 'Marks' },
|
||||
{ firstName: 'Bejamin', lastName: 'Pike' }
|
||||
]
|
||||
}
|
||||
|
||||
this.columns = [
|
||||
{
|
||||
Header: 'First Name',
|
||||
accessor: 'firstName',
|
||||
Cell: this.renderEditable
|
||||
},
|
||||
{
|
||||
Header: 'Last Name',
|
||||
accessor: 'lastName',
|
||||
Cell: this.renderEditable
|
||||
},
|
||||
{
|
||||
Header: 'Full Name',
|
||||
id: 'full',
|
||||
accessor: d => d.firstName + ' ' + d.lastName
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
renderEditable (cellInfo) {
|
||||
return (<div style={{ backgroundColor: '#fafafa' }} contentEditable suppressContentEditableWarning onBlur={(e) => {
|
||||
const data = [...this.state.data]
|
||||
data[cellInfo.index][cellInfo.column.id] = e.target.textContent
|
||||
this.setState({data: data})
|
||||
}}>{this.state.data[cellInfo.index][cellInfo.column.id]}</div>)
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<div className='table-wrap' style={{marginBottom: '20px'}}>
|
||||
<p>First two columns are editable just by clicking into them using the <code>contentEditable</code> attribute. Last column (Full Name) is computed from the first two.</p>
|
||||
<ReactTable
|
||||
data={this.state.data}
|
||||
columns={this.columns}
|
||||
defaultPageSize={2}
|
||||
showPageSizeOptions={false}
|
||||
showPagination={false}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Source Code
|
||||
const CodeHighlight = require('./components/codeHighlight').default
|
||||
const source = require('!raw-loader!./EditableTable')
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<Story />
|
||||
<CodeHighlight>{() => source}</CodeHighlight>
|
||||
</div>
|
||||
)
|
||||
@@ -1,193 +0,0 @@
|
||||
import React from 'react'
|
||||
import _ from 'lodash'
|
||||
import namor from 'namor'
|
||||
|
||||
import CodeHighlight from './components/codeHighlight'
|
||||
|
||||
import ReactTable from '../src/index'
|
||||
|
||||
class Story extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
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)
|
||||
}
|
||||
})
|
||||
|
||||
this.state = {
|
||||
tableOptions: {
|
||||
loading: false,
|
||||
showPagination: true,
|
||||
showPageSizeOptions: true,
|
||||
showPageJump: true,
|
||||
collapseOnSortingChange: true,
|
||||
collapseOnPageChange: true,
|
||||
collapseOnDataChange: true,
|
||||
freezeWhenExpanded: false,
|
||||
filterable: true,
|
||||
sortable: true,
|
||||
resizable: true
|
||||
},
|
||||
data: data
|
||||
}
|
||||
|
||||
this.setTableOption = this.setTableOption.bind(this)
|
||||
}
|
||||
|
||||
render () {
|
||||
const columns = [{
|
||||
Header: 'Name',
|
||||
columns: [{
|
||||
Header: 'First Name',
|
||||
accessor: 'firstName',
|
||||
filterMethod: (filter, row) => (row[filter.id].startsWith(filter.value) && row[filter.id].endsWith(filter.value))
|
||||
}, {
|
||||
Header: 'Last Name',
|
||||
id: 'lastName',
|
||||
accessor: d => d.lastName,
|
||||
filterMethod: (filter, row) => (row[filter.id].includes(filter.value))
|
||||
}]
|
||||
}, {
|
||||
Header: 'Info',
|
||||
columns: [{
|
||||
Header: 'Age',
|
||||
accessor: 'age'
|
||||
}, {
|
||||
Header: 'Over 21',
|
||||
accessor: 'age',
|
||||
id: 'over',
|
||||
Cell: ({value}) => (value >= 21 ? 'Yes' : 'No'),
|
||||
filterMethod: (filter, row) => {
|
||||
if (filter.value === 'all') {
|
||||
return true
|
||||
}
|
||||
if (filter.value === 'true') {
|
||||
return row[filter.id] >= 21
|
||||
}
|
||||
return row[filter.id] < 21
|
||||
},
|
||||
Filter: ({filter, onChange}) => (
|
||||
<select
|
||||
onChange={event => onChange(event.target.value)}
|
||||
style={{width: '100%'}}
|
||||
value={filter ? filter.value : 'all'}
|
||||
>
|
||||
<option value='all' />
|
||||
<option value='true'>Can Drink</option>
|
||||
<option value='false'>Can't Drink</option>
|
||||
</select>
|
||||
)
|
||||
}
|
||||
]
|
||||
}]
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div style={{float: 'left'}}>
|
||||
<h1>Table Options</h1>
|
||||
<table>
|
||||
<tbody>
|
||||
{
|
||||
Object.keys(this.state.tableOptions).map(optionKey => {
|
||||
const optionValue = this.state.tableOptions[optionKey]
|
||||
return (
|
||||
<tr key={optionKey}>
|
||||
<td>{optionKey}</td>
|
||||
<td style={{paddingLeft: 10, paddingTop: 5}}>
|
||||
<input type='checkbox'
|
||||
name={optionKey}
|
||||
checked={optionValue}
|
||||
onChange={this.setTableOption}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
})
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div className='table-wrap' style={{paddingLeft: 240}}>
|
||||
<ReactTable
|
||||
className='-striped -highlight'
|
||||
data={this.state.data}
|
||||
columns={columns}
|
||||
defaultPageSize={10}
|
||||
defaultFilterMethod={(filter, row) => (String(row[filter.id]) === filter.value)}
|
||||
{...this.state.tableOptions}
|
||||
SubComponent={(row) => {
|
||||
return (
|
||||
<div style={{padding: '20px'}}>
|
||||
<em>You can put any component you want here, even another React Table!</em>
|
||||
<br />
|
||||
<br />
|
||||
<ReactTable
|
||||
data={this.state.data}
|
||||
columns={columns}
|
||||
defaultPageSize={3}
|
||||
showPagination={false}
|
||||
SubComponent={(row) => {
|
||||
return (
|
||||
<div style={{padding: '20px'}}>
|
||||
<em>It even has access to the row data: </em>
|
||||
<CodeHighlight>{() => JSON.stringify(row, null, 2)}</CodeHighlight>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<br />
|
||||
<em>Tip: Hold shift when sorting to multi-sort!</em>
|
||||
</div>
|
||||
<div>
|
||||
<h1>Custom Filters In This Example</h1>
|
||||
<p>The default filter for all columns of a table if it is not specified in the configuration is set to match
|
||||
on values that start with the filter text. Example: age.startsWith("2").</p>
|
||||
<p>This example overrides the default filter behavior by setting
|
||||
the <strong>defaultFilterMethod</strong> table option to match on values that are exactly equal to the
|
||||
filter text. Example: age == "23")</p>
|
||||
<p>Each column can also be customized with the column <strong>filterMethod</strong> option:</p>
|
||||
<p>In this example the firstName column filters on the value starting with and ending with the filter
|
||||
value.</p>
|
||||
<p>In this example the lastName column filters on the value including the filter value anywhere in its
|
||||
text.</p>
|
||||
<p>To completely override the filter that is shown, you can set the <strong>Filter</strong> column
|
||||
option. Using this option you can specify the JSX that is shown. The option is passed
|
||||
an <strong>onChange</strong> method that must be called with the value that you wan't to
|
||||
pass to the <strong>filterMethod</strong> option whenever the filter has changed.</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
setTableOption (event) {
|
||||
const target = event.target
|
||||
const value = target.type === 'checkbox' ? target.checked : target.value
|
||||
const name = target.name
|
||||
this.setState({
|
||||
tableOptions: {
|
||||
...this.state.tableOptions,
|
||||
[name]: value
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Source Code
|
||||
const source = require('!raw-loader!./Filtering')
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<Story />
|
||||
<CodeHighlight>{() => source}</CodeHighlight>
|
||||
</div>
|
||||
)
|
||||
@@ -1,91 +0,0 @@
|
||||
import React from 'react'
|
||||
import _ from 'lodash'
|
||||
import namor from 'namor'
|
||||
|
||||
import ReactTable from '../src/index'
|
||||
|
||||
class Story extends React.Component {
|
||||
render () {
|
||||
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',
|
||||
Footer: (
|
||||
<span><strong>Popular:</strong> {
|
||||
_.first(
|
||||
_.reduce(
|
||||
_.map(
|
||||
_.groupBy(
|
||||
data, d => d.firstName
|
||||
)
|
||||
),
|
||||
(a, b) => a.length > b.length ? a : b
|
||||
)
|
||||
).firstName}
|
||||
</span>
|
||||
)
|
||||
}, {
|
||||
Header: 'Last Name',
|
||||
id: 'lastName',
|
||||
accessor: d => d.lastName,
|
||||
Footer: (
|
||||
<span><strong>Longest:</strong> {
|
||||
_.reduce(
|
||||
_.map(
|
||||
_.groupBy(
|
||||
data, d => d.lastName
|
||||
),
|
||||
(d, key) => key
|
||||
),
|
||||
(a, b) => a.length > b.length ? a : b
|
||||
)}
|
||||
</span>
|
||||
)
|
||||
}]
|
||||
}, {
|
||||
Header: 'Info',
|
||||
columns: [{
|
||||
Header: 'Age',
|
||||
accessor: 'age',
|
||||
Footer: <span><strong>Average:</strong> {_.round(_.mean(_.map(data, d => d.age)))}</span>
|
||||
}]
|
||||
}]
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className='table-wrap'>
|
||||
<ReactTable
|
||||
className='-striped -highlight'
|
||||
data={data}
|
||||
columns={columns}
|
||||
defaultPageSize={10}
|
||||
/>
|
||||
</div>
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<br />
|
||||
<em>Tip: Hold shift when sorting to multi-sort!</em>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Source Code
|
||||
const CodeHighlight = require('./components/codeHighlight').default
|
||||
const source = require('!raw-loader!./Footers')
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<Story />
|
||||
<CodeHighlight>{() => source}</CodeHighlight>
|
||||
</div>
|
||||
)
|
||||
@@ -1,136 +0,0 @@
|
||||
import React from 'react'
|
||||
import _ from 'lodash'
|
||||
import namor from 'namor'
|
||||
import JSONTree from 'react-json-tree'
|
||||
|
||||
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'
|
||||
}
|
||||
|
||||
class Story extends React.Component {
|
||||
render () {
|
||||
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',
|
||||
Footer: 'Footer'
|
||||
}, {
|
||||
Header: 'Last Name',
|
||||
id: 'lastName',
|
||||
accessor: d => d.lastName,
|
||||
Footer: 'Footer'
|
||||
}]
|
||||
}, {
|
||||
Header: 'Info',
|
||||
columns: [{
|
||||
Header: 'Age',
|
||||
accessor: 'age',
|
||||
Footer: 'Footer'
|
||||
}]
|
||||
}]
|
||||
|
||||
return (
|
||||
<div>
|
||||
<strong>Functional rendering</strong> simply means that you have all of the building blocks to render your own React Table however you'd like.
|
||||
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<strong>Decorating the standard table output</strong>
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<div className='table-wrap'>
|
||||
<ReactTable
|
||||
data={data}
|
||||
columns={columns}
|
||||
>
|
||||
{(state, makeTable, instance) => {
|
||||
return (
|
||||
<div style={{
|
||||
background: '#ffcf00',
|
||||
borderRadius: '5px',
|
||||
overflow: 'hidden',
|
||||
padding: '5px'
|
||||
}}>
|
||||
<pre><code>state.allVisibleColumns === {JSON.stringify(state.allVisibleColumns, null, 4)}</code></pre>
|
||||
{makeTable()}
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
</ReactTable>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<strong>Need more control? This is the entire table state and component instance at your disposal!</strong>
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<div className='table-wrap'>
|
||||
<ReactTable
|
||||
className='-striped -highlight'
|
||||
data={data}
|
||||
columns={columns}
|
||||
defaultPageSize={10}
|
||||
>
|
||||
{(state, StandardTable, instance) => {
|
||||
return (
|
||||
<div>
|
||||
<JSONTree
|
||||
data={Object.assign({}, state, {children: 'function () {...}'})}
|
||||
theme={JSONtheme}
|
||||
invertTheme
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
</ReactTable>
|
||||
</div>
|
||||
<br />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Source Code
|
||||
const CodeHighlight = require('./components/codeHighlight').default
|
||||
const source = require('!raw-loader!./FunctionalRendering')
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<Story />
|
||||
<CodeHighlight>{() => source}</CodeHighlight>
|
||||
</div>
|
||||
)
|
||||
@@ -1,56 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
import ReactTable from '../src/index'
|
||||
|
||||
class Story extends React.Component {
|
||||
render () {
|
||||
const columns = [{
|
||||
Header: 'Name',
|
||||
columns: [{
|
||||
Header: 'First Name',
|
||||
accessor: 'firstName'
|
||||
}, {
|
||||
Header: 'Last Name',
|
||||
id: 'lastName',
|
||||
accessor: d => d.lastName
|
||||
}]
|
||||
}, {
|
||||
Header: 'Info',
|
||||
columns: [{
|
||||
Header: 'Age',
|
||||
accessor: 'age'
|
||||
}]
|
||||
}]
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className='table-wrap'>
|
||||
<ReactTable
|
||||
className='-striped -highlight'
|
||||
data={[]}
|
||||
noDataText='Oh Noes!'
|
||||
// noDataText={() => 'Oh Noes!'} // Supports functions
|
||||
// noDataText={() => <span>Oh Noes!</span>} // Supports JSX / React Components
|
||||
columns={columns}
|
||||
defaultPageSize={10}
|
||||
/>
|
||||
</div>
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<br />
|
||||
<em>Tip: Hold shift when sorting to multi-sort!</em>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Source Code
|
||||
const CodeHighlight = require('./components/codeHighlight').default
|
||||
const source = require('!raw-loader!./NoDataText')
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<Story />
|
||||
<CodeHighlight>{() => source}</CodeHighlight>
|
||||
</div>
|
||||
)
|
||||
@@ -1,96 +0,0 @@
|
||||
import React from 'react'
|
||||
import _ from 'lodash'
|
||||
import namor from 'namor'
|
||||
|
||||
import ReactTable from '../src/index'
|
||||
|
||||
class Story extends React.Component {
|
||||
render () {
|
||||
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)),
|
||||
Aggregated: row => {
|
||||
return <span>{row.value} (avg)</span>
|
||||
}
|
||||
}, {
|
||||
Header: 'Visits',
|
||||
accessor: 'visits',
|
||||
aggregate: vals => _.sum(vals)
|
||||
}]
|
||||
}]
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className='table-wrap'>
|
||||
<ReactTable
|
||||
data={data}
|
||||
columns={columns}
|
||||
className='-striped -highlight'
|
||||
defaultPageSize={10}
|
||||
pivotBy={['firstName', 'lastName']}
|
||||
SubComponent={(row) => {
|
||||
return (
|
||||
<div style={{padding: '20px'}}>
|
||||
<em>You can put any component you want here, even another React Table!</em>
|
||||
<br />
|
||||
<br />
|
||||
<ReactTable
|
||||
data={data}
|
||||
columns={columns}
|
||||
defaultPageSize={3}
|
||||
showPagination={false}
|
||||
SubComponent={(row) => {
|
||||
return (
|
||||
<div style={{padding: '20px'}}>
|
||||
<em>It even has access to the row data: </em>
|
||||
<CodeHighlight>{() => JSON.stringify(row, null, 2)}</CodeHighlight>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<br />
|
||||
<em>Tip: Hold shift when sorting to multi-sort!</em>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Source Code
|
||||
const CodeHighlight = require('./components/codeHighlight').default
|
||||
const source = require('!raw-loader!./OneHundredKRows')
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<Story />
|
||||
<CodeHighlight>{() => source}</CodeHighlight>
|
||||
</div>
|
||||
)
|
||||
@@ -1,73 +0,0 @@
|
||||
import React from 'react'
|
||||
import _ from 'lodash'
|
||||
import namor from 'namor'
|
||||
|
||||
import ReactTable from '../src/index'
|
||||
|
||||
class Story extends React.Component {
|
||||
render () {
|
||||
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)),
|
||||
Aggregated: row => {
|
||||
return <span>{row.value} (avg)</span>
|
||||
}
|
||||
}, {
|
||||
Header: 'Visits',
|
||||
accessor: 'visits',
|
||||
aggregate: vals => _.sum(vals)
|
||||
}]
|
||||
}]
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className='table-wrap'>
|
||||
<ReactTable
|
||||
data={data}
|
||||
columns={columns}
|
||||
className='-striped -highlight'
|
||||
defaultPageSize={10}
|
||||
pivotBy={['firstName', 'lastName']}
|
||||
/>
|
||||
</div>
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<br />
|
||||
<em>Tip: Hold shift when sorting to multi-sort!</em>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Source Code
|
||||
const CodeHighlight = require('./components/codeHighlight').default
|
||||
const source = require('!raw-loader!./Pivoting')
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<Story />
|
||||
<CodeHighlight>{() => source}</CodeHighlight>
|
||||
</div>
|
||||
)
|
||||
@@ -1,131 +0,0 @@
|
||||
import React from 'react'
|
||||
import _ from 'lodash'
|
||||
import namor from 'namor'
|
||||
|
||||
import ReactTable from '../src/index'
|
||||
|
||||
class Story extends React.Component {
|
||||
render () {
|
||||
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',
|
||||
PivotValue: ({value}) => <span style={{color: 'darkred'}}>{value}</span>
|
||||
}, {
|
||||
Header: 'Last Name',
|
||||
id: 'lastName',
|
||||
accessor: d => d.lastName,
|
||||
PivotValue: ({value}) => <span style={{color: 'darkblue'}}>{value}</span>,
|
||||
Footer: () => <div style={{textAlign: 'center'}}><strong>Pivot Column Footer</strong></div>
|
||||
}]
|
||||
}, {
|
||||
Header: 'Info',
|
||||
columns: [{
|
||||
Header: 'Age',
|
||||
accessor: 'age',
|
||||
aggregate: vals => {
|
||||
return _.round(_.mean(vals))
|
||||
},
|
||||
Aggregated: row => <span>{row.value} (avg)</span>
|
||||
}, {
|
||||
Header: 'Visits',
|
||||
accessor: 'visits',
|
||||
aggregate: vals => _.sum(vals),
|
||||
filterable: false
|
||||
}]
|
||||
}, {
|
||||
pivot: true,
|
||||
Header: () => <strong>Overridden Pivot Column Header Group</strong>
|
||||
}, {
|
||||
expander: true
|
||||
}]
|
||||
|
||||
const subtableColumns = [{
|
||||
Header: 'Name',
|
||||
columns: [{
|
||||
Header: 'First Name',
|
||||
accessor: 'firstName'
|
||||
}, {
|
||||
Header: 'Last Name',
|
||||
id: 'lastName'
|
||||
}]
|
||||
}, {
|
||||
Header: 'Info',
|
||||
columns: [{
|
||||
Header: 'Age',
|
||||
accessor: 'age'
|
||||
}, {
|
||||
Header: 'Visits',
|
||||
accessor: 'visits'
|
||||
}]
|
||||
}]
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className='table-wrap'>
|
||||
<ReactTable
|
||||
data={data}
|
||||
columns={columns}
|
||||
defaultPageSize={10}
|
||||
className='-striped -highlight'
|
||||
pivotBy={['firstName', 'lastName']}
|
||||
defaultSorted={[{id: 'firstName', desc: false}, {id: 'lastName', desc: true}]}
|
||||
collapseOnSortingChange={false}
|
||||
filterable
|
||||
ExpanderComponent={({isExpanded, ...rest}) => (
|
||||
isExpanded ? <span> ➘ </span> : <span> ➙ </span>
|
||||
)}
|
||||
SubComponent={(row) => {
|
||||
return (
|
||||
<div style={{padding: '20px'}}>
|
||||
<em>You can put any component you want here, even another React Table!</em>
|
||||
<br />
|
||||
<br />
|
||||
<ReactTable
|
||||
data={data}
|
||||
columns={subtableColumns}
|
||||
defaultPageSize={3}
|
||||
showPagination={false}
|
||||
SubComponent={(row) => {
|
||||
return (
|
||||
<div style={{padding: '20px'}}>
|
||||
<em>It even has access to the row data: </em>
|
||||
<CodeHighlight>{() => JSON.stringify(row, null, 2)}</CodeHighlight>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<br />
|
||||
<em>Tip: Hold shift when sorting to multi-sort!</em>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Source Code
|
||||
const CodeHighlight = require('./components/codeHighlight').default
|
||||
const source = require('!raw-loader!./PivotingOptions')
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<Story />
|
||||
<CodeHighlight>{() => source}</CodeHighlight>
|
||||
</div>
|
||||
)
|
||||
@@ -1,99 +0,0 @@
|
||||
import React from 'react'
|
||||
import _ from 'lodash'
|
||||
import namor from 'namor'
|
||||
|
||||
import ReactTable from '../src/index'
|
||||
|
||||
class Story extends React.Component {
|
||||
render () {
|
||||
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)),
|
||||
Aggregated: row => {
|
||||
return <span>{row.value} (avg)</span>
|
||||
},
|
||||
filterMethod: (filter, row) => (filter.value === `${row[filter.id]} (avg)`)
|
||||
}, {
|
||||
Header: 'Visits',
|
||||
accessor: 'visits',
|
||||
aggregate: vals => _.sum(vals),
|
||||
filterable: false
|
||||
}]
|
||||
}]
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className='table-wrap'>
|
||||
<ReactTable
|
||||
data={data}
|
||||
columns={columns}
|
||||
defaultPageSize={10}
|
||||
className='-striped -highlight'
|
||||
pivotBy={['firstName', 'lastName']}
|
||||
filterable
|
||||
SubComponent={(row) => {
|
||||
return (
|
||||
<div style={{padding: '20px'}}>
|
||||
<em>You can put any component you want here, even another React Table!</em>
|
||||
<br />
|
||||
<br />
|
||||
<ReactTable
|
||||
data={data}
|
||||
columns={columns}
|
||||
defaultPageSize={3}
|
||||
showPagination={false}
|
||||
SubComponent={(row) => {
|
||||
return (
|
||||
<div style={{padding: '20px'}}>
|
||||
<em>It even has access to the row data: </em>
|
||||
<CodeHighlight>{() => JSON.stringify(row, null, 2)}</CodeHighlight>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<br />
|
||||
<em>Tip: Hold shift when sorting to multi-sort!</em>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Source Code
|
||||
const CodeHighlight = require('./components/codeHighlight').default
|
||||
const source = require('!raw-loader!./PivotingSubComponents')
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<Story />
|
||||
<CodeHighlight>{() => source}</CodeHighlight>
|
||||
</div>
|
||||
)
|
||||
@@ -1,120 +0,0 @@
|
||||
import React from 'react'
|
||||
import _ from 'lodash'
|
||||
import namor from 'namor'
|
||||
|
||||
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, sorted, filtered) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
// On the server, you'll likely use SQL or noSQL or some other query language to do this.
|
||||
// For this mock, we'll just use lodash
|
||||
let filteredData = rawData
|
||||
if (filtered.length) {
|
||||
filteredData = filtered.reduce(
|
||||
(filteredSoFar, nextFilter) => {
|
||||
return filteredSoFar.filter(
|
||||
(row) => {
|
||||
return (row[nextFilter.id] + '').includes(nextFilter.value)
|
||||
})
|
||||
}
|
||||
, filteredData)
|
||||
}
|
||||
const sortedData = _.orderBy(filteredData, sorted.map(sort => {
|
||||
return row => {
|
||||
if (row[sort.id] === null || row[sort.id] === undefined) {
|
||||
return -Infinity
|
||||
}
|
||||
return typeof row[sort.id] === 'string' ? row[sort.id].toLowerCase() : row[sort.id]
|
||||
}
|
||||
}), sorted.map(d => d.desc ? 'desc' : 'asc'))
|
||||
|
||||
// Be sure to send back the rows to be displayed and any other pertinent information, like how many pages there are total.
|
||||
const res = {
|
||||
rows: sortedData.slice(pageSize * page, (pageSize * page) + pageSize),
|
||||
pages: Math.ceil(filteredData.length / pageSize)
|
||||
}
|
||||
|
||||
// Here we'll simulate a server response with 500ms of delay.
|
||||
setTimeout(() => resolve(res), 500)
|
||||
})
|
||||
}
|
||||
|
||||
class Story extends React.Component {
|
||||
constructor () {
|
||||
super()
|
||||
this.state = {
|
||||
data: [],
|
||||
pages: null,
|
||||
loading: true
|
||||
}
|
||||
this.fetchData = this.fetchData.bind(this)
|
||||
}
|
||||
fetchData (state, instance) {
|
||||
// Whenever the table model changes, or the user sorts or changes pages, this method gets called and passed the current table model.
|
||||
// You can set the `loading` prop of the table to true to use the built-in one or show you're own loading bar if you want.
|
||||
this.setState({loading: true})
|
||||
// Request the data however you want. Here, we'll use our mocked service we created earlier
|
||||
requestData(state.pageSize, state.page, state.sorted, state.filtered)
|
||||
.then((res) => {
|
||||
// Now just get the rows of data to your React Table (and update anything else like total pages or loading)
|
||||
this.setState({
|
||||
data: res.rows,
|
||||
pages: res.pages,
|
||||
loading: false
|
||||
})
|
||||
})
|
||||
}
|
||||
render () {
|
||||
return (
|
||||
<div>
|
||||
<div className='table-wrap'>
|
||||
<ReactTable
|
||||
className='-striped -highlight'
|
||||
columns={[{
|
||||
Header: 'First Name',
|
||||
accessor: 'firstName'
|
||||
}, {
|
||||
Header: 'Last Name',
|
||||
id: 'lastName',
|
||||
accessor: d => d.lastName
|
||||
}, {
|
||||
Header: 'Age',
|
||||
accessor: 'age'
|
||||
}]}
|
||||
manual // Forces table not to paginate or sort automatically, so we can handle it server-side
|
||||
defaultPageSize={10}
|
||||
filterable
|
||||
data={this.state.data} // Set the rows to be displayed
|
||||
pages={this.state.pages} // Display the total number of pages
|
||||
loading={this.state.loading} // Display the loading overlay when we need it
|
||||
onFetchData={this.fetchData} // Request new data when things change
|
||||
/>
|
||||
</div>
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<br />
|
||||
<em>Tip: Hold shift when sorting to multi-sort!</em>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Source Code
|
||||
const CodeHighlight = require('./components/codeHighlight').default
|
||||
const source = require('!raw-loader!./ServerSide')
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<Story />
|
||||
<CodeHighlight>{() => source}</CodeHighlight>
|
||||
</div>
|
||||
)
|
||||
@@ -1,69 +0,0 @@
|
||||
import React from 'react'
|
||||
import _ from 'lodash'
|
||||
import namor from 'namor'
|
||||
|
||||
import ReactTable from '../src/index'
|
||||
|
||||
class Story extends React.Component {
|
||||
render () {
|
||||
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),
|
||||
children: _.map(_.range(10), 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>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const CodeHighlight = require('./components/codeHighlight').default
|
||||
const source = require('!raw-loader!./Simple')
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<Story />
|
||||
<CodeHighlight>{() => source}</CodeHighlight>
|
||||
</div>
|
||||
)
|
||||
@@ -1,145 +0,0 @@
|
||||
import React from 'react'
|
||||
import _ from 'lodash'
|
||||
import namor from 'namor'
|
||||
|
||||
import ReactTable from '../src/index'
|
||||
|
||||
class Story extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
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)
|
||||
}
|
||||
})
|
||||
|
||||
this.state = {
|
||||
tableOptions: {
|
||||
loading: false,
|
||||
showPagination: true,
|
||||
showPageSizeOptions: true,
|
||||
showPageJump: true,
|
||||
collapseOnSortingChange: true,
|
||||
collapseOnPageChange: true,
|
||||
collapseOnDataChange: true,
|
||||
freezeWhenExpanded: false,
|
||||
filterable: false,
|
||||
sortable: true,
|
||||
resizable: true
|
||||
},
|
||||
data: data
|
||||
}
|
||||
|
||||
this.setTableOption = this.setTableOption.bind(this)
|
||||
}
|
||||
render () {
|
||||
const columns = [{
|
||||
Header: 'Name',
|
||||
columns: [{
|
||||
Header: 'First Name',
|
||||
accessor: 'firstName'
|
||||
}, {
|
||||
Header: 'Last Name',
|
||||
id: 'lastName',
|
||||
accessor: d => d.lastName
|
||||
}]
|
||||
}, {
|
||||
Header: 'Info',
|
||||
columns: [{
|
||||
Header: 'Age',
|
||||
accessor: 'age'
|
||||
}]
|
||||
}]
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div style={{float: 'left'}}>
|
||||
<h1>Table Options</h1>
|
||||
<table>
|
||||
<tbody>
|
||||
{
|
||||
Object.keys(this.state.tableOptions).map(optionKey => {
|
||||
const optionValue = this.state.tableOptions[optionKey]
|
||||
return (
|
||||
<tr key={optionKey}>
|
||||
<td>{optionKey}</td>
|
||||
<td style={{paddingLeft: 10, paddingTop: 5}}>
|
||||
<input type='checkbox'
|
||||
name={optionKey}
|
||||
checked={optionValue}
|
||||
onChange={this.setTableOption}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
})
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div className='table-wrap' style={{paddingLeft: 240}}>
|
||||
<ReactTable
|
||||
className='-striped -highlight'
|
||||
data={this.state.data}
|
||||
columns={columns}
|
||||
defaultPageSize={10}
|
||||
{...this.state.tableOptions}
|
||||
SubComponent={(row) => {
|
||||
return (
|
||||
<div style={{padding: '20px'}}>
|
||||
<em>You can put any component you want here, even another React Table!</em>
|
||||
<br />
|
||||
<br />
|
||||
<ReactTable
|
||||
data={this.state.data}
|
||||
columns={columns}
|
||||
defaultPageSize={3}
|
||||
showPagination={false}
|
||||
SubComponent={(row) => {
|
||||
return (
|
||||
<div style={{padding: '20px'}}>
|
||||
<em>It even has access to the row data: </em>
|
||||
<CodeHighlight>{() => JSON.stringify(row, null, 2)}</CodeHighlight>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<br />
|
||||
<em>Tip: Hold shift when sorting to multi-sort!</em>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
setTableOption (event) {
|
||||
const target = event.target
|
||||
const value = target.type === 'checkbox' ? target.checked : target.value
|
||||
const name = target.name
|
||||
this.setState({
|
||||
tableOptions: {
|
||||
...this.state.tableOptions,
|
||||
[name]: value
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Source Code
|
||||
const CodeHighlight = require('./components/codeHighlight').default
|
||||
const source = require('!raw-loader!./SubComponents')
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<Story />
|
||||
<CodeHighlight>{() => source}</CodeHighlight>
|
||||
</div>
|
||||
)
|
||||
@@ -1,77 +0,0 @@
|
||||
import React from 'react'
|
||||
import _ from 'lodash'
|
||||
import namor from 'namor'
|
||||
|
||||
import ReactTable from '../src/index'
|
||||
|
||||
class Story extends React.Component {
|
||||
render () {
|
||||
const data = _.map(_.range(5553), d => {
|
||||
const children = _.map(_.range(10), d => {
|
||||
const grandChildren = _.map(_.range(10), d => {
|
||||
return {
|
||||
age: Math.floor(Math.random() * 30)
|
||||
}
|
||||
})
|
||||
return {
|
||||
firstName: namor.generate({ words: 1, numLen: 0 }),
|
||||
age: Math.floor(Math.random() * 30),
|
||||
children: grandChildren
|
||||
}
|
||||
})
|
||||
return {
|
||||
lastName: namor.generate({ words: 1, numLen: 0 }),
|
||||
firstName: children.map(d => d.firstName),
|
||||
age: Math.floor(Math.random() * 30),
|
||||
children
|
||||
}
|
||||
})
|
||||
|
||||
const columns = [{
|
||||
Header: 'Name',
|
||||
columns: [{
|
||||
Header: 'First Name',
|
||||
accessor: 'firstName',
|
||||
expander: true
|
||||
}, {
|
||||
Header: 'Last Name',
|
||||
accessor: 'lastName'
|
||||
}]
|
||||
}, {
|
||||
Header: 'Info',
|
||||
columns: [{
|
||||
Header: 'Age',
|
||||
accessor: 'age'
|
||||
}]
|
||||
}]
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className='table-wrap'>
|
||||
<ReactTable
|
||||
className='-striped -highlight'
|
||||
data={data}
|
||||
columns={columns}
|
||||
defaultPageSize={10}
|
||||
subRowsKey='children'
|
||||
/>
|
||||
</div>
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<br />
|
||||
<em>Tip: Hold shift when sorting to multi-sort!</em>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Source Code
|
||||
const CodeHighlight = require('./components/codeHighlight').default
|
||||
const source = require('!raw-loader!./SubRows')
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<Story />
|
||||
<CodeHighlight>{() => source}</CodeHighlight>
|
||||
</div>
|
||||
)
|
||||
@@ -1,21 +0,0 @@
|
||||
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()
|
||||
}
|
||||
})
|
||||
@@ -1,20 +0,0 @@
|
||||
const webpack = require('webpack')
|
||||
module.exports = {
|
||||
entry: './lib/index.js',
|
||||
output: {
|
||||
filename: './react-table.js',
|
||||
libraryTarget: 'umd',
|
||||
library: 'ReactTable'
|
||||
},
|
||||
externals: {
|
||||
react: {
|
||||
root: 'React',
|
||||
commonjs2: 'react',
|
||||
commonjs: 'react',
|
||||
amd: 'react'
|
||||
}
|
||||
},
|
||||
plugins: [
|
||||
new webpack.optimize.UglifyJsPlugin()
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
* https://github.com/tannerlinsley/react-table
|
||||