Compare commits

..
6 Commits
Author SHA1 Message Date
Tanner Linsley 0c3f2f2cd1 5.6.0 2017-04-20 16:44:31 -06:00
Tanner Linsley 03538823e9 Updated Docs 2017-04-20 16:44:24 -06:00
Aaron SchwartzandTanner Linsley bc7005db99 Enhanced expander and pivot (#215)
* Convert expander column to be more like a regular column.

* Update story.

* Simplify setting render on defaultExpander.

* Add more control over expander and pivot columns using the  column.

* Fix default filtering on pivot column.

* Add comments.
2017-04-20 16:41:50 -06:00
Tanner Linsley 42b5f5bb18 Convert to use es6 classes for react 15.5.x compat 2017-04-18 11:33:22 -06:00
Tanner Linsley 5ec616c2a3 Add CDN to docs 2017-04-18 09:48:38 -06:00
Tanner Linsley c16df80938 Added codepen example 2017-04-17 12:23:14 -06:00
20 changed files with 533 additions and 318 deletions
+2
View File
@@ -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
View File
@@ -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 -9
View File
@@ -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
View File
@@ -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
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.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":""}
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
View File
@@ -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
View File
@@ -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}
>&bull;</div>
<div className={classnames('rt-expander', isExpanded && '-open')}>
&bull;
</div>
)
},
PaginationComponent: Pagination,
+72 -124
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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>
)
}
})
}
+36 -22
View File
@@ -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>&#x2299;</span> : <span>&#x2295;</span>}
</div>
),
style: {cursor: 'pointer', fontSize: 25, padding: '0', textAlign: 'center', userSelect: 'none'},
footer: () => <span>&hearts;</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>&#x2299;</span> : <span>&#x2295;</span>}
</div>
),
style: {cursor: 'pointer', fontSize: 25, padding: '0', textAlign: 'center', userSelect: 'none'},
footer: () => <span>&hearts;</span>
}]
}]
return (
+183
View File
@@ -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 &#8674; Last Name Pivot</strong>,
expander: true,
minWidth: 200,
render: ({isExpanded, ...rest}) => (
isExpanded ? <span> &#10136; </span> : <span> &#10137; </span>
),
filterRender: ({key}) => <span key={key}> &#10609; </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 &#8674; Last Name Pivot</strong>,
expander: true,
minWidth: 200,
render: ({isExpanded, ...rest}) => (
isExpanded ? <span> &#10136; </span> : <span> &#10137; </span>
),
filterRender: ({key}) => <span key={key}> &#10609; </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>
)
`
}