mirror of
https://github.com/gosticks/react-table.git
synced 2026-08-19 08:20:30 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0c3f2f2cd1 | ||
|
|
03538823e9 | ||
|
|
bc7005db99 | ||
|
|
42b5f5bb18 | ||
|
|
5ec616c2a3 | ||
|
|
c16df80938 |
@@ -26,6 +26,7 @@ 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'
|
||||
//
|
||||
configure(() => {
|
||||
storiesOf('1. Docs')
|
||||
@@ -51,6 +52,7 @@ configure(() => {
|
||||
.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)
|
||||
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
## Problem Description
|
||||
include a detailed explanation of the problem here...
|
||||
|
||||
## Code Snippet(s)
|
||||
## Code Snippet(s) or Codepen (http://codepen.io/tannerlinsley/pen/QpeZBa?editors=0010)
|
||||
|
||||
## Steps to Reproduce
|
||||
1. list the steps
|
||||
1. list the steps
|
||||
2. to reproduce the issue
|
||||
|
||||
## System Information
|
||||
|
||||
@@ -38,7 +38,9 @@
|
||||
- Fully controllable via optional props and callbacks
|
||||
- <a href="https://medium.com/@tannerlinsley/why-i-wrote-react-table-and-the-problems-it-has-solved-for-nozzle-others-445c4e93d4a8#.axza4ixba" target="\_parent">"Why I wrote React Table and the problems it has solved for Nozzle.io</a> by Tanner Linsley
|
||||
|
||||
## <a href="http://react-table.js.org/?selectedKind=2.%20Demos&selectedStory=Client-side%20Data&full=0&down=0&left=1&panelRight=0&downPanel=kadirahq%2Fstorybook-addon-actions%2Factions-panel" target="\_parent">Demo</a>
|
||||
## Demos and examples
|
||||
- <a href="http://codepen.io/tannerlinsley/pen/QpeZBa?editors=0010" target="\_blank">Codepen</a>
|
||||
- <a href="http://react-table.js.org/?selectedKind=2.%20Demos&selectedStory=Client-side%20Data&full=0&down=0&left=1&panelRight=0&downPanel=kadirahq%2Fstorybook-addon-actions%2Factions-panel" target="\_parent">Storybook</a>
|
||||
|
||||
## Table of Contents
|
||||
- [Installation](#installation)
|
||||
@@ -66,8 +68,6 @@
|
||||
## Installation
|
||||
1. Install React Table as a dependency
|
||||
```bash
|
||||
$ npm install react-table
|
||||
# or
|
||||
$ yarn add react-table
|
||||
```
|
||||
2. Import the `react-table` module
|
||||
@@ -77,13 +77,25 @@ import ReactTable from 'react-table'
|
||||
// ES5
|
||||
var ReactTable = require('react-table').default
|
||||
```
|
||||
3. Import styles by including `react-table.css` anywhere on the page
|
||||
3. Import styles by including `react-table.css`
|
||||
```javascript
|
||||
// JS (Webpack)
|
||||
import 'react-table/react-table.css'
|
||||
// html
|
||||
// Old-school
|
||||
<link rel="stylesheet" href="node_modules/react-table/react-table.css">
|
||||
```
|
||||
##### CDN
|
||||
```html
|
||||
<!-- CSS -->
|
||||
<link rel="stylesheet" href="https://unpkg.com/react-table@latest/react-table.css">
|
||||
|
||||
<!-- JS -->
|
||||
<script src="https://unpkg.com/react-table@latest/react-table.js"></script>
|
||||
|
||||
<script>
|
||||
var ReactTable = window.ReactTable.default
|
||||
</script>
|
||||
```
|
||||
|
||||
|
||||
## Example
|
||||
@@ -141,7 +153,6 @@ These are all of the available props (and their default values) for the main `<R
|
||||
pageSizeOptions: [5, 10, 20, 25, 50, 100],
|
||||
defaultPageSize: 20,
|
||||
showPageJump: true,
|
||||
expanderColumnWidth: 35,
|
||||
collapseOnSortingChange: true,
|
||||
collapseOnPageChange: true,
|
||||
collapseOnDataChange: true,
|
||||
@@ -246,6 +257,19 @@ These are all of the available props (and their default values) for the main `<R
|
||||
/>
|
||||
)
|
||||
},
|
||||
|
||||
// Global Expander Column Defaults
|
||||
expanderDefaults: {
|
||||
sortable: false,
|
||||
width: 35,
|
||||
hideFilter: true
|
||||
// render: will be overriden in methods.js to display ExpanderComponent
|
||||
},
|
||||
|
||||
// Global Pivot Column Defaults
|
||||
pivotDefaults: {
|
||||
// render: will be overriden in methods.js to display ExpanderComponent
|
||||
},
|
||||
|
||||
// Text
|
||||
previousText: 'Previous',
|
||||
@@ -295,8 +319,13 @@ Or just define them as props
|
||||
maxWidth: undefined, // A maximum width for this column.
|
||||
|
||||
// Special
|
||||
expander: false, // This option will override all data-related options and designates the column to be used
|
||||
// for pivoting and sub-component expansion
|
||||
// Turns this column into a special column for specifying expander and pivot column options.
|
||||
// If this option is true and there is NOT a pivot column, the `expanderDefaults` options will be applied on top of the column options.
|
||||
// If this option is true and there IS a pivot column, the `pivotDefaults` options will be applied on top of the column options.
|
||||
// Adding a column with the `expander` option set will allow you to rearrange expander and pivot column orderings in the table.
|
||||
// It will also let you specify rendering of the header (and header group if this special column is placed in the `columns` option of another column) and
|
||||
// the rendering of the expander itself.
|
||||
expander: false,
|
||||
|
||||
// Cell Options
|
||||
className: '', // Set the classname of the `td` element of the column
|
||||
@@ -640,7 +669,7 @@ 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, value) => {...}} // Called when a user enters a value into a filter input field or the value passed to the onFilterChange handler by the filterRender option.
|
||||
onFilteringChange={(column, value) => {...}} // Called when a user enters a value into a filter input field or the value passed to the onFilterChange handler by the filterRender option.
|
||||
onResize={(column, event, isTouch) => {...}} // Called when a user clicks on a resizing component (the right edge of a column header)
|
||||
/>
|
||||
```
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<div id="error-display"></div>
|
||||
<script src="static/preview.0cd0bb2bf09f3220bea7.bundle.js"></script>
|
||||
<script src="static/preview.5f0262046fdd8adfb130.bundle.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+1
-1
@@ -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.2e7b063c56eb89efa1fe.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":""}
|
||||
+27
-27
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"static/manager.2e7b063c56eb89efa1fe.bundle.js","sources":["webpack:///static/manager.2e7b063c56eb89efa1fe.bundle.js"],"mappings":"AAAA;AAkuDA;AA84DA;AA28DA;AA00DA;AAsvEA;AAuhDA;AAsrDA;AAsiDA;AAg6DA;AA2nDA;AA++CA;AAkvDA;AAsnEA;AA2oDA;AAivCA;AA+nDA;AAkpDA;AA6lEA;AAs4DA;AAquDA;AA+pDA;AAoxDA;AAsrDA;AA+yDA;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.0cd0bb2bf09f3220bea7.bundle.js","sources":["webpack:///static/preview.0cd0bb2bf09f3220bea7.bundle.js"],"mappings":"AAAA;AAkuDA;AA62DA;AAwtFA;AAsiFA;AA0uOA;AAgmGA;AA6rDA;AA0iEA;AA0xDA;AA25DA;AAmqDA;AA0vDA;AA+9CA;AAg5DA;AAwoDA;AAk7CA;AA2pDA;AAmjEA;AA27DA;AAghCA;AA4vDA;AA8kDA;AAwpEA;AAk3DA;AAy0DA;AA8xCA;AAu3EA;AAi4GA;AAwoDA;AAk+CA;AA+oCA;AAutCA;AA4jDA;AAwcA;AA+jFA","sourceRoot":""}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"static/preview.5f0262046fdd8adfb130.bundle.js","sources":["webpack:///static/preview.5f0262046fdd8adfb130.bundle.js"],"mappings":"AAAA;AAkuDA;AAmgEA;AA2jFA;AAinFA;AAgsPA;AA+6EA;AAytDA;AA+jEA;AAixDA;AAuzDA;AAk1DA;AA6pDA;AA2+CA;AA+4DA;AAqpDA;AA89CA;AA0nDA;AA2jEA;AA03DA;AA6gCA;AA80DA;AAooDA;AA2nEA;AAw1DA;AA64DA;AAixCA;AAyrFA;AAmjGA;AA4lDA;AA+zCA;AA8vCA;AAshCA;AAwpDA;AA+rCA;AAsCA;AA+jFA","sourceRoot":""}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-table",
|
||||
"version": "5.5.3",
|
||||
"version": "5.6.0",
|
||||
"description": "A fast, lightweight, opinionated table and datagrid built on React",
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/tannerlinsley/react-table#readme",
|
||||
|
||||
+17
-6
@@ -15,7 +15,6 @@ export default {
|
||||
pageSizeOptions: [5, 10, 20, 25, 50, 100],
|
||||
defaultPageSize: 20,
|
||||
showPageJump: true,
|
||||
expanderColumnWidth: 35,
|
||||
collapseOnSortingChange: true,
|
||||
collapseOnPageChange: true,
|
||||
collapseOnDataChange: true,
|
||||
@@ -120,6 +119,19 @@ export default {
|
||||
)
|
||||
},
|
||||
|
||||
// Global Expander Column Defaults
|
||||
expanderDefaults: {
|
||||
sortable: false,
|
||||
width: 35,
|
||||
hideFilter: true
|
||||
// render: will be overriden in methods.js to display ExpanderComponent
|
||||
},
|
||||
|
||||
// Global Pivot Column Defaults
|
||||
pivotDefaults: {
|
||||
// render: will be overriden in methods.js to display ExpanderComponent
|
||||
},
|
||||
|
||||
// Text
|
||||
previousText: 'Previous',
|
||||
nextText: 'Next',
|
||||
@@ -150,12 +162,11 @@ export default {
|
||||
},
|
||||
TdComponent: _.makeTemplateComponent('rt-td'),
|
||||
TfootComponent: _.makeTemplateComponent('rt-tfoot'),
|
||||
ExpanderComponent: ({isExpanded, ...rest}) => {
|
||||
ExpanderComponent: ({isExpanded}) => {
|
||||
return (
|
||||
<div
|
||||
className={classnames('rt-expander', isExpanded && '-open')}
|
||||
{...rest}
|
||||
>•</div>
|
||||
<div className={classnames('rt-expander', isExpanded && '-open')}>
|
||||
•
|
||||
</div>
|
||||
)
|
||||
},
|
||||
PaginationComponent: Pagination,
|
||||
|
||||
+72
-124
@@ -1,16 +1,47 @@
|
||||
import React from 'react'
|
||||
import React, { Component } from 'react'
|
||||
import classnames from 'classnames'
|
||||
//
|
||||
import _ from './utils'
|
||||
import lifecycle from './lifecycle'
|
||||
import methods from './methods'
|
||||
import defaults from './defaultProps'
|
||||
import Lifecycle from './lifecycle'
|
||||
import Methods from './methods'
|
||||
import defaultProps from './defaultProps'
|
||||
|
||||
export const ReactTableDefaults = defaults
|
||||
export const ReactTableDefaults = defaultProps
|
||||
|
||||
export default React.createClass({
|
||||
...lifecycle,
|
||||
...methods,
|
||||
export default class ReactTable extends Methods(Lifecycle(Component)) {
|
||||
static defaultProps = defaultProps
|
||||
|
||||
constructor (props) {
|
||||
super()
|
||||
|
||||
this.getResolvedState = this.getResolvedState.bind(this)
|
||||
this.getDataModel = this.getDataModel.bind(this)
|
||||
this.getSortedData = this.getSortedData.bind(this)
|
||||
this.fireOnChange = this.fireOnChange.bind(this)
|
||||
this.getPropOrState = this.getPropOrState.bind(this)
|
||||
this.getStateOrProp = this.getStateOrProp.bind(this)
|
||||
this.filterData = this.filterData.bind(this)
|
||||
this.sortData = this.sortData.bind(this)
|
||||
this.getMinRows = this.getMinRows.bind(this)
|
||||
this.onPageChange = this.onPageChange.bind(this)
|
||||
this.onPageSizeChange = this.onPageSizeChange.bind(this)
|
||||
this.sortColumn = this.sortColumn.bind(this)
|
||||
this.filterColumn = this.filterColumn.bind(this)
|
||||
this.resizeColumnStart = this.resizeColumnStart.bind(this)
|
||||
this.resizeColumnEnd = this.resizeColumnEnd.bind(this)
|
||||
this.resizeColumnMoving = this.resizeColumnMoving.bind(this)
|
||||
|
||||
this.state = {
|
||||
page: 0,
|
||||
pageSize: props.defaultPageSize || 10,
|
||||
sorting: props.defaultSorting,
|
||||
expandedRows: {},
|
||||
filtering: props.defaultFiltering,
|
||||
resizing: props.defaultResizing,
|
||||
currentlyResizing: undefined,
|
||||
skipNextSort: false
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
const resolvedState = this.getResolvedState()
|
||||
@@ -41,7 +72,6 @@ export default React.createClass({
|
||||
getNoDataProps,
|
||||
getResizerProps,
|
||||
showPagination,
|
||||
expanderColumnWidth,
|
||||
manual,
|
||||
loadingText,
|
||||
noDataText,
|
||||
@@ -69,7 +99,6 @@ export default React.createClass({
|
||||
ThComponent,
|
||||
TdComponent,
|
||||
TfootComponent,
|
||||
ExpanderComponent,
|
||||
PaginationComponent,
|
||||
LoadingComponent,
|
||||
SubComponent,
|
||||
@@ -200,39 +229,6 @@ export default React.createClass({
|
||||
maxWidth: `${maxWidth}px`
|
||||
}
|
||||
|
||||
if (column.expander) {
|
||||
if (column.pivotColumns) {
|
||||
return (
|
||||
<ThComponent
|
||||
key={i}
|
||||
className={classnames(
|
||||
'rt-pivot-header',
|
||||
classes
|
||||
)}
|
||||
style={{
|
||||
...styles,
|
||||
...flexStyles
|
||||
}}
|
||||
{...rest}
|
||||
/>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<ThComponent
|
||||
key={i}
|
||||
className={classnames(
|
||||
'rt-expander-header',
|
||||
classes
|
||||
)}
|
||||
style={{
|
||||
...styles,
|
||||
flex: `0 0 auto`,
|
||||
width: `${expanderColumnWidth}px`
|
||||
}}
|
||||
{...rest}
|
||||
/>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<ThComponent
|
||||
key={i}
|
||||
@@ -343,7 +339,10 @@ export default React.createClass({
|
||||
column: column
|
||||
})}
|
||||
{i < column.pivotColumns.length - 1 && (
|
||||
<ExpanderComponent />
|
||||
_.normalizeComponent(column.render, {
|
||||
data: sortedData,
|
||||
column: column
|
||||
})
|
||||
)}
|
||||
</span>
|
||||
)
|
||||
@@ -353,21 +352,6 @@ export default React.createClass({
|
||||
</ThComponent>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<ThComponent
|
||||
key={i}
|
||||
className={classnames(
|
||||
'rt-expander-header',
|
||||
classes
|
||||
)}
|
||||
style={{
|
||||
...styles,
|
||||
flex: `0 0 auto`,
|
||||
width: `${expanderColumnWidth}px`
|
||||
}}
|
||||
{...rest}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -465,13 +449,21 @@ export default React.createClass({
|
||||
filter,
|
||||
onFilterChange: (value) => (this.filterColumn(column, value, col))
|
||||
},
|
||||
defaults.column.filterRender
|
||||
defaultProps.column.filterRender
|
||||
)
|
||||
) : null}
|
||||
</span>
|
||||
)
|
||||
if (i < column.pivotColumns.length - 1) {
|
||||
pivotCols.push(<ExpanderComponent key={col.id + '-' + i} />)
|
||||
pivotCols.push(
|
||||
_.normalizeComponent(column.filterRender,
|
||||
{
|
||||
column,
|
||||
filter,
|
||||
key: col.id + '-' + i
|
||||
},
|
||||
defaultProps.column.filterRender
|
||||
))
|
||||
}
|
||||
}
|
||||
return (
|
||||
@@ -495,21 +487,6 @@ export default React.createClass({
|
||||
</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)
|
||||
@@ -535,7 +512,7 @@ export default React.createClass({
|
||||
filter,
|
||||
onFilterChange: (value) => (this.filterColumn(column, value))
|
||||
},
|
||||
defaults.column.filterRender
|
||||
defaultProps.column.filterRender
|
||||
)
|
||||
) : null}
|
||||
</ThComponent>
|
||||
@@ -589,6 +566,8 @@ export default React.createClass({
|
||||
...columnProps.style
|
||||
}
|
||||
|
||||
const extraProps = {}
|
||||
|
||||
if (column.expander) {
|
||||
const onTdClick = (e) => {
|
||||
if (onExpandRow) {
|
||||
@@ -605,6 +584,8 @@ export default React.createClass({
|
||||
})
|
||||
}
|
||||
|
||||
extraProps['onClick'] = onTdClick
|
||||
|
||||
if (column.pivotColumns) {
|
||||
// Return the pivot expander cell
|
||||
const PivotCell = column.pivotRender
|
||||
@@ -627,9 +608,11 @@ export default React.createClass({
|
||||
>
|
||||
{rowInfo.subRows ? (
|
||||
<span>
|
||||
<ExpanderComponent
|
||||
isExpanded={isExpanded}
|
||||
/>
|
||||
{_.normalizeComponent(column.render, {
|
||||
...rowInfo,
|
||||
value: rowInfo.rowValues[column.id],
|
||||
isExpanded
|
||||
}, rowInfo.rowValues[column.id])}
|
||||
{column && column.pivotRender ? (
|
||||
<PivotCell
|
||||
{...rowInfo}
|
||||
@@ -639,37 +622,16 @@ export default React.createClass({
|
||||
</span>
|
||||
) : SubComponent ? (
|
||||
<span>
|
||||
<ExpanderComponent
|
||||
isExpanded={isExpanded}
|
||||
/>
|
||||
{_.normalizeComponent(column.render, {
|
||||
...rowInfo,
|
||||
value: rowInfo.rowValues[column.id],
|
||||
isExpanded
|
||||
}, rowInfo.rowValues[column.id])}
|
||||
</span>
|
||||
) : null}
|
||||
</TdComponent>
|
||||
)
|
||||
}
|
||||
|
||||
// Return the regular expander cell
|
||||
return (
|
||||
<TdComponent
|
||||
key={i2}
|
||||
className={classnames(
|
||||
classes,
|
||||
{hidden: !show}
|
||||
)}
|
||||
style={{
|
||||
...styles,
|
||||
flex: `0 0 auto`,
|
||||
width: `${expanderColumnWidth}px`
|
||||
}}
|
||||
onClick={onTdClick}
|
||||
>
|
||||
<span>
|
||||
<ExpanderComponent
|
||||
isExpanded={isExpanded}
|
||||
/>
|
||||
</span>
|
||||
</TdComponent>
|
||||
)
|
||||
}
|
||||
|
||||
// Return regular cell
|
||||
@@ -687,10 +649,12 @@ export default React.createClass({
|
||||
maxWidth: `${maxWidth}px`
|
||||
}}
|
||||
{...tdProps.rest}
|
||||
{...extraProps}
|
||||
>
|
||||
{_.normalizeComponent(column.render, {
|
||||
...rowInfo,
|
||||
value: rowInfo.rowValues[column.id]
|
||||
value: rowInfo.rowValues[column.id],
|
||||
isExpanded
|
||||
}, rowInfo.rowValues[column.id])}
|
||||
</TdComponent>
|
||||
)
|
||||
@@ -830,22 +794,6 @@ export default React.createClass({
|
||||
</TdComponent>
|
||||
)
|
||||
}
|
||||
|
||||
// Return the regular expander cell
|
||||
return (
|
||||
<TdComponent
|
||||
key={i2}
|
||||
className={classnames(
|
||||
classes,
|
||||
{hidden: !show}
|
||||
)}
|
||||
style={{
|
||||
...styles,
|
||||
flex: `0 0 auto`,
|
||||
width: `${expanderColumnWidth}px`
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
// Return regular cell
|
||||
@@ -951,4 +899,4 @@ export default React.createClass({
|
||||
// childProps are optionally passed to a function-as-a-child
|
||||
return children ? children(finalState, makeTable, this) : makeTable()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
+4
-33
@@ -1,41 +1,12 @@
|
||||
import _ from './utils'
|
||||
import defaultProps from './defaultProps'
|
||||
|
||||
export default {
|
||||
getDefaultProps () {
|
||||
return defaultProps
|
||||
},
|
||||
|
||||
getInitialState () {
|
||||
return {
|
||||
page: 0,
|
||||
pageSize: this.props.defaultPageSize || 10,
|
||||
sorting: this.props.defaultSorting,
|
||||
expandedRows: {},
|
||||
filtering: this.props.defaultFiltering,
|
||||
resizing: this.props.defaultResizing,
|
||||
currentlyResizing: undefined,
|
||||
skipNextSort: false
|
||||
}
|
||||
},
|
||||
|
||||
getResolvedState (props, state) {
|
||||
const resolvedState = {
|
||||
..._.compactObject(this.state),
|
||||
..._.compactObject(this.props),
|
||||
..._.compactObject(state),
|
||||
..._.compactObject(props)
|
||||
}
|
||||
return resolvedState
|
||||
},
|
||||
export default Base => class extends Base {
|
||||
|
||||
componentWillMount () {
|
||||
this.setStateWithData(this.getDataModel(this.getResolvedState()))
|
||||
},
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
this.fireOnChange()
|
||||
},
|
||||
}
|
||||
|
||||
componentWillReceiveProps (nextProps, nextState) {
|
||||
const oldState = this.getResolvedState()
|
||||
@@ -61,7 +32,7 @@ export default {
|
||||
) {
|
||||
this.setStateWithData(this.getDataModel(newState))
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
setStateWithData (newState, cb) {
|
||||
const oldState = this.getResolvedState()
|
||||
|
||||
+87
-42
@@ -1,6 +1,16 @@
|
||||
import _ from './utils'
|
||||
|
||||
export default {
|
||||
export default Base => class extends Base {
|
||||
getResolvedState (props, state) {
|
||||
const resolvedState = {
|
||||
..._.compactObject(this.state),
|
||||
..._.compactObject(this.props),
|
||||
..._.compactObject(state),
|
||||
..._.compactObject(props)
|
||||
}
|
||||
return resolvedState
|
||||
}
|
||||
|
||||
getDataModel (newState) {
|
||||
const {
|
||||
columns,
|
||||
@@ -9,7 +19,6 @@ export default {
|
||||
pivotIDKey,
|
||||
pivotValKey,
|
||||
subRowsKey,
|
||||
expanderColumnWidth,
|
||||
SubComponent
|
||||
} = newState
|
||||
|
||||
@@ -35,29 +44,42 @@ export default {
|
||||
currentSpan = []
|
||||
}
|
||||
|
||||
const noSubExpanderColumns = columns.map(col => {
|
||||
return {
|
||||
...col,
|
||||
columns: col.columns ? col.columns.filter(d => !d.expander) : undefined
|
||||
}
|
||||
})
|
||||
let columnsWithExpander = [...columns]
|
||||
|
||||
let expanderColumnIndex = columns.findIndex(col => col.expander)
|
||||
const needsExpander = (SubComponent || pivotBy.length) && expanderColumnIndex === -1
|
||||
const columnsWithExpander = needsExpander ? [{expander: true}, ...noSubExpanderColumns] : noSubExpanderColumns
|
||||
if (needsExpander) {
|
||||
expanderColumnIndex = 0
|
||||
let expanderColumn = columns.find(col => col.expander || (col.columns && col.columns.some(col2 => col2.expander)))
|
||||
// The actual expander might be in the columns field of a group column
|
||||
if (expanderColumn && !expanderColumn.expander) {
|
||||
expanderColumn = expanderColumn.columns.find(col => col.expander)
|
||||
}
|
||||
|
||||
// If it has subrows or pivot columns we need to make sure we have an expander column
|
||||
if ((SubComponent || pivotBy.length) && !expanderColumn) {
|
||||
expanderColumn = {expander: true}
|
||||
columnsWithExpander = [expanderColumn, ...columnsWithExpander]
|
||||
}
|
||||
|
||||
const makeDecoratedColumn = (column) => {
|
||||
const dcol = {
|
||||
...this.props.column,
|
||||
...column
|
||||
}
|
||||
|
||||
if (dcol.expander) {
|
||||
dcol.width = expanderColumnWidth
|
||||
return dcol
|
||||
let dcol
|
||||
if (pivotBy.length && column.expander) {
|
||||
dcol = {
|
||||
...this.props.column,
|
||||
render: this.props.ExpanderComponent,
|
||||
filterRender: this.props.ExpanderComponent,
|
||||
...this.props.pivotDefaults,
|
||||
...column
|
||||
}
|
||||
} else if (column.expander) {
|
||||
dcol = {
|
||||
...this.props.column,
|
||||
render: this.props.ExpanderComponent,
|
||||
...this.props.expanderDefaults,
|
||||
...column
|
||||
}
|
||||
} else {
|
||||
dcol = {
|
||||
...this.props.column,
|
||||
...column
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof dcol.accessor === 'string') {
|
||||
@@ -129,12 +151,24 @@ export default {
|
||||
pivotColumns.push(allDecoratedColumns[i])
|
||||
}
|
||||
}
|
||||
const pivotColumn = {
|
||||
...pivotColumns[0],
|
||||
pivotColumns,
|
||||
expander: true
|
||||
|
||||
const pivotExpanderColumn = visibleColumns.findIndex(col => col.expander || (col.columns && col.columns.some(col2 => col2.expander)))
|
||||
if (pivotExpanderColumn >= 0) {
|
||||
const pivotColumn = {
|
||||
...visibleColumns[pivotExpanderColumn],
|
||||
pivotColumns
|
||||
}
|
||||
visibleColumns[pivotExpanderColumn] = pivotColumn
|
||||
} else {
|
||||
// If the expander column wasn't on the top level column, find it in the `columns` option.
|
||||
const pivotExpanderSubColumn = visibleColumns[pivotExpanderColumn].columns.findIndex(col => col.expander)
|
||||
const pivotColumn = {
|
||||
...visibleColumns[pivotExpanderColumn].columns[pivotExpanderSubColumn],
|
||||
pivotColumns
|
||||
}
|
||||
// Add the pivot columns to the expander column
|
||||
visibleColumns[pivotExpanderColumn].columns[pivotExpanderSubColumn] = pivotColumn
|
||||
}
|
||||
visibleColumns[expanderColumnIndex] = pivotColumn
|
||||
}
|
||||
|
||||
// Build flast list of allVisibleColumns and HeaderGroups
|
||||
@@ -176,8 +210,7 @@ export default {
|
||||
})
|
||||
return aggregationValues
|
||||
}
|
||||
let standardColumns = pivotBy.length ? allVisibleColumns.slice(1) : allVisibleColumns
|
||||
const aggregatingColumns = standardColumns.filter(d => d.aggregate)
|
||||
const aggregatingColumns = allVisibleColumns.filter(d => !d.expander && d.aggregate)
|
||||
let pivotColumn
|
||||
if (pivotBy.length) {
|
||||
pivotColumn = allVisibleColumns[0]
|
||||
@@ -220,7 +253,8 @@ export default {
|
||||
allDecoratedColumns,
|
||||
hasHeaderGroups
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
getSortedData (resolvedState) {
|
||||
const {
|
||||
manual,
|
||||
@@ -236,16 +270,20 @@ export default {
|
||||
return {
|
||||
sortedData: manual ? resolvedData : this.sortData(this.filterData(resolvedData, showFilters, filtering, defaultFilterMethod, allVisibleColumns), sorting)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
fireOnChange () {
|
||||
this.props.onChange(this.getResolvedState(), this)
|
||||
},
|
||||
}
|
||||
|
||||
getPropOrState (key) {
|
||||
return _.getFirstDefined(this.props[key], this.state[key])
|
||||
},
|
||||
}
|
||||
|
||||
getStateOrProp (key) {
|
||||
return _.getFirstDefined(this.state[key], this.props[key])
|
||||
},
|
||||
}
|
||||
|
||||
filterData (data, showFilters, filtering, defaultFilterMethod, allVisibleColumns) {
|
||||
let filteredData = data
|
||||
|
||||
@@ -290,7 +328,8 @@ export default {
|
||||
}
|
||||
|
||||
return filteredData
|
||||
},
|
||||
}
|
||||
|
||||
sortData (data, sorting) {
|
||||
if (!sorting.length) {
|
||||
return data
|
||||
@@ -314,11 +353,11 @@ export default {
|
||||
[this.props.subRowsKey]: this.sortData(row[this.props.subRowsKey], sorting)
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
getMinRows () {
|
||||
return _.getFirstDefined(this.props.minRows, this.getStateOrProp('pageSize'))
|
||||
},
|
||||
}
|
||||
|
||||
// User actions
|
||||
onPageChange (page) {
|
||||
@@ -335,7 +374,8 @@ export default {
|
||||
, () => {
|
||||
this.fireOnChange()
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
onPageSizeChange (newPageSize) {
|
||||
const {onPageSizeChange} = this.props
|
||||
const {pageSize, page} = this.getResolvedState()
|
||||
@@ -354,7 +394,8 @@ export default {
|
||||
}, () => {
|
||||
this.fireOnChange()
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
sortColumn (column, additive) {
|
||||
const {sorting, skipNextSort} = this.getResolvedState()
|
||||
|
||||
@@ -451,7 +492,8 @@ export default {
|
||||
}, () => {
|
||||
this.fireOnChange()
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
filterColumn (column, value, pivotColumn) {
|
||||
const {filtering} = this.getResolvedState()
|
||||
const {onFilteringChange} = this.props
|
||||
@@ -486,7 +528,8 @@ export default {
|
||||
}, () => {
|
||||
this.fireOnChange()
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
resizeColumnStart (column, event, isTouch) {
|
||||
const {onResize} = this.props
|
||||
|
||||
@@ -520,7 +563,8 @@ export default {
|
||||
document.addEventListener('mouseleave', this.resizeColumnEnd)
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
resizeColumnEnd (event) {
|
||||
let isTouch = event.type === 'touchend' || event.type === 'touchcancel'
|
||||
|
||||
@@ -544,7 +588,8 @@ export default {
|
||||
skipNextSort: true
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
resizeColumnMoving (event) {
|
||||
const {resizing, currentlyResizing} = this.getResolvedState()
|
||||
|
||||
|
||||
+22
-11
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import React, { Component } from 'react'
|
||||
import classnames from 'classnames'
|
||||
//
|
||||
// import _ from './utils'
|
||||
@@ -7,33 +7,44 @@ const defaultButton = (props) => (
|
||||
<button type='button' {...props} className='-btn'>{props.children}</button>
|
||||
)
|
||||
|
||||
export default React.createClass({
|
||||
getInitialState () {
|
||||
return {
|
||||
page: this.props.page
|
||||
export default class ReactTablePagination extends Component {
|
||||
constructor (props) {
|
||||
super()
|
||||
|
||||
this.getSafePage = this.getSafePage.bind(this)
|
||||
this.changePage = this.changePage.bind(this)
|
||||
this.applyPage = this.applyPage.bind(this)
|
||||
|
||||
this.state = {
|
||||
page: props.page
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
this.setState({page: nextProps.page})
|
||||
},
|
||||
}
|
||||
|
||||
getSafePage (page) {
|
||||
if (isNaN(page)) {
|
||||
page = this.props.page
|
||||
}
|
||||
return Math.min(Math.max(page, 0), this.props.pages - 1)
|
||||
},
|
||||
}
|
||||
|
||||
changePage (page) {
|
||||
page = this.getSafePage(page)
|
||||
this.setState({page})
|
||||
if (this.props.page !== page) {
|
||||
this.props.onPageChange(page)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
applyPage (e) {
|
||||
e && e.preventDefault()
|
||||
const page = this.state.page
|
||||
this.changePage(page === '' ? this.props.page : page)
|
||||
},
|
||||
}
|
||||
|
||||
render () {
|
||||
const {
|
||||
// Computed
|
||||
@@ -128,4 +139,4 @@ export default React.createClass({
|
||||
</div>
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@ import ReactTable from '../src/index'
|
||||
export default () => {
|
||||
const data = _.map(_.range(5553), d => {
|
||||
return {
|
||||
firstName: namor.generate({ words: 1, numLen: 0 }),
|
||||
lastName: namor.generate({ words: 1, numLen: 0 }),
|
||||
firstName: namor.generate({words: 1, numLen: 0}),
|
||||
lastName: namor.generate({words: 1, numLen: 0}),
|
||||
age: Math.floor(Math.random() * 30)
|
||||
}
|
||||
})
|
||||
@@ -19,26 +19,33 @@ export default () => {
|
||||
columns: [{
|
||||
header: 'First Name',
|
||||
accessor: 'firstName',
|
||||
render: row => {
|
||||
return <span>{row.aggregated ? '...' : row.value}</span>
|
||||
}
|
||||
footer: () => <div style={{textAlign: 'center'}}>First Name</div>
|
||||
}, {
|
||||
header: 'Last Name',
|
||||
id: 'lastName',
|
||||
accessor: d => d.lastName
|
||||
accessor: 'lastName',
|
||||
footer: () => <div style={{textAlign: 'center'}}>Last Name</div>
|
||||
}]
|
||||
}, {
|
||||
header: 'Info',
|
||||
columns: [{
|
||||
header: 'Age',
|
||||
accessor: 'age',
|
||||
aggregate: vals => _.round(_.mean(vals)),
|
||||
render: row => {
|
||||
return <span>{row.aggregated ? `${row.value} (avg)` : row.value}</span>
|
||||
}
|
||||
footer: () => <div style={{textAlign: 'center'}}>Age</div>
|
||||
}]
|
||||
}, {
|
||||
expander: true
|
||||
header: 'Expand',
|
||||
columns: [{
|
||||
expander: true,
|
||||
header: () => (<strong>More</strong>),
|
||||
width: 65,
|
||||
render: ({isExpanded, ...rest}) => (
|
||||
<div>
|
||||
{isExpanded ? <span>⊙</span> : <span>⊕</span>}
|
||||
</div>
|
||||
),
|
||||
style: {cursor: 'pointer', fontSize: 25, padding: '0', textAlign: 'center', userSelect: 'none'},
|
||||
footer: () => <span>♥</span>
|
||||
}]
|
||||
}]
|
||||
|
||||
return (
|
||||
@@ -71,26 +78,33 @@ const columns = [{
|
||||
columns: [{
|
||||
header: 'First Name',
|
||||
accessor: 'firstName',
|
||||
render: row => {
|
||||
return <span>{row.aggregated ? '...' : row.value}</span>
|
||||
}
|
||||
footer: () => <div style={{textAlign: 'center'}}>First Name</div>
|
||||
}, {
|
||||
header: 'Last Name',
|
||||
id: 'lastName',
|
||||
accessor: d => d.lastName
|
||||
accessor: 'lastName',
|
||||
footer: () => <div style={{textAlign: 'center'}}>Last Name</div>
|
||||
}]
|
||||
}, {
|
||||
header: 'Info',
|
||||
columns: [{
|
||||
header: 'Age',
|
||||
accessor: 'age',
|
||||
aggregate: vals => _.round(_.mean(vals)),
|
||||
render: row => {
|
||||
return <span>{row.aggregated ? \`$\{row.value} (avg)\` : row.value}</span>
|
||||
}
|
||||
footer: () => <div style={{textAlign: 'center'}}>Age</div>
|
||||
}]
|
||||
}, {
|
||||
expander: true
|
||||
header: 'Expand',
|
||||
columns: [{
|
||||
expander: true,
|
||||
header: () => (<strong>More</strong>),
|
||||
width: 65,
|
||||
render: ({isExpanded, ...rest}) => (
|
||||
<div>
|
||||
{isExpanded ? <span>⊙</span> : <span>⊕</span>}
|
||||
</div>
|
||||
),
|
||||
style: {cursor: 'pointer', fontSize: 25, padding: '0', textAlign: 'center', userSelect: 'none'},
|
||||
footer: () => <span>♥</span>
|
||||
}]
|
||||
}]
|
||||
|
||||
return (
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
import React from 'react'
|
||||
import _ from 'lodash'
|
||||
import namor from 'namor'
|
||||
|
||||
import CodeHighlight from './components/codeHighlight'
|
||||
import ReactTable from '../src/index'
|
||||
|
||||
export default () => {
|
||||
const data = _.map(_.range(1000), d => {
|
||||
return {
|
||||
firstName: namor.generate({words: 1, numLen: 0}),
|
||||
lastName: namor.generate({words: 1, numLen: 0}),
|
||||
age: Math.floor(Math.random() * 30),
|
||||
visits: Math.floor(Math.random() * 100)
|
||||
}
|
||||
})
|
||||
|
||||
const columns = [{
|
||||
header: 'Name',
|
||||
columns: [{
|
||||
header: 'First Name',
|
||||
accessor: 'firstName'
|
||||
}, {
|
||||
header: 'Last Name',
|
||||
id: 'lastName',
|
||||
accessor: d => d.lastName
|
||||
}]
|
||||
}, {
|
||||
header: 'Info',
|
||||
columns: [{
|
||||
header: 'Age',
|
||||
accessor: 'age',
|
||||
aggregate: vals => {
|
||||
return _.round(_.mean(vals))
|
||||
},
|
||||
render: row => {
|
||||
return <span>{row.aggregated ? `${row.value} (avg)` : row.value}</span>
|
||||
}
|
||||
}, {
|
||||
header: 'Visits',
|
||||
accessor: 'visits',
|
||||
aggregate: vals => _.sum(vals),
|
||||
hideFilter: true
|
||||
}]
|
||||
}, {
|
||||
header: () => <strong>First ⇢ Last Name Pivot</strong>,
|
||||
expander: true,
|
||||
minWidth: 200,
|
||||
render: ({isExpanded, ...rest}) => (
|
||||
isExpanded ? <span> ➘ </span> : <span> ➙ </span>
|
||||
),
|
||||
filterRender: ({key}) => <span key={key}> ⥱ </span>,
|
||||
footer: () => <div style={{textAlign: 'center'}}><strong>Pivot Footer</strong></div>
|
||||
}]
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className='table-wrap'>
|
||||
<ReactTable
|
||||
data={data}
|
||||
columns={columns}
|
||||
defaultPageSize={10}
|
||||
className='-striped -highlight'
|
||||
pivotBy={['firstName', 'lastName']}
|
||||
showFilters={true}
|
||||
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.filter(x=>!x.expander)}
|
||||
defaultPageSize={3}
|
||||
showPagination={false}
|
||||
SubComponent={(row) => {
|
||||
return (
|
||||
<div style={{padding: '20px'}}>
|
||||
<em>It even has access to the row data: </em>
|
||||
<CodeHighlight>{() => JSON.stringify(row, null, 2)}</CodeHighlight>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<br />
|
||||
<em>Tip: Hold shift when sorting to multi-sort!</em>
|
||||
</div>
|
||||
<CodeHighlight>{() => getCode()}</CodeHighlight>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function getCode () {
|
||||
return `
|
||||
const columns = [{
|
||||
header: 'Name',
|
||||
columns: [{
|
||||
header: 'First Name',
|
||||
accessor: 'firstName'
|
||||
}, {
|
||||
header: 'Last Name',
|
||||
id: 'lastName',
|
||||
accessor: d => d.lastName
|
||||
}]
|
||||
}, {
|
||||
header: 'Info',
|
||||
columns: [{
|
||||
header: 'Age',
|
||||
accessor: 'age',
|
||||
aggregate: vals => {
|
||||
return _.round(_.mean(vals))
|
||||
},
|
||||
render: row => {
|
||||
return <span>{row.aggregated ? \`\${row.value} (avg)\` : row.value}</span>
|
||||
}
|
||||
}, {
|
||||
header: 'Visits',
|
||||
accessor: 'visits',
|
||||
aggregate: vals => _.sum(vals),
|
||||
hideFilter: true
|
||||
}]
|
||||
}, {
|
||||
header: () => <strong>First ⇢ Last Name Pivot</strong>,
|
||||
expander: true,
|
||||
minWidth: 200,
|
||||
render: ({isExpanded, ...rest}) => (
|
||||
isExpanded ? <span> ➘ </span> : <span> ➙ </span>
|
||||
),
|
||||
filterRender: ({key}) => <span key={key}> ⥱ </span>,
|
||||
footer: () => <div style={{textAlign: 'center'}}><strong>Pivot Footer</strong></div>
|
||||
}]
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className='table-wrap'>
|
||||
<ReactTable
|
||||
data={data}
|
||||
columns={columns}
|
||||
defaultPageSize={10}
|
||||
className='-striped -highlight'
|
||||
pivotBy={['firstName', 'lastName']}
|
||||
showFilters={true}
|
||||
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.filter(x=>!x.expander)}
|
||||
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>
|
||||
)
|
||||
`
|
||||
}
|
||||
Reference in New Issue
Block a user