Compare commits

..
3 Commits
Author SHA1 Message Date
Tanner Linsley b629d3ebbb 5.3.0 2017-02-16 10:41:46 -07:00
Tanner Linsley 1ebea1cac8 Added more customization for functional rendering 2017-02-16 10:41:35 -07:00
Tanner Linsley b16eee1bba Added support for Column Footers 2017-02-16 09:29:12 -07:00
28 changed files with 461 additions and 873 deletions
Vendored
BIN
View File
Binary file not shown.
-2
View File
@@ -3,5 +3,3 @@ lib/
react-table.js
react-table.css
*.log
.idea
.DS_Store
-2
View File
@@ -24,7 +24,6 @@ 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'
//
configure(() => {
storiesOf('1. Docs')
@@ -54,5 +53,4 @@ configure(() => {
.add('Custom Expander Position', CustomExpanderPosition)
.add('Custom "No Data" Text', NoDataText)
.add('Footers', Footers)
.add('Custom Filtering', Filtering)
}, module)
-11
View File
@@ -4,14 +4,3 @@ body {
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;
}
+62 -68
View File
@@ -102,7 +102,7 @@ const data = [{
const columns = [{
header: 'Name',
accessor: 'name' // String-based value accessors!
accessor: 'name' // String-based value accessors !
}, {
header: 'Age',
accessor: 'age',
@@ -138,14 +138,10 @@ These are all of the available props (and their default values) for the main `<R
defaultPageSize: 20,
showPageJump: true,
expanderColumnWidth: 35,
collapseOnSortingChange: true,
collapseOnSortingChange: false,
collapseOnPageChange: true,
collapseOnDataChange: true,
freezeWhenExpanded: false,
defaultSorting: [],
showFilters: false,
defaultFiltering: [],
defaultFilterMethod: (filter, row) => (row[filter.id] == filter.value),
// Controlled State Overrides (see Fully Controlled Component section)
page: undefined,
@@ -157,7 +153,6 @@ These are all of the available props (and their default values) for the main `<R
onPageChange: undefined,
onPageSizeChange: undefined,
onSortingChange: undefined,
onFilteringChange: undefined,
// Pivoting
pivotBy: undefined,
@@ -188,9 +183,6 @@ These are all of the available props (and their default values) for the main `<R
getTheadProps: () => ({}),
getTheadTrProps: () => ({}),
getTheadThProps: () => ({}),
getTheadFilterProps: () => ({}),
getTheadFilterTrProps: () => ({}),
getTheadFilterThProps: () => ({}),
getTbodyProps: () => ({}),
getTrGroupProps: () => ({}),
getTrProps: () => ({}),
@@ -222,8 +214,7 @@ These are all of the available props (and their default values) for the main `<R
footer: undefined,
footerClassName: '',
footerStyle: {},
getFooterProps: () => ({}),
filterMethod: undefined
getFooterProps: () => ({})
},
// Text
@@ -265,7 +256,7 @@ Or just define them as props
```javascript
[{
// General
accessor: 'propertyName' // or Accessor eg. (row) => row.propertyName (see "Accessors" section for more details)
accessor: 'propertyName' or Accessor eg. (row) => row.propertyName,
id: 'myProperty', // Conditional - A unique ID is required if the accessor is not a string or if you would like to override the column name used in server-side calls
sortable: true,
show: true, // can be used to hide a column
@@ -300,39 +291,11 @@ Or just define them as props
footer: 'Header Name' or JSX eg. ({data, column}) => <div>Header Name</div>,
footerClassName: '', // Set the classname of the `td` element of the column's footer
footerStyle: {}, // Set the style of the `td` element of the column's footer
getFooterProps: (state, rowInfo, column, instance) => ({}) // A function that returns props to decorate the `td` element of the column's footer
getFooterProps: (state, rowInfo, column, instance) => ({}) // a function that returns props to decorate the `td` element of the column's footer
// Filtering
filterMethod: (filter, row, column) => {return true} // A function returning a boolean that specifies the filtering logic for the column
// filter == an object specifying which filter is being applied. Format: {id: [the filter column's id], value: [the value the user typed in the filter field]}
// row == the row of data supplied to the table
// column == the column that the filter is on
}]
```
## Accessors
Accessors are functions that return the value to populate the row's value for the column.
This lets the render function not have to worry about accessing the correct data, the value is automatically populated in it's props.
If a `string` or `array` is passed the default accessor is used.
The default accessor will parse the input into an array and recursively flatten it.
Any values that contain a dot (`.`) will be split.
Any values that contain bracket (`[]`) will be split.
This array is then used as the path to the value to return.
("$" is the placeholder value that would be returned by the default accessor)
| value | path | data |
|--------------|-----------------|------------------------|
| "a" | ["a"] | {"a": $} |
| "a.b" | ["a", "b"] | {"a": {"b": $}} |
| "a[0]" | ["a", "0"] | {"a": [$]} |
| ["a.b", "c"] | ["a", "b", "c"] | {"a": {"b": {"c": $}}} |
*NOTE*
If your data has a field/key with a dot (`.`) you will need to supply a custom accessor.
## Column Header Groups
To group columns with another header column, just nest your columns in a header column. Header columns utilize the same header properties as regular columns.
```javascript
@@ -433,11 +396,11 @@ Every single built-in component's props can be dynamically extended using any on
/>
```
These callbacks are executed with each render of the element with four parameters:
1. Table State
2. RowInfo (undefined if not applicable)
3. Column (undefined if not applicable)
4. React Table Instance
These callbacks are executed with each render of the element with three parameters:
1. Table State
1. RowInfo (undefined if not applicable)
1. Column (undefined if not applicable)
1. React Table Instance
This makes it extremely easy to add, say... a row click callback!
```javascript
@@ -545,7 +508,7 @@ By adding a `SubComponent` props, you can easily add an expansion level to all r
## Server-side Data
If you want to handle pagination, sorting, and filtering on the server, `react-table` makes it easy on you.
If you want to handle pagination, and sorting on the server, `react-table` makes it easy on you.
1. Feed React Table `data` from somewhere dynamic. eg. `state`, a redux store, etc...
1. Add `manual` as a prop. This informs React Table that you'll be handling sorting and pagination server-side
@@ -568,8 +531,7 @@ If you want to handle pagination, sorting, and filtering on the server, `react-t
Axios.post('mysite.com/data', {
page: state.page,
pageSize: state.pageSize,
sorting: state.sorting,
filtering: state.filtering
sorting: state.sorting
})
.then((res) => {
// Update react-table
@@ -615,7 +577,6 @@ Here are the props and their corresponding callbacks that control the state of t
onPageSizeChange={(pageSize, pageIndex) => {...}} // Called when the pageSize is changed by the user. The resolve page is also sent to maintain approximate position in the data
onSortingChange={(column, shiftKey) => {...}} // Called when a sortable column header is clicked with the column itself and if the shiftkey was held. If the column is a pivoted column, `column` will be an array of columns
onExpandRow={(index, event) => {...}} // Called when an expander is clicked. Use this to manage `expandedRows`
onFilteringChange={(column, event) => {...}} // Called when a user enters a value into a filter input field. The event is the onChange event of the input field.
/>
```
@@ -624,21 +585,56 @@ Possibly one of the coolest features of React-Table is its ability to expose int
The function you pass will be called with the following items:
- Fully-resolved state of the table
- A function that returns the standard table component
- The standard table component (including individual partials as properties of this component)
- The instance of the component
You can then return any JSX or react you want! This turns out to be perfect for:
- Reordering the internal components of the table
- Accessing the internal state of the table without a `ref`
- Decorating the table or extending it with your own UI
- Building your own custom display logic
Custom pagination order:
```javascript
<ReactTable
data={data}
columns={columns}
>
{(state, {
Root,
Table,
HeaderGroups,
Headers,
Rows,
Footers,
Pagination,
NoData,
Loading
}, instance) => {
return (
<Root>
<Pagination />
<Table>
<HeaderGroups />
<Headers />
<Rows />
<Footers />
</Table>
<NoData />
<Loading />
</Root>
)
}}
</ReactTable>
```
Accessing internal state and wrapping with more UI:
```javascript
<ReactTable
data={data}
columns={columns}
>
{(state, makeTable, instance) => {
{(state, Table, instance) => {
return (
<div style={{
background: '#ffcf00',
@@ -647,7 +643,7 @@ Accessing internal state and wrapping with more UI:
padding: '5px'
}}>
<pre><code>state.allVisibleColumns === {JSON.stringify(state.allVisibleColumns, null, 4)}</code></pre>
{makeTable()}
<Table />
</div>
)
}}
@@ -665,20 +661,18 @@ Though we confidently stand by the markup and architecture behind it, `react-tab
// Change the global default
import { ReactTableDefaults } from 'react-table'
Object.assign(ReactTableDefaults, {
TableComponent: component,
TheadComponent: component,
TbodyComponent: component,
TrGroupComponent: component,
TrComponent: component,
ThComponent: component
TdComponent: component,
TfootComponent: component,
ExpanderComponent: component,
PaginationComponent: component,
PreviousComponent: undefined,
NextComponent: undefined,
LoadingComponent: component,
NoDataComponent: component,
TableComponent: Component,
TheadComponent: Component,
TbodyComponent: Component,
TrGroupComponent: Component,
TrComponent: Component,
ThComponent: Component,
TdComponent: Component,
PaginationComponent: Component,
PreviousComponent: Component,
NextComponent: Component,
LoadingComponent: Component,
ExpanderComponent: Component
})
// Or change per instance
+1 -1
View File
@@ -16,7 +16,7 @@
<body>
<div id="root"></div>
<div id="error-display"></div>
<script src="static/preview.ea1bdf726a82703c8f6f.bundle.js"></script>
<script src="static/preview.fe48f7ea9cf295bed07c.bundle.js"></script>
</body>
</html>
+1 -1
View File
@@ -38,7 +38,7 @@
</head>
<body style="margin: 0;">
<div id="root"></div>
<script src="static/manager.064c8fe6b78907f0a142.bundle.js"></script>
<script src="static/manager.3f690da6fe3fd9729ee0.bundle.js"></script>
</body>
</html>
@@ -1 +0,0 @@
{"version":3,"file":"static/manager.064c8fe6b78907f0a142.bundle.js","sources":["webpack:///static/manager.064c8fe6b78907f0a142.bundle.js"],"mappings":"AAAA;AAkuDA;AA84DA;AAy8DA;AA00DA;AAsyEA;AA89CA;AA+rDA;AAsiDA;AAg6DA;AA2nDA;AA++CA;AAkvDA;AAsnEA;AA2oDA;AAivCA;AA+nDA;AAkpDA;AA6lEA;AAs4DA;AAquDA;AA+pDA;AAqxDA;AAsrDA;AA4yDA;AA88GA;AAj6CA;AAopGA;AAsuFA;AA+zEA;AAtMA;AAizEA","sourceRoot":""}
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
{"version":3,"file":"static/manager.3f690da6fe3fd9729ee0.bundle.js","sources":["webpack:///static/manager.3f690da6fe3fd9729ee0.bundle.js"],"mappings":"AAAA;AAkuDA;AA84DA;AA28DA;AA00DA;AAsyEA;AA89CA;AA+rDA;AAsiDA;AAg6DA;AA2nDA;AA++CA;AAkvDA;AAsnEA;AA2oDA;AAivCA;AA+nDA;AAkpDA;AA6lEA;AAs4DA;AAquDA;AA+pDA;AAoxDA;AAsrDA;AA4yDA;AA88GA;AAj6CA;AAopGA;AAsuFA;AA+zEA;AAtMA;AAizEA","sourceRoot":""}
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
{"version":3,"file":"static/preview.ea1bdf726a82703c8f6f.bundle.js","sources":["webpack:///static/preview.ea1bdf726a82703c8f6f.bundle.js"],"mappings":"AAAA;AAkuDA;AAo/DA;AAgrFA;AAmmFA;AA07OA;AAuwFA;AAwtDA;AA+jEA;AA4uDA;AAi8DA;AA+lDA;AA4yDA;AA28CA;AAw7DA;AAooDA;AA67CA;AAiqDA;AAynEA;AAwxDA;AA+rCA;AA+mDA;AA2lDA;AAkqEA;AAs2DA;AA2zDA;AAo4CA;AAksFA;AAmjGA;AAksDA;AA02CA;AAgoCA;AAm/CA;AA+4CA;AAsCA;AA+jFA","sourceRoot":""}
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
{"version":3,"file":"static/preview.fe48f7ea9cf295bed07c.bundle.js","sources":["webpack:///static/preview.fe48f7ea9cf295bed07c.bundle.js"],"mappings":"AAAA;AAkuDA;AA48CA;AA0sGA;AAigFA;AAyiNA;AA0rFA;AAk4FA;AAsiEA;AAwuDA;AAu9DA;AA6gDA;AAixDA;AA69CA;AAk+DA;AAqoDA;AAs9CA;AAgoDA;AAwsEA;AAuoDA;AAmvCA;AAioDA;AAkpDA;AA6lEA;AAs4DA;AAuyDA;AAokDA;AA0mFA;AAyiGA;AA2gDA;AAm2CA;AAy/BA;AA4uDA;AAy4BA;AA0XA;AA6zEA","sourceRoot":""}
+3 -4
View File
@@ -1,6 +1,6 @@
{
"name": "react-table",
"version": "5.3.4",
"version": "5.3.0",
"description": "A fast, lightweight, opinionated table and datagrid built on React",
"license": "MIT",
"homepage": "https://github.com/tannerlinsley/react-table#readme",
@@ -24,13 +24,13 @@
],
"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:css": "rm -rf react-table.css && stylus src/index.styl --compress -o react-table.css && yarn run css:autoprefix",
"css:autoprefix": "postcss --use autoprefixer react-table.css -r",
"watch": "npm-run-all --parallel watch:*",
"watch: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 && browserify lib/index.js -s reactTable -x react -t babelify -g uglifyify -o react-table.js",
"umd": "rm -rf react-table.js && browserify lib/index.js -s reactTable -x react -t babelify -g uglifyify -o react-table.js",
"prepublish": "npm-run-all build:* && npm run umd",
"storybook": "start-storybook -p 8000 -c .storybook",
"docs": "build-storybook -o docs && cp .storybook/CNAME docs/CNAME"
@@ -61,7 +61,6 @@
"react": "^15.4.2",
"react-dom": "^15.4.2",
"react-json-tree": "^0.10.1",
"rimraf": "^2.6.1",
"standard": "^8.0.0",
"storybook": "^0.0.0",
"stylus": "^0.54.5",
+2 -11
View File
@@ -16,14 +16,10 @@ export default {
defaultPageSize: 20,
showPageJump: true,
expanderColumnWidth: 35,
collapseOnSortingChange: true,
collapseOnSortingChange: false,
collapseOnPageChange: true,
collapseOnDataChange: true,
freezeWhenExpanded: false,
defaultSorting: [],
showFilters: false,
defaultFiltering: [],
defaultFilterMethod: (filter, row, column) => (row[filter.id] === filter.value),
// Controlled State Overrides
// page: undefined,
@@ -35,7 +31,6 @@ export default {
onPageChange: undefined,
onPageSizeChange: undefined,
onSortingChange: undefined,
onFilteringChange: undefined,
// Pivoting
pivotBy: undefined,
@@ -66,9 +61,6 @@ export default {
getTheadProps: emptyObj,
getTheadTrProps: emptyObj,
getTheadThProps: emptyObj,
getTheadFilterProps: emptyObj,
getTheadFilterTrProps: emptyObj,
getTheadFilterThProps: emptyObj,
getTbodyProps: emptyObj,
getTrGroupProps: emptyObj,
getTrProps: emptyObj,
@@ -99,8 +91,7 @@ export default {
footer: undefined,
footerClassName: '',
footerStyle: {},
getFooterProps: emptyObj,
filterMethod: undefined
getFooterProps: emptyObj
},
// Text
+128 -219
View File
@@ -4,9 +4,6 @@ import classnames from 'classnames'
import _ from './utils'
import lifecycle from './lifecycle'
import methods from './methods'
import defaults from './defaultProps'
export const ReactTableDefaults = defaults
export default React.createClass({
...lifecycle,
@@ -26,9 +23,6 @@ export default React.createClass({
getTheadProps,
getTheadTrProps,
getTheadThProps,
getTheadFilterProps,
getTheadFilterTrProps,
getTheadFilterThProps,
getTbodyProps,
getTrGroupProps,
getTrProps,
@@ -44,13 +38,11 @@ export default React.createClass({
manual,
loadingText,
noDataText,
showFilters,
// State
loading,
pageSize,
page,
sorting,
filtering,
pages,
// Pivoting State
pivotValKey,
@@ -87,7 +79,7 @@ export default React.createClass({
const minRows = this.getMinRows()
const padRows = pages > 1 ? _.range(pageSize - pageRows.length)
: minRows ? _.range(Math.max(minRows - pageRows.length, 0))
: []
: []
const hasColumnFooter = allVisibleColumns.some(d => d.footer)
@@ -291,7 +283,7 @@ export default React.createClass({
'rt-pivot-header',
column.sortable && '-cursor-pointer',
classes,
pivotSort ? (pivotSort.desc ? '-sort-desc' : '-sort-asc') : ''
pivotSort ? (pivotSort.desc ? '-sort-asc' : '-sort-desc') : ''
)}
style={{
...styles,
@@ -342,7 +334,7 @@ export default React.createClass({
key={i}
className={classnames(
classes,
sort ? (sort.desc ? '-sort-desc' : '-sort-asc') : '',
sort ? (sort.desc ? '-sort-asc' : '-sort-desc') : '',
column.sortable && '-cursor-pointer',
!show && '-hidden',
)}
@@ -365,142 +357,6 @@ export default React.createClass({
)
}
const makeFilters = () => {
const theadFilterProps = _.splitProps(getTheadFilterProps(finalState, undefined, undefined, this))
const theadFilterTrProps = _.splitProps(getTheadFilterTrProps(finalState, undefined, undefined, this))
return (
<TheadComponent
className={classnames('-filters', theadFilterProps.className)}
style={{
...theadFilterProps.style,
minWidth: `${rowMinWidth}px`
}}
{...theadFilterProps.rest}
>
<TrComponent
className={theadFilterTrProps.className}
style={theadFilterTrProps.style}
{...theadFilterTrProps.rest}
>
{allVisibleColumns.map(makeFilter)}
</TrComponent>
</TheadComponent>
)
}
const makeFilter = (column, i) => {
const width = _.getFirstDefined(column.width, column.minWidth)
const maxWidth = _.getFirstDefined(column.width, column.maxWidth)
const theadFilterThProps = _.splitProps(getTheadFilterThProps(finalState, undefined, column, this))
const columnHeaderProps = _.splitProps(column.getHeaderProps(finalState, undefined, column, this))
const classes = [
column.headerClassName,
theadFilterThProps.className,
columnHeaderProps.className
]
const styles = {
...column.headerStyle,
...theadFilterThProps.style,
...columnHeaderProps.style
}
const rest = {
...theadFilterThProps.rest,
...columnHeaderProps.rest
}
if (column.expander) {
if (column.pivotColumns) {
const pivotCols = []
for (let i = 0; i < column.pivotColumns.length; i++) {
const col = column.pivotColumns[i]
const filter = filtering.find(filter => filter.id === col.id)
pivotCols.push(
<span key={col.id}
style={{display: 'flex', alignContent: 'flex-end', flex: 1}}>
<input type='text'
style={{
flex: 1,
width: 20,
backgroundColor: i > 0 ? '#f3f3f3' : '#fff'
}}
value={filter ? filter.value : ''}
disabled={i > 0}
onChange={(event) => this.filterColumn(col, event)}
/>
</span>
)
if (i < column.pivotColumns.length - 1) {
pivotCols.push(<ExpanderComponent key={col.id + '-' + i} />)
}
}
return (
<ThComponent
key={i}
className={classnames(
'rt-pivot-header',
column.sortable && '-cursor-pointer',
classes
)}
style={{
...styles,
flex: `${width} 0 auto`,
width: `${width}px`,
maxWidth: `${maxWidth}px`,
display: 'flex'
}}
{...rest}
>
{pivotCols}
</ThComponent>
)
}
return (
<ThComponent
key={i}
className={classnames(
'rt-expander-header',
classes
)}
style={{
...styles,
flex: `0 0 auto`,
width: `${expanderColumnWidth}px`
}}
{...rest}
/>
)
}
const filter = filtering.find(filter => filter.id === column.id)
return (
<ThComponent
key={i}
className={classnames(
classes
)}
style={{
...styles,
flex: `${width} 0 auto`,
width: `${width}px`,
maxWidth: `${maxWidth}px`
}}
{...rest}
>
<input type='text'
style={{
width: `100%`
}}
value={filter ? filter.value : ''}
onChange={(event) => this.filterColumn(column, event)}
/>
</ThComponent>
)
}
const makePageRow = (row, i, path = []) => {
const rowInfo = {
row: row.__original,
@@ -593,15 +449,15 @@ export default React.createClass({
{...rowInfo}
value={rowInfo.rowValues[pivotValKey]}
/>
) : <span>{row[pivotValKey]} ({rowInfo.subRows.length})</span>}
) : <span>{row[pivotValKey]} ({rowInfo.subRows.length})</span>}
</span>
) : SubComponent ? (
<span>
<ExpanderComponent
isExpanded={isExpanded}
/>
</span>
) : null}
) : SubComponent ? (
<span>
<ExpanderComponent
isExpanded={isExpanded}
/>
</span>
) : null}
</TdComponent>
)
}
@@ -667,6 +523,7 @@ export default React.createClass({
const makePadRow = (row, i) => {
const trGroupProps = getTrGroupProps(finalState, undefined, undefined, this)
const trProps = _.splitProps(getTrProps(finalState, undefined, undefined, this))
const tdProps = _.splitProps(getTdProps(finalState, undefined, undefined, this))
return (
<TrGroupComponent
key={i}
@@ -679,6 +536,20 @@ export default React.createClass({
)}
style={trProps.style || {}}
>
{SubComponent && (
<ThComponent
className={classnames(
'rt-expander-header',
tdProps.className
)}
style={{
...tdProps.style,
flex: `0 0 auto`,
width: `${expanderColumnWidth}px`
}}
{...tdProps.rest}
/>
)}
{allVisibleColumns.map((column, i2) => {
const show = typeof column.show === 'function' ? column.show() : column.show
const width = _.getFirstDefined(column.width, column.minWidth)
@@ -822,10 +693,7 @@ export default React.createClass({
{...tFootTdProps.rest}
{...columnFooterProps.rest}
>
{_.normalizeComponent(column.footer, {
data: sortedData,
column: column
})}
{_.normalizeComponent(column.footer)}
</TdComponent>
)
})}
@@ -841,69 +709,110 @@ export default React.createClass({
const loadingProps = getLoadingProps(finalState, undefined, undefined, this)
const noDataProps = getNoDataProps(finalState, undefined, undefined, this)
const makeTable = () => (
<div
className={classnames(
'ReactTable',
className,
rootProps.className
)}
style={{
...style,
...rootProps.style
}}
{...rootProps.rest}
>
<TableComponent
className={classnames(tableProps.className)}
style={tableProps.style}
{...tableProps.rest}
const Root = ({children}) => {
return (
<div
className={classnames(
'ReactTable',
className,
rootProps.className
)}
style={{
...style,
...rootProps.style
}}
{...rootProps.rest}
>
{hasHeaderGroups ? makeHeaderGroups() : null}
{makeHeaders()}
{showFilters ? makeFilters() : null}
<TbodyComponent
className={classnames(tBodyProps.className)}
style={{
...tBodyProps.style,
minWidth: `${rowMinWidth}px`
}}
{...tBodyProps.rest}
>
{pageRows.map((d, i) => makePageRow(d, i))}
{padRows.map(makePadRow)}
</TbodyComponent>
{hasColumnFooter ? makeColumnFooters() : null}
</TableComponent>
{showPagination ? (
<PaginationComponent
{...resolvedState}
pages={pages}
canPrevious={canPrevious}
canNext={canNext}
onPageChange={this.onPageChange}
onPageSizeChange={this.onPageSizeChange}
className={paginationProps.className}
style={paginationProps.style}
{...paginationProps.rest}
/>
) : null}
{!pageRows.length && (
<NoDataComponent
{...noDataProps}
>
{_.normalizeComponent(noDataText)}
</NoDataComponent>
)}
<LoadingComponent
loading={loading}
loadingText={loadingText}
{...loadingProps}
/>
</div>
{children}
</div>
)
}
const Table = ({children}) => (
<TableComponent
className={classnames(tableProps.className)}
style={tableProps.style}
{...tableProps.rest}
>
{children}
</TableComponent>
)
const HeaderGroups = () => hasHeaderGroups ? makeHeaderGroups() : null
const Headers = () => makeHeaders()
const Rows = ({children}) => (
<TbodyComponent
className={classnames(tBodyProps.className)}
style={{
...tBodyProps.style,
minWidth: `${rowMinWidth}px`
}}
{...tBodyProps.rest}
>
{pageRows.map((d, i) => makePageRow(d, i))}
{padRows.map(makePadRow)}
</TbodyComponent>
)
const Footers = () => hasColumnFooter ? makeColumnFooters() : null
const Pagination = () => showPagination ? (
<PaginationComponent
{...resolvedState}
pages={pages}
canPrevious={canPrevious}
canNext={canNext}
onPageChange={this.onPageChange}
onPageSizeChange={this.onPageSizeChange}
className={paginationProps.className}
style={paginationProps.style}
{...paginationProps.rest}
/>
) : null
const NoData = () => !pageRows.length ? (
<NoDataComponent
{...noDataProps}
>
{_.normalizeComponent(noDataText)}
</NoDataComponent>
) : null
const Loading = () => (
<LoadingComponent
loading={loading}
loadingText={loadingText}
{...loadingProps}
/>
)
const StandardTable = () => (
<Root>
<Table>
<HeaderGroups />
<Headers />
<Rows />
<Footers />
</Table>
<Pagination />
<NoData />
<Loading />
</Root>
)
Object.assign(StandardTable, {
Root,
Table,
HeaderGroups,
Headers,
Rows,
Footers,
Pagination,
NoData,
Loading
})
// childProps are optionally passed to a function-as-a-child
return children ? children(finalState, makeTable, this) : makeTable()
return children ? children(finalState, StandardTable, this) : <StandardTable />
}
})
-6
View File
@@ -22,12 +22,6 @@ $expandSize = 7px
background: alpha(black, .03)
border-bottom: 1px solid alpha(black, .05)
&.-filters
border-bottom: 1px solid alpha(black, 0.05)
.rt-th
border-right: 1px solid alpha(black, 0.02)
&.-header
box-shadow: 0 2px 15px 0px alpha(black, .15)
+9 -25
View File
@@ -11,8 +11,7 @@ export default {
page: 0,
pageSize: this.props.defaultPageSize || 10,
sorting: this.props.defaultSorting,
expandedRows: {},
filtering: this.props.defaultFiltering
expandedRows: {}
}
},
@@ -27,7 +26,7 @@ export default {
},
componentWillMount () {
this.setStateWithData(this.getDataModel(this.getResolvedState()))
this.setStateWithData(this.getDataModel())
},
componentDidMount () {
@@ -38,32 +37,21 @@ export default {
const oldState = this.getResolvedState()
const newState = this.getResolvedState(nextProps, nextState)
if (oldState.defaultSorting !== newState.defaultSorting) {
newState.sorting = newState.defaultSorting
}
if ((oldState.showFilters !== newState.showFilters) ||
(oldState.showFilters !== newState.showFilters)) {
newState.filtering = newState.defaultFiltering
}
// Props that trigger a data update
if (
oldState.data !== newState.data ||
oldState.columns !== newState.columns ||
oldState.pivotBy !== newState.pivotBy ||
oldState.sorting !== newState.sorting ||
oldState.showFilters !== newState.showFilters ||
oldState.filtering !== newState.filtering
oldState.sorting !== newState.sorting
) {
this.setStateWithData(this.getDataModel(newState))
this.setStateWithData(this.getDataModel(nextProps, nextState))
}
},
setStateWithData (newState, cb) {
const oldState = this.getResolvedState()
const newResolvedState = this.getResolvedState({}, newState)
const {freezeWhenExpanded} = newResolvedState
const { freezeWhenExpanded } = newResolvedState
// Default to unfrozen state
newResolvedState.frozen = false
@@ -85,16 +73,12 @@ export default {
if (
(oldState.frozen && !newResolvedState.frozen) ||
oldState.sorting !== newResolvedState.sorting ||
oldState.filtering !== newResolvedState.filtering ||
oldState.showFilters !== newResolvedState.showFilters ||
(!newResolvedState.frozen && oldState.resolvedData !== newResolvedState.resolvedData)
) {
// Handle collapseOnSortingChange & collapseOnDataChange
// Handle collapseOnSortingChange & collapseOnPageChange
if (
(oldState.sorting !== newResolvedState.sorting && this.props.collapseOnSortingChange) ||
(oldState.filtering !== newResolvedState.filtering) ||
(oldState.showFilters !== newResolvedState.showFilters) ||
(!newResolvedState.frozen && oldState.resolvedData !== newResolvedState.resolvedData && this.props.collapseOnDataChange)
(!newResolvedState.frozen && oldState.resolvedData !== newResolvedState.resolvedData && this.props.collapseOnPageChange)
) {
newResolvedState.expandedRows = {}
}
@@ -103,8 +87,8 @@ export default {
}
// Calculate pageSize all the time
if (newResolvedState.sortedData) {
newResolvedState.pages = newResolvedState.manual ? newResolvedState.pages : Math.ceil(newResolvedState.sortedData.length / newResolvedState.pageSize)
if (newResolvedState.resolvedData) {
newResolvedState.pages = newResolvedState.manual ? newResolvedState.pages : Math.ceil(newResolvedState.resolvedData.length / newResolvedState.pageSize)
}
return this.setState(newResolvedState, cb)
+26 -75
View File
@@ -1,7 +1,7 @@
import _ from './utils'
export default {
getDataModel (newState) {
getDataModel (nextProps, nextState) {
const {
columns,
pivotBy = [],
@@ -14,7 +14,7 @@ export default {
page,
pages,
pageSize
} = newState
} = this.getResolvedState(nextProps, nextState)
// Determine Header Groups
let hasHeaderGroups = false
@@ -192,14 +192,15 @@ export default {
// Group the rows together for this level
let groupedRows = Object.entries(
_.groupBy(rows, keys[i]))
.map(([key, value]) => {
return {
[pivotIDKey]: keys[i],
[pivotValKey]: key,
[keys[i]]: key,
[subRowsKey]: value
.map(([key, value]) => {
return {
[pivotIDKey]: keys[i],
[pivotValKey]: key,
[keys[i]]: key,
[subRowsKey]: value
}
}
})
)
// Recurse into the subRows
groupedRows = groupedRows.map(rowGroup => {
let subRows = groupRecursively(rowGroup[subRowsKey], keys, i + 1)
@@ -218,7 +219,6 @@ export default {
const newPage = page > newPages ? newPage - 1 : page
return {
...newState,
resolvedData,
pivotColumn,
allVisibleColumns,
@@ -232,16 +232,12 @@ export default {
const {
manual,
sorting,
filtering,
showFilters,
defaultFilterMethod,
resolvedData,
allVisibleColumns
resolvedData
} = resolvedState
// Resolve the data from either manual data or sorted data
return {
sortedData: manual ? resolvedData : this.sortData(resolvedData, sorting, showFilters, filtering, defaultFilterMethod, allVisibleColumns)
sortedData: manual ? resolvedData : this.sortData(resolvedData, sorting)
}
},
@@ -254,28 +250,11 @@ export default {
getStateOrProp (key) {
return _.getFirstDefined(this.state[key], this.props[key])
},
sortData (data, sorting, showFilters, filtering, defaultFilterMethod, allVisibleColumns) {
let filteredData = data
if (showFilters && filtering.length) {
filteredData = filtering.reduce(
(filteredSoFar, nextFilter) => {
return filteredSoFar.filter(
(row) => {
const column = allVisibleColumns.find(x => x.id === nextFilter.id) || {}
const filterMethod = column.filterMethod || defaultFilterMethod
return filterMethod(nextFilter, row, column)
})
}
, filteredData
)
}
sortData (data, sorting) {
if (!sorting.length) {
return filteredData
return data
}
const sorted = _.orderBy(filteredData, sorting.map(sort => {
const sorted = _.orderBy(data, sorting.map(sort => {
return row => {
if (row[sort.id] === null || row[sort.id] === undefined) {
return -Infinity
@@ -301,23 +280,20 @@ export default {
// User actions
onPageChange (page) {
const {onPageChange, collapseOnPageChange} = this.props
const { onPageChange } = this.props
if (onPageChange) {
return onPageChange(page)
}
const newState = {page}
if (collapseOnPageChange) {
newState.expandedRows = {}
}
this.setStateWithData(
newState
, () => {
this.fireOnChange()
})
this.setStateWithData({
expandedRows: {},
page
}, () => {
this.fireOnChange()
})
},
onPageSizeChange (newPageSize) {
const {onPageSizeChange} = this.props
const {pageSize, page} = this.getResolvedState()
const { onPageSizeChange } = this.props
const { pageSize, page } = this.getResolvedState()
// Normalize the page to display
const currentRow = pageSize * page
@@ -335,8 +311,8 @@ export default {
})
},
sortColumn (column, additive) {
const {sorting} = this.getResolvedState()
const {onSortingChange} = this.props
const { sorting } = this.getResolvedState()
const { onSortingChange } = this.props
if (onSortingChange) {
return onSortingChange(column, additive)
}
@@ -418,30 +394,5 @@ export default {
}, () => {
this.fireOnChange()
})
},
filterColumn (column, event) {
const {filtering} = this.getResolvedState()
const {onFilteringChange} = this.props
if (onFilteringChange) {
return onFilteringChange(column, event)
}
// Remove old filter first if it exists
const newFiltering = (filtering || []).filter(x => x.id !== column.id)
if (event.target.value !== '') {
newFiltering.push({
id: column.id,
value: event.target.value
})
}
this.setStateWithData({
page: 0,
filtering: newFiltering
}, () => {
this.fireOnChange()
})
}
}
+5 -8
View File
@@ -4,7 +4,7 @@ import classnames from 'classnames'
// import _ from './utils'
const defaultButton = (props) => (
<button type='button' {...props} className='-btn'>{props.children}</button>
<button {...props} className='-btn'>{props.children}</button>
)
export default React.createClass({
@@ -66,7 +66,9 @@ export default React.createClass({
<div className='-center'>
<span className='-pageInfo'>
{this.props.pageText} {showPageJump ? (
<div className='-pageJump'>
<form className='-pageJump'
onSubmit={this.applyPage}
>
<input
type={this.state.page === '' ? 'text' : 'number'}
onChange={e => {
@@ -79,13 +81,8 @@ export default React.createClass({
}}
value={this.state.page === '' ? '' : this.state.page + 1}
onBlur={this.applyPage}
onKeyPress={e => {
if (e.which === 13 || e.keyCode === 13) {
this.applyPage()
}
}}
/>
</div>
</form>
) : (
<span className='-currentPage'>{page + 1}</span>
)} {this.props.ofText} <span className='-totalPages'>{pages}</span>
+1 -1
View File
@@ -193,7 +193,7 @@ function isSortingDesc (d) {
function normalizeComponent (Comp, params = {}, fallback = Comp) {
return typeof Comp === 'function' ? (
Object.getPrototypeOf(Comp).isReactComponent ? (
Comp.prototype.isReactComponent ? (
<Comp
{...params}
/>
-206
View File
@@ -1,206 +0,0 @@
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
class Filtering 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,
showFilters: 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'
}]
}]
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) => ((row[filter.id] + "").startsWith(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 be an exact match. Example: age == "23".</p>
<p>This example overrides the default filter behavior by setting the <strong>defaultFilterMethod</strong> table option to match on values that start with the filter text. Example: age.startsWith("2")</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>
</div>
<CodeHighlight>{() => this.getCode()}</CodeHighlight>
</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
}
})
}
getCode() {
return `
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'
}]
}]
export default (
<ReactTable
data={data}
columns={columns}
defaultPageSize={10}
defaultFilterMethod={(filter, row) => ((row[filter.id] + \"\").startsWith(filter.value))}
{...otherOptions}
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>
)
}}
/>
)
`
}
}
export default () => <Filtering/>
+83 -3
View File
@@ -60,13 +60,16 @@ export default () => {
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 />
Whether it's <strong>completely custom</strong>, or even just <strong>rearranging the order of the table's elements</strong>, this is how you can do it.
<br />
<br />
<br />
<br />
<strong>Decorating the standard table output</strong>
<strong>Pagination at the top using partials:</strong>
<br />
<br />
@@ -75,7 +78,84 @@ export default () => {
data={data}
columns={columns}
>
{(state, makeTable, instance) => {
{(state, {
Root,
Table,
HeaderGroups,
Headers,
Rows,
Footers,
Pagination,
NoData,
Loading
}, instance) => {
return (
<Root>
<Pagination />
<Table>
<HeaderGroups />
<Headers />
<Rows />
<Footers />
</Table>
<NoData />
<Loading />
</Root>
)
}}
</ReactTable>
</div>
<CodeHighlight>{() => `
import ReactTable from 'react-table'
return (
<ReactTable
data={data}
columns={columns}
>
{(state, {
Root,
Table,
HeaderGroups,
Headers,
Rows,
Footers,
Pagination,
NoData,
Loading
}, instance) => {
return (
<Root>
<Pagination />
<Table>
<HeaderGroups />
<Headers />
<Rows />
<Footers />
</Table>
<NoData />
<Loading />
</Root>
)
}}
</ReactTable>
)
`}</CodeHighlight>
<br />
<br />
<strong>Wrapping the standard table output</strong>
<br />
<br />
<div className='table-wrap'>
<ReactTable
data={data}
columns={columns}
>
{(state, Table, instance) => {
return (
<div style={{
background: '#ffcf00',
@@ -84,7 +164,7 @@ export default () => {
padding: '5px'
}}>
<pre><code>state.allVisibleColumns === {JSON.stringify(state.allVisibleColumns, null, 4)}</code></pre>
{makeTable()}
<Table />
</div>
)
}}
+2 -6
View File
@@ -33,8 +33,7 @@ export default () => {
aggregate: vals => _.round(_.mean(vals)),
render: row => {
return <span>{row.aggregated ? `${row.value} (avg)` : row.value}</span>
},
filterMethod: (filter, row) => (filter.value == `${row[filter.id]} (avg)`)
}
}, {
header: 'Visits',
accessor: 'visits',
@@ -51,7 +50,6 @@ export default () => {
defaultPageSize={10}
className='-striped -highlight'
pivotBy={['firstName', 'lastName']}
showFilters={true}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
@@ -106,8 +104,7 @@ const columns = [{
aggregate: vals => _.round(_.mean(vals)),
render: row => {
return <span>{row.aggregated ? \`\${row.value} (avg)\` : row.value}</span>
},
filterMethod: (filter, row) => (filter.value == \`\${row[filter.id]} (avg)\`)
}
}, {
header: 'Visits',
accessor: 'visits',
@@ -122,7 +119,6 @@ return (
defaultPageSize={10}
className='-striped -highlight'
pivotBy={['firstName', 'lastName']}
showFilters={true}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
+7 -21
View File
@@ -14,34 +14,23 @@ const rawData = _.map(_.range(3424), d => {
})
// Now let's mock the server. It's job is simple: use the table model to sort and return the page data
const requestData = (pageSize, page, sorting, filtering) => {
const requestData = (pageSize, page, sorting) => {
return new Promise((resolve, reject) => {
// On the server, you'll likely use SQL or noSQL or some other query language to do this.
// For this mock, we'll just use lodash
let filteredData = rawData
if (filtering.length) {
filteredData = filtering.reduce(
(filteredSoFar, nextFilter) => {
return filteredSoFar.filter(
(row) => {
return (row[nextFilter.id] + '').includes(nextFilter.value)
})
}
, filteredData)
}
const sortedData = _.orderBy(filteredData, sorting.map(sort => {
const sortedData = _.orderBy(rawData, sorting.map(sort => {
return row => {
if (row[sort.id] === null || row[sort.id] === undefined) {
return -Infinity
}
return typeof row[sort.id] === 'string' ? row[sort.id].toLowerCase() : row[sort.id]
}
}), sorting.map(d => d.desc ? 'desc' : 'asc'))
}), sorting.map(d => d.asc ? 'asc' : 'desc'))
// Be sure to send back the rows to be displayed and any other pertinent information, like how many pages there are total.
const res = {
rows: sortedData.slice(pageSize * page, (pageSize * page) + pageSize),
pages: Math.ceil(filteredData.length / pageSize)
pages: Math.ceil(rawData.length / pageSize)
}
// Here we'll simulate a server response with 500ms of delay.
@@ -59,13 +48,13 @@ const ServerSide = React.createClass({
}
},
fetchData (state, instance) {
console.log(state, instance)
// Whenever the table model changes, or the user sorts or changes pages, this method gets called and passed the current table model.
// You can set the `loading` prop of the table to true to use the built-in one or show you're own loading bar if you want.
this.setState({loading: true})
// Request the data however you want. Here, we'll use our mocked service we created earlier
requestData(state.pageSize, state.page, state.sorting, state.filtering)
requestData(state.pageSize, state.page, state.sorting)
.then((res) => {
console.log(res.rows)
// 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,
@@ -93,7 +82,6 @@ const ServerSide = React.createClass({
}]}
manual // Forces table not to paginate or sort automatically, so we can handle it server-side
defaultPageSize={10}
showFilters
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
@@ -136,8 +124,7 @@ export default React.createClass({
Axios.post('mysite.com/data', {
pageSize: state.pageSize,
page: state.page,
sorting: state.sorting,
filtering: state.filtering
sorting: state.sorting
})
.then((res) => {
// Now update your state!
@@ -164,7 +151,6 @@ export default React.createClass({
}]}
manual // Forces table not to paginate or sort automatically, so we can handle it server-side
defaultPageSize={10}
showFilters={true}
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
+65 -131
View File
@@ -5,139 +5,77 @@ import namor from 'namor'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
class SubComponents 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,
showFilters: false
},
data: data
export default () => {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30)
}
})
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
}]
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
}]
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>
<CodeHighlight>{() => this.getCode()}</CodeHighlight>
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>You can put any component you want here, even another React Table!</em>
<br />
<br />
<ReactTable
data={data}
columns={columns}
defaultPageSize={3}
showPagination={false}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>It even has access to the row data: </em>
<CodeHighlight>{() => JSON.stringify(row, null, 2)}</CodeHighlight>
</div>
)
}}
/>
</div>
)
}}
/>
</div>
)
}
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
<CodeHighlight>{() => getCode()}</CodeHighlight>
</div>
)
}
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
}
})
}
getCode() {
return `
function getCode () {
return `
const columns = [{
header: 'Name',
columns: [{
@@ -161,7 +99,6 @@ export default (
data={data}
columns={columns}
defaultPageSize={10}
{...otherOptions}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
@@ -188,7 +125,4 @@ export default (
/>
)
`
}
}
export default () => <SubComponents/>
}
+1 -7
View File
@@ -2998,7 +2998,7 @@ indexof@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d"
inflight@^1.0.4:
inflight@^1.0.4, inflight@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
dependencies:
@@ -4964,12 +4964,6 @@ rimraf@2, rimraf@^2.2.8, rimraf@~2.5.1, rimraf@~2.5.4:
dependencies:
glob "^7.0.5"
rimraf@^2.6.1:
version "2.6.1"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d"
dependencies:
glob "^7.0.5"
ripemd160@0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-0.2.0.tgz#2bf198bde167cacfa51c0a928e84b68bbe171fce"