Compare commits

...
71 Commits
Author SHA1 Message Date
Tanner Linsley 6d28bb2c4d 5.3.4 2017-03-01 15:50:43 -07:00
Tanner Linsley 9e95b331df Feature: Changing defaultSorting now updates the sorting model 2017-03-01 15:50:36 -07:00
TacticalCodingandTanner Linsley f296b075fe Rename CollapseOnPageChange to CollapseOnDataChange (#100)
* Rename CollapseOnPageChange to CollapseOnDataChange to more accurately reflect its purpose.

* Add support for collapseOnPageChange.

* Fix collapseOnPageChange efficiency.
2017-02-27 16:05:07 -07:00
Tanner Linsley a948a9a41e 5.3.3 2017-02-27 10:01:06 -07:00
atlantehandTanner Linsley 08dbe38ced fix number of callback parameters and alignment (#95) 2017-02-27 08:15:45 -07:00
Daniel WinterandTanner Linsley 884058b459 added missing named export for ReactTableDefaults (#93) 2017-02-19 07:09:29 -07:00
Tanner Linsley ee37ad7101 Update Docs 2017-02-16 15:15:47 -07:00
Tanner Linsley 6b384f2a90 5.3.2 2017-02-16 14:02:30 -07:00
Tanner Linsley 782e9efdfb Fix NoData from always showing 2017-02-16 14:02:21 -07:00
Tanner Linsley ff952de830 5.3.1 2017-02-16 12:40:48 -07:00
Tanner Linsley 149b11674b Docs Update 2017-02-16 12:40:43 -07:00
Tanner Linsley 8a362e4d04 Rollback on table partials to fix mounting/unmounting issues 2017-02-16 12:40:12 -07:00
Tanner Linsley 265a5c8753 5.3.0 2017-02-16 10:41:52 -07:00
Tanner Linsley 5155ebad72 Added more customization for functional rendering 2017-02-16 10:41:52 -07:00
Tanner Linsley d7a58450b7 Added support for Column Footers 2017-02-16 10:41:52 -07:00
avnunnandTanner Linsley bb2527e280 Added documentation for column accessors (#82) 2017-02-15 17:39:01 -07:00
Tanner Linsley 6d5207eb4e 5.2.0 2017-02-15 10:07:33 -07:00
Tanner Linsley 0d397e0c29 Update Docs
Fixes #80
2017-02-15 10:07:14 -07:00
Tanner Linsley b15f3ac3b0 Added "noData" component
Fixes #78
2017-02-15 09:55:42 -07:00
Tanner Linsley 48ea0df09d Normalize all JSX callbacks to support functions 2017-02-15 09:54:57 -07:00
Tanner Linsley 403fb7a708 5.1.1 2017-02-13 15:54:59 -07:00
Tanner Linsley ecd5658e4b Better resolve server-side data pages and pagesize 2017-02-13 15:54:47 -07:00
Tanner Linsley 3852227bdd Fix custom cell render to allow pure functions 2017-02-13 15:54:25 -07:00
Tanner Linsley 1fec9b882f 5.1.0 2017-02-10 16:51:47 -07:00
Tanner Linsley 46c4c6fdb2 Doc Updates 2017-02-10 16:46:54 -07:00
Tanner Linsley e702fc80ca defaultSorting changes and doc updates 2017-02-10 16:46:14 -07:00
Tanner Linsley beaa748187 5.0.4 2017-02-10 14:49:04 -07:00
Tanner Linsley cce77d24f2 Retain original data order if no sorting is found 2017-02-10 14:48:55 -07:00
Tanner Linsley 3984a540c1 5.0.3 2017-02-09 10:07:42 -07:00
Tanner Linsley 726fd52753 Adjust current page if available pages dips below current page
Fixes #69
2017-02-09 10:07:42 -07:00
Tanner LinsleyandGitHub 6a6d373526 Update README.md 2017-02-08 08:20:30 -07:00
TacticalCodingandTanner Linsley e11fdab457 Fix 'iterator must have unique key' warning on pivoting tables. (#56) (#66) 2017-02-07 10:31:40 -07:00
Jan ZandTanner Linsley 1e4f838326 'collapseOnChange' and 'freezeWhenExpanded' (#61)
* rough draft of "closeSubComponentOnDataChange" and "preventAutoSortWhenComponentIsOpen"

* changed flag name from ...component to ...subcomponent

* fixed problem with sorting not immediately being applied. passes tests now

* changed var names

* Cleanup and simplification

* Fix deps

* Better freezing strategy

* subcomponent reverse
2017-02-06 15:09:35 -07:00
Tanner Linsley aa48ef57ee 5.0.2 2017-02-03 14:05:32 -07:00
Tanner Linsley 22f79fcd28 Added instance to all custom props callbacks 2017-02-03 14:05:25 -07:00
Tanner Linsley ff8e24760a 5.0.1 2017-02-03 11:07:51 -07:00
Tanner Linsley f1511bd27e Bug fixes and Doc Updates 2017-02-03 11:07:48 -07:00
Tanner Linsley 4733997c26 Updated Docs 2017-02-02 18:17:37 -07:00
Tanner Linsley c3a6e236ae 5.0.0 2017-02-02 18:13:48 -07:00
Tanner Linsley 83200d4e4c Rewrite of dynamic props and stable sorting algorithm 2017-02-02 18:13:40 -07:00
Tanner Linsley 5e16c2cb24 4.4.1 2017-01-27 14:34:59 -07:00
Tanner Linsley 66cee186a3 pivotBy prop now defaults to undefined 2017-01-27 14:34:50 -07:00
Tanner Linsley 55bbf4bf37 Updated Docs 2017-01-27 14:20:51 -07:00
Tanner Linsley 10ce93344c Updated Docs 2017-01-27 14:17:33 -07:00
Tanner Linsley 114621a359 4.4.0 2017-01-27 14:10:57 -07:00
Tanner Linsley 8de0fa420b Better default sorting, column.width support, expander column position 2017-01-27 14:10:47 -07:00
Tanner Linsley aa77193810 Update Docs 2017-01-26 21:26:58 -07:00
Tanner Linsley 92c33de7ac 4.3.0 2017-01-26 21:25:04 -07:00
Tanner Linsley c3fb084550 Feature: Functional Rendering 2017-01-26 21:22:21 -07:00
Tanner Linsley 04c71f17a8 4.2.8 2017-01-26 15:26:38 -07:00
Tanner Linsley 34fa57c4d3 Updated to latest autoprefixer 2017-01-26 15:26:38 -07:00
George LimaandTanner Linsley de1c8a6156 Update README.md (#38)
Bug fix in installation docs
2017-01-23 12:22:11 -07:00
Tanner Linsley ab9d67d2d9 Update Docs 2017-01-23 10:18:30 -07:00
Tanner Linsley dc0713c1d1 4.2.7 2017-01-23 10:16:59 -07:00
Tanner Linsley c1004ee9e9 column.maxWidth support and fixed css autoprefixer warnings
Fixes #34
2017-01-23 10:16:34 -07:00
Tanner Linsley c0098ebc2c 4.2.6 2017-01-22 10:27:29 -07:00
Tanner Linsley 33645b4fea Styling fixes and documentation 2017-01-22 10:26:49 -07:00
Tanner Linsley 3d325dad8d Fix CNAME being overwritten by storybook export 2017-01-20 11:04:53 -07:00
Tanner Linsley f3ee89a514 Doc Update 2017-01-20 10:58:36 -07:00
Tanner Linsley 90001c1b3a Slack and Contributing Updates 2017-01-20 10:18:34 -07:00
Tanner Linsley 8d7b9c2feb Create CNAME 2017-01-19 19:39:11 -07:00
Tanner Linsley f754eb0bd5 4.2.5 2017-01-19 19:38:34 -07:00
Tanner Linsley 66f1b04ba6 Fix utils.groupBy where watch key would cause error in Firefox 2017-01-19 19:37:32 -07:00
Tanner Linsley bea4b366d6 No cname needed 2017-01-18 21:27:15 -07:00
Tanner Linsley 64168eb3ef Updates demo site 2017-01-18 21:22:21 -07:00
Tanner Linsley 77be7c066f Create CNAME 2017-01-18 21:17:11 -07:00
Tanner Linsley e9e69428a2 Updated Docs 2017-01-18 10:22:59 -07:00
Tanner Linsley 3c039789f1 Updated Docs 2017-01-18 10:22:47 -07:00
Tanner Linsley 5865f59129 New Stories 2017-01-18 10:01:34 -07:00
Tanner Linsley c663cce719 Create CNAME 2017-01-18 09:16:35 -07:00
Tanner Linsley a6f803c1a3 Updated Storybook 2017-01-18 09:09:59 -07:00
42 changed files with 3824 additions and 1930 deletions
Vendored
BIN
View File
Binary file not shown.
+1 -3
View File
@@ -3,6 +3,4 @@ lib/
react-table.js
react-table.css
*.log
example/dist/
storybook-static
.idea
View File
+17 -1
View File
@@ -11,11 +11,19 @@ import '../react-table.css'
import Readme from '../README.md'
//
import Simple from '../stories/Simple.js'
import CellRenderers from '../stories/CellRenderers.js'
import DefaultSorting from '../stories/DefaultSorting.js'
import CustomWidths from '../stories/CustomWidths.js'
import CustomComponentProps from '../stories/CustomComponentProps.js'
import ServerSide from '../stories/ServerSide.js'
import SubComponents from '../stories/SubComponents.js'
import Pivoting from '../stories/Pivoting.js'
import PivotingSubComponents from '../stories/PivotingSubComponents.js'
import OneHundredKRows from '../stories/OneHundredKRows.js'
import FunctionalRendering from '../stories/FunctionalRendering.js'
import CustomExpanderPosition from '../stories/CustomExpanderPosition.js'
import NoDataText from '../stories/NoDataText.js'
import Footers from '../stories/Footers.js'
//
configure(() => {
storiesOf('1. Docs')
@@ -31,10 +39,18 @@ configure(() => {
return <ReadmeCmp />
})
storiesOf('2. Demos')
.add('Client-side Data', Simple)
.add('Simple Table', Simple)
.add('Cell Renderers & Custom Components', CellRenderers)
.add('Default Sorting', DefaultSorting)
.add('Custom Column Widths', CustomWidths)
.add('Custom Component Props', CustomComponentProps)
.add('Server-side Data', ServerSide)
.add('Sub Components', SubComponents)
.add('Pivoting & Aggregation', Pivoting)
.add('Pivoting & Aggregation w/ Sub Components', PivotingSubComponents)
.add('100k Rows w/ Pivoting & Sub Components', OneHundredKRows)
.add('Functional Rendering', FunctionalRendering)
.add('Custom Expander Position', CustomExpanderPosition)
.add('Custom "No Data" Text', NoDataText)
.add('Footers', Footers)
}, module)
+7
View File
@@ -4,3 +4,10 @@ body {
font-family: 'Open Sans', sans-serif;
font-weight: 300;
}
h1 {
font-size: 24px;
font-weight: bold;
margin-bottom: 15px;
margin-top: 5px;
}
+4
View File
@@ -1,3 +1,7 @@
body{
padding: 20px;
}
strong {
font-weight: bold
}
+373 -81
View File
@@ -15,8 +15,8 @@
<a href="https://npmjs.com/package/react-table" target="\_parent">
<img alt="" src="https://img.shields.io/npm/dm/react-table.svg" />
</a>
<a href="https://react-table-slack.herokuapp.com/" target="\_parent">
<img alt="" src="https://img.shields.io/badge/slack-react--table-blue.svg" />
<a href="https://react-chat-signup.herokuapp.com/" target="\_parent">
<img alt="" src="https://img.shields.io/badge/slack-react--chat-blue.svg" />
</a>
<a href="https://github.com/tannerlinsley/react-table" target="\_parent">
<img alt="" src="https://img.shields.io/github/stars/tannerlinsley/react-table.svg?style=social&label=Star" />
@@ -24,6 +24,9 @@
<a href="https://twitter.com/tannerlinsley" target="\_parent">
<img alt="" src="https://img.shields.io/twitter/follow/tannerlinsley.svg?style=social&label=Follow" />
</a>
<a href="https://cash.me/$tannerlinsley" target="\_parent">
<img alt="" src="https://img.shields.io/badge/%24-Donate-brightgreen.svg" />
</a>
## Features
@@ -35,7 +38,7 @@
- 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.zabapps.com/?selectedKind=2.%20Demos&selectedStory=Client-side%20Data&full=0&down=1&left=1&panelRight=0&downPanel=kadirahq%2Fstorybook-addon-actions%2Factions-panel" target="\_parent">Demo</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">Demo</a>
## Table of Contents
- [Installation](#installation)
@@ -43,19 +46,44 @@
- [Data](#data)
- [Props](#props)
- [Columns](#columns)
- [Column Header Groups](#column-header-groups)
- [Custom Cell and Header Rendering](#custom-cell-and-header-rendering)
- [Styles](#styles)
- [Header Groups](#header-groups)
- [Pivoting & Aggregation](#pivoting--aggregation)
- [Sub Tables & Sub Components](#sub-tables--sub-components)
- [Custom Props](#custom-props)
- [Pivoting and Aggregation](#pivoting-and-aggregation)
- [Sub Tables and Sub Components](#sub-tables-and-sub-components)
- [Server-side Data](#server-side-data)
- [Fully Controlled Component](#fully-controlled-component)
- [Multi-sort](#multi-sort)
- [Functional Rendering](#functional-rendering)
- [Multi-Sort](#multi-sort)
- [Component Overrides](#component-overrides)
- [Contributing](#contributing)
- [Scripts](#scripts)
- [Used By](#used-by)
## Installation
1. Install React Table as a dependency
```bash
$ npm install react-table
# or
$ yarn add react-table
```
2. Import the `react-table` module
```javascript
// ES6
import ReactTable from 'react-table'
// ES5
var ReactTable = require('react-table').default
```
3. Import styles by including `react-table.css` anywhere on the page
```javascript
// JS (Webpack)
import 'react-table/react-table.css'
// html
<link rel="stylesheet" href="node_modules/react-table/react-table.css">
```
## Example
```javascript
@@ -74,11 +102,11 @@ const data = [{
const columns = [{
header: 'Name',
accessor: 'name' // String-based value accessors !
accessor: 'name' // String-based value accessors!
}, {
header: 'Age',
accessor: 'age',
render: props => <span className='number'>props.value</span> // Custom cell components!
render: props => <span className='number'>{props.value}</span> // Custom cell components!
}, {
header: 'Friend Name',
accessor: d => d.friend.name // Custom value accessors!
@@ -102,55 +130,102 @@ These are all of the available props (and their default values) for the main `<R
```javascript
{
// General
loading: false, // Whether to show the loading overlay or not
defaultPageSize: 20, // The default page size (this can be changed by the user if `showPageSizeOptions` is enabled)
minRows: 0, // Ensure this many rows are always rendered, regardless of rows on page
showPagination: true, // Shows or hides the pagination component
showPageJump: true, // Shows or hides the pagination number input
showPageSizeOptions: true, // Enables the user to change the page size
pageSizeOptions: [5, 10, 20, 25, 50, 100], // The available page size options
expanderColumnWidth: 30, // default columnWidth for the expander column
data: [],
loading: false,
showPagination: true,
showPageSizeOptions: true,
pageSizeOptions: [5, 10, 20, 25, 50, 100],
defaultPageSize: 20,
showPageJump: true,
expanderColumnWidth: 35,
collapseOnSortingChange: true,
collapseOnPageChange: true,
collapseOnDataChange: true,
freezeWhenExpanded: false,
defaultSorting: [],
// Callbacks
onChange: (state, instance) => null, // Anytime the internal state of the table changes, this will fire
onTrClick: (row, event) => null, // Handler for row click events
// Controlled State Overrides (see Fully Controlled Component section)
page: undefined,
pageSize: undefined,
sorting: undefined
// Controlled State Callbacks
onExpandSubComponent: undefined,
onPageChange: undefined,
onPageSizeChange: undefined,
onSortingChange: undefined,
// Pivoting
pivotBy: undefined,
pivotColumnWidth: 200,
pivotValKey: '_pivotVal',
pivotIDKey: '_pivotID',
subRowsKey: '_subRows',
// Pivoting State Overrides (see Fully Controlled Component section)
expandedRows: {},
// Pivoting State Callbacks
onExpandRow: undefined,
// General Callbacks
onChange: () => null,
// Classes
className: '',
style: {},
// Component decorators
getProps: () => ({}),
getTableProps: () => ({}),
getTheadGroupProps: () => ({}),
getTheadGroupTrProps: () => ({}),
getTheadGroupThProps: () => ({}),
getTheadProps: () => ({}),
getTheadTrProps: () => ({}),
getTheadThProps: () => ({}),
getTbodyProps: () => ({}),
getTrGroupProps: () => ({}),
getTrProps: () => ({}),
getThProps: () => ({}),
getTdProps: () => ({}),
getTfootProps: () => ({}),
getTfootTrProps: () => ({}),
getTfootThProps: () => ({}),
getPaginationProps: () => ({}),
getLoadingProps: () => ({}),
getNoDataProps: () => ({}),
// Global Column Defaults
column: {
sortable: true,
show: true,
minWidth: 100,
// Cells only
render: undefined,
className: '',
style: {},
getProps: () => ({}),
// Headers only
header: undefined,
headerClassName: '',
headerStyle: {},
getHeaderProps: () => ({})
// Footers only
footer: undefined,
footerClassName: '',
footerStyle: {},
getFooterProps: () => ({})
},
// Text
previousText: 'Previous',
nextText: 'Next',
loadingText: 'Loading...',
noDataText: 'No rows found',
pageText: 'Page',
ofText: 'of',
rowsText: 'rows',
// Classes
className: '-striped -highlight', // The most top level className for the component
tableClassName: '', // ClassName for the `table` element
theadClassName: '', // ClassName for the `thead` element
tbodyClassName: '', // ClassName for the `tbody` element
trClassName: '', // ClassName for all `tr` elements
trClassCallback: row => null, // A call back to dynamically add classes (via the classnames module) to a row element
paginationClassName: '' // ClassName for `pagination` element
// Styles
style: {}, // Main style object for the component
tableStyle: {}, // style object for the `table` component
theadStyle: {}, // style object for the `thead` component
tbodyStyle: {}, // style object for the `tbody` component
trStyle: {}, // style object for the `tr` component
trStyleCallback: row => {}, // A call back to dynamically add styles to a row element
thStyle: {}, // style object for the `th` component
tdStyle: {}, // style object for the `td` component
paginationStyle: {}, // style object for the `paginination` component
// Controlled Props (see Using as a Fully Controlled Component below)
page: undefined,
pageSize: undefined,
sorting: undefined,
expandedRows: undefined,
// Controlled Callbacks
onExpandRow: undefined,
onPageChange: undefined,
onPageSizeChange: undefined,
}
```
@@ -166,7 +241,7 @@ Object.assign(ReactTableDefaults, {
})
```
Or just define them on the component per-instance
Or just define them as props
```javascript
<ReactTable
@@ -182,17 +257,22 @@ Or just define them on the component per-instance
```javascript
[{
// General
accessor: 'propertyName' or Accessor eg. (row) => row.propertyName,
accessor: 'propertyName' // or Accessor eg. (row) => row.propertyName (see "Accessors" section for more details)
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,
sort: 'asc' or 'desc', // used to determine the column sorting on init
show: true, // can be used to hide a column
minWidth: 100 // A minimum width for this column. If there is room, columns will flex to fill available space
width: undefined, // A hardcoded width for the column. This overrides both min and max width options
minWidth: 100 // A minimum width for this column. If there is extra room, column will flex to fill available space (up to the max-width, if set)
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
// Cell Options
className: '', // Set the classname of the `td` element of the column
style: {}, // Set the style of the `td` element of the column
render: JSX eg. ({value, rowValues, row, index, viewIndex}) => <span>{value}</span>, // Provide a JSX element or stateless function to render whatever you want as the column's cell with access to the entire row
render: JSX eg. (rowInfo: {value, rowValues, row, index, viewIndex}) => <span>{value}</span>, // Provide a JSX element or stateless function to render whatever you want as the column's cell with access to the entire row
// value == the accessed value of the column
// rowValues == an object of all of the accessed values for the row
// row == the original row of data supplied to the table
@@ -200,24 +280,51 @@ Or just define them on the component per-instance
// viewIndex == the index of the row in the current page
// Header & HeaderGroup Options
header: 'Header Name' or JSX eg. ({data, column}) => <div>Header Name</div>,
header: 'Header Name', a function that returns a primitive, or JSX / React Component eg. ({data, column}) => <div>Header Name</div>,
headerClassName: '', // Set the classname of the `th` element of the column
headerStyle: {}, // Set the style of the `th` element of the column
getHeaderProps: (state, rowInfo, column, instance) => ({}) // a function that returns props to decorate the `th` element of the column
// Header Groups only
columns: [...] // See Header Groups section below
// Footer
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
}]
```
## Styles
React-table is built to be dropped into existing applications or styled from the ground up, but if you'd like a decent starting point, you can optionally include our default theme `react-table.css`. We think it looks great, honestly :)
## 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.
## Header Groups
To group columns with another header column, just nest your columns in a header column like so:
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
const columns = [{
header: 'Favorites',
headerClassName: 'my-favorites-column-header-group'
columns: [{
header: 'Color',
accessor: 'favorites.color'
@@ -231,7 +338,151 @@ const columns = [{
}]
```
## Pivoting & Aggregation
## Custom Cell, Header and Footer Rendering
You can use any react component or JSX to display content in column headers, cells and footers. Any component you use will be passed the following props (if available):
- `row` - Original row from your data
- `rowValues` - The post-accessed values from the original row
- `index` - The index of the row
- `viewIndex` - the index of the row relative to the current page
- `level` - The nesting depth (zero-indexed)
- `nestingPath` - The nesting path of the row
- `aggregated` - A boolean stating if the row is an aggregation row
- `subRows` - An array of any expandable sub-rows contained in this row
```javascript
// This column uses a stateless component to produce a different colored bar depending on the value
// You can also use stateful components or any other function that returns JSX
const columns = [{
header: () => <span><i className='fa-tasks' /> Progress</span>,
accessor: 'progress',
render: row => (
<div
style={{
width: '100%',
height: '100%',
backgroundColor: '#dadada',
borderRadius: '2px'
}}
>
<div
style={{
width: `${row.value}%`,
height: '100%',
backgroundColor: row.value > 66 ? '#85cc00'
: row.value > 33 ? '#ffbf00'
: '#ff2e00',
borderRadius: '2px',
transition: 'all .2s ease-out'
}}
/>
</div>
)
}]
```
## Styles
- React-table ships with a minimal and clean stylesheet to get you on your feet quickly.
- The stylesheet is located at `react-table/react-table.css`.
- There are countless ways to import a stylesheet. If you have questions on how to do so, consult the documentation of your build system.
#### Classes
- Adding a `-striped` className to ReactTable will slightly color odd numbered rows for legibility
- Adding a `-highlight` className to ReactTable will highlight any row as you hover over it
#### CSS
We think the default styles looks great! But, if you prefer a more custom look, all of the included styles are easily overridable. Every single component contains a unique class that makes it super easy to customize. Just go for it!
#### JS Styles
Every single react-table element and `get[ComponentName]Props` callback supports `classname` and `style` props.
## Custom Props
#### Built-in Components
Every single built-in component's props can be dynamically extended using any one of these prop-callbacks:
```javascript
<ReactTable
getProps={fn}
getTableProps={fn}
getTheadGroupProps={fn}
getTheadGroupTrProps={fn}
getTheadGroupThProps={fn}
getTheadProps={fn}
getTheadTrProps={fn}
getTheadThProps={fn}
getTbodyProps={fn}
getTrGroupProps={fn}
getTrProps={fn}
getThProps={fn}
getTdProps={fn}
getPaginationProps={fn}
getLoadingProps={fn}
/>
```
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
This makes it extremely easy to add, say... a row click callback!
```javascript
// When any Td element is clicked, we'll log out some information
<ReactTable
getTdProps={(state, rowInfo, column, instance) => {
return {
onClick: e => {
console.log('A Td Element was clicked!')
console.log('it produced this event:', e)
console.log('It was in this column:', column)
console.log('It was in this row:', rowInfo)
console.log('It was in this table instance:', instance)
}
}
}}
/>
```
You can use these callbacks for dynamic styling as well!
```javascript
// Any Tr element will be green if its (row.age > 20)
<ReactTable
getTrProps={(state, rowInfo, column) => {
return {
style: {
background: rowInfo.age > 20 ? 'green' : 'red'
}
}
}}
/>
```
#### Column Components
Just as core components can have dynamic props, columns and column headers can too!
You can utilize either of these prop callbacks on columns:
```javascript
const columns = [{
getHeaderProps: () => (...),
getProps: () => (...)
}]
```
In a similar fashion these can be used to dynamically style just about anything!
```javascript
// This columns cells will be red if (row.name === Santa Clause)
const columns = [{
getProps: (state, rowInfo, column) => {
return {
style: {
background: rowInfo.name === 'Santa Clause' ? 'red' : null
}
}
}
}]
```
## Pivoting and Aggregation
Pivoting the table will group records together based on their accessed values and allow the rows in that group to be expanded underneath it.
To pivot, pass an array of `columnID`'s to `pivotBy`. Remember, a column's `id` is either the one that you assign it (when using a custom accessors) or its `accessor` string.
```javascript
@@ -261,7 +512,7 @@ const columns = [{
Pivoted columns can be sorted just like regular columns, but not independently of each other. For instance, if you click to sort the pivot column in ascending order, it will sort by each pivot recursively in ascending order together.
## Sub Tables & Sub Components
## Sub Tables and Sub Components
By adding a `SubComponent` props, you can easily add an expansion level to all root-level rows:
```javascript
<ReactTable
@@ -352,6 +603,43 @@ Here are the props and their corresponding callbacks that control the state of t
/>
```
## Functional Rendering
Possibly one of the coolest features of React-Table is its ability to expose internal components and state for custom render logic. The easiest way to do this is to pass a function as the child of `<ReactTable />`.
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 instance of the component
You can then return any JSX or react you want! This turns out to be perfect for:
- 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
Accessing internal state and wrapping with more UI:
```javascript
<ReactTable
data={data}
columns={columns}
>
{(state, makeTable, instance) => {
return (
<div style={{
background: '#ffcf00',
borderRadius: '5px',
overflow: 'hidden',
padding: '5px'
}}>
<pre><code>state.allVisibleColumns === {JSON.stringify(state.allVisibleColumns, null, 4)}</code></pre>
{makeTable()}
</div>
)
}}
</ReactTable>
```
The possibilities are endless!
## Multi-Sort
When clicking on a column header, hold shift to multi-sort! You can toggle `ascending` `descending` and `none` for multi-sort columns. Clicking on a header without holding shift will clear the multi-sort and replace it with the single sort of that column. It's quite handy!
@@ -361,18 +649,20 @@ 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,
PaginationComponent: Component,
PreviousComponent: Component,
NextComponent: Component,
LoadingComponent: Component,
ExpanderComponent: Component
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,
})
// Or change per instance
@@ -391,17 +681,19 @@ To suggest a feature, create an issue if it does not already exist.
If you would like to help develop a suggested feature follow these steps:
- Fork this repo
- `npm install`
- `npm run watch`
- `$ yarn`
- `$ yarn run storybook`
- Implement your changes to files in the `src/` directory
- View changes as you code via our <a href="https://github.com/storybooks/react-storybook" target="\_parent">React Storybook</a> `localhost:8000`
- Make changes to stories in `/stories`, or create a new one if needed
- Submit PR for review
If you would like to preview your changes as you develop, you can link and utilize our <a href="https://github.com/storybooks/react-storybook" target="\_parent">React Storybook</a> like so:
#### Scripts
- `npm install`
- `run storybook` (or run them in separate tabs)
- Make changes to stories in `/stories`, or create a new one if needed
- View changes at `localhost:8000`
- `$ yarn run storybook` Runs the storybook server
- `$ yarn run test` Runs the test suite
- `$ yarn run prepublish` Builds the distributable bundle
- `$ yarn run docs` Builds the website/docs from the storybook for github pages
## Used By
+1
View File
@@ -0,0 +1 @@
react-table.js.org
+1 -1
View File
@@ -16,7 +16,7 @@
<body>
<div id="root"></div>
<div id="error-display"></div>
<script src="static/preview.30adfa2464622c0f1904.bundle.js"></script>
<script src="static/preview.742092f25ec9b6802477.bundle.js"></script>
</body>
</html>
+2 -2
View File
@@ -4,7 +4,7 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="storybook-version" content="2.35.2">
<meta name="storybook-version" content="2.35.3">
<title>React Storybook</title>
<style>
/*
@@ -38,7 +38,7 @@
</head>
<body style="margin: 0;">
<div id="root"></div>
<script src="static/manager.32cbfa2b6d56d1f8fbac.bundle.js"></script>
<script src="static/manager.1e44a83b81ae02b691ef.bundle.js"></script>
</body>
</html>
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
{"version":3,"file":"static/manager.1e44a83b81ae02b691ef.bundle.js","sources":["webpack:///static/manager.1e44a83b81ae02b691ef.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;AAqxDA;AAsrDA;AA2yDA;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/manager.32cbfa2b6d56d1f8fbac.bundle.js","sources":["webpack:///static/manager.32cbfa2b6d56d1f8fbac.bundle.js"],"mappings":"AAAA;AA4zDA;AAg4DA;AAwgEA;AAqiEA;AAk0EA;AA67CA;AA0qDA;AAy4DA;AA8lDA;AA4hDA;AA62DA;AA+/DA;AA6mDA;AAsyCA;AA2gDA;AA+2DA;AA+jEA;AAixDA;AA6lDA;AA+nDA;AA0qEA;AAinDA;AAs3DA;AA80GA;AAhvCA;AAuqGA;AAuqEA;AA6wEA;AAleA;AA+gEA;AA+mCA","sourceRoot":""}
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
{"version":3,"file":"static/preview.30adfa2464622c0f1904.bundle.js","sources":["webpack:///static/preview.30adfa2464622c0f1904.bundle.js"],"mappings":"AAAA;AAwxDA;AA45DA;AAo9DA;AA24DA;AAg3CA;AAkoIA;AAgwGA;AA+sPA;AAk6CA;AAq4DA;AA4gDA;AAmpDA;AA05DA;AAkoDA;AAu+CA;AA0rDA;AAiqEA;AAyoDA;AA8xCA;AAmnDA;AAqzDA;AAqhEA;AAqwDA;AAk7DA;AAw1CA;AAisFA;AAw3GA;AAo/CA;AAikCA;AA29BA;AA+vBA;AAy1CA","sourceRoot":""}
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
{"version":3,"file":"static/preview.742092f25ec9b6802477.bundle.js","sources":["webpack:///static/preview.742092f25ec9b6802477.bundle.js"],"mappings":"AAAA;AAkuDA;AAo8CA;AA8uGA;AA++EA;AAi9NA;AAo5GA;AAmvDA;AAmgEA;AA4xDA;AAigEA;AAmjDA;AA4sDA;AAk8CA;AAu/DA;AA8lDA;AA09CA;AAqoDA;AAywEA;AAokDA;AAsvCA;AA2mDA;AA4tDA;AAqjEA;AAs2DA;AAmyDA;AAsnDA;AAk1EA;AAmjGA;AAiuDA;AA+2CA;AAq5BA;AA4zDA;AA26BA;AAuOA;AAw5EA","sourceRoot":""}
+8 -4
View File
@@ -1,6 +1,6 @@
{
"name": "react-table",
"version": "4.2.4",
"version": "5.3.4",
"description": "A fast, lightweight, opinionated table and datagrid built on React",
"license": "MIT",
"homepage": "https://github.com/tannerlinsley/react-table#readme",
@@ -24,7 +24,8 @@
],
"scripts": {
"build:node": "babel src --out-dir lib --source-maps inline",
"build:css": "rm -rf react-table.css && stylus src/index.styl --use ./node_modules/nib/lib/nib.js --compress -o react-table.css",
"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",
@@ -32,7 +33,7 @@
"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"
"docs": "build-storybook -o docs && cp .storybook/CNAME docs/CNAME"
},
"dependencies": {
"classnames": "^2.2.5"
@@ -42,6 +43,7 @@
},
"devDependencies": {
"@kadira/storybook": "^2.35.1",
"autoprefixer": "^6.7.0",
"babel-cli": "6.14.0",
"babel-eslint": "6.1.2",
"babel-preset-es2015": "6.14.0",
@@ -53,12 +55,14 @@
"html-loader": "^0.4.4",
"markdown-loader": "^0.1.7",
"namor": "^0.3.0",
"nib": "^1.1.2",
"npm-run-all": "^3.1.1",
"onchange": "^3.0.2",
"postcss-cli": "^2.6.0",
"react": "^15.4.2",
"react-dom": "^15.4.2",
"react-json-tree": "^0.10.1",
"standard": "^8.0.0",
"storybook": "^0.0.0",
"stylus": "^0.54.5",
"uglifyify": "3.0.3"
},
Binary file not shown.
Binary file not shown.
+153
View File
@@ -0,0 +1,153 @@
import React from 'react'
import classnames from 'classnames'
//
import _ from './utils'
import Pagination from './pagination'
const emptyObj = () => ({})
export default {
// General
data: [],
loading: false,
showPagination: true,
showPageSizeOptions: true,
pageSizeOptions: [5, 10, 20, 25, 50, 100],
defaultPageSize: 20,
showPageJump: true,
expanderColumnWidth: 35,
collapseOnSortingChange: true,
collapseOnPageChange: true,
collapseOnDataChange: true,
freezeWhenExpanded: false,
defaultSorting: [],
// Controlled State Overrides
// page: undefined,
// pageSize: undefined,
// sorting: undefined,
// Controlled State Callbacks
onExpandSubComponent: undefined,
onPageChange: undefined,
onPageSizeChange: undefined,
onSortingChange: undefined,
// Pivoting
pivotBy: undefined,
pivotColumnWidth: 200,
pivotValKey: '_pivotVal',
pivotIDKey: '_pivotID',
subRowsKey: '_subRows',
// Pivoting State Overrides
// expandedRows: {},
// Pivoting State Callbacks
onExpandRow: undefined,
// General Callbacks
onChange: () => null,
// Classes
className: '',
style: {},
// Component decorators
getProps: emptyObj,
getTableProps: emptyObj,
getTheadGroupProps: emptyObj,
getTheadGroupTrProps: emptyObj,
getTheadGroupThProps: emptyObj,
getTheadProps: emptyObj,
getTheadTrProps: emptyObj,
getTheadThProps: emptyObj,
getTbodyProps: emptyObj,
getTrGroupProps: emptyObj,
getTrProps: emptyObj,
getTdProps: emptyObj,
getTfootProps: emptyObj,
getTfootTrProps: emptyObj,
getTfootTdProps: emptyObj,
getPaginationProps: emptyObj,
getLoadingProps: emptyObj,
getNoDataProps: emptyObj,
// Global Column Defaults
column: {
sortable: true,
show: true,
minWidth: 100,
// Cells only
render: undefined,
className: '',
style: {},
getProps: emptyObj,
// Headers only
header: undefined,
headerClassName: '',
headerStyle: {},
getHeaderProps: emptyObj,
// Footers only
footer: undefined,
footerClassName: '',
footerStyle: {},
getFooterProps: emptyObj
},
// Text
previousText: 'Previous',
nextText: 'Next',
loadingText: 'Loading...',
noDataText: 'No rows found',
pageText: 'Page',
ofText: 'of',
rowsText: 'rows',
// Components
TableComponent: _.makeTemplateComponent('rt-table'),
TheadComponent: _.makeTemplateComponent('rt-thead'),
TbodyComponent: _.makeTemplateComponent('rt-tbody'),
TrGroupComponent: _.makeTemplateComponent('rt-tr-group'),
TrComponent: _.makeTemplateComponent('rt-tr'),
ThComponent: ({toggleSort, className, children, ...rest}) => {
return (
<div
className={classnames(className, 'rt-th')}
onClick={e => {
toggleSort && toggleSort(e)
}}
{...rest}
>
{children}
</div>
)
},
TdComponent: _.makeTemplateComponent('rt-td'),
TfootComponent: _.makeTemplateComponent('rt-tfoot'),
ExpanderComponent: ({isExpanded, ...rest}) => {
return (
<div
className={classnames('rt-expander', isExpanded && '-open')}
{...rest}
>&bull;</div>
)
},
PaginationComponent: Pagination,
PreviousComponent: undefined,
NextComponent: undefined,
LoadingComponent: ({className, loading, loadingText, ...rest}) => (
<div className={classnames(
'-loading',
{'-active': loading},
className
)}
{...rest}
>
<div className='-loading-inner'>
{loadingText}
</div>
</div>
),
NoDataComponent: _.makeTemplateComponent('rt-noData')
}
+580 -790
View File
File diff suppressed because it is too large Load Diff
+22 -3
View File
@@ -1,5 +1,3 @@
@import 'nib'
$easeOutQuad = cubic-bezier(0.250, 0.460, 0.450, 0.940)
$easeOutBack = cubic-bezier(0.175, 0.885, 0.320, 1.275)
$expandSize = 7px
@@ -32,7 +30,6 @@ $expandSize = 7px
.rt-th
.rt-td
color: black
border-right: 1px solid alpha(black, .05)
transition box-shadow .3s $easeOutBack
box-shadow:inset 0 0 0 0 transparent
@@ -102,6 +99,15 @@ $expandSize = 7px
cursor: pointer
&.-open:after
transform: translate(-50%, -50%) rotate(0deg)
.rt-tfoot
display: flex
flex-direction: column
box-shadow: 0 0px 15px 0px alpha(black, .15)
.rt-td
border-right:1px solid alpha(black, .05)
&:last-child
border-right:0
&.-striped
.rt-tr.-odd
@@ -119,6 +125,7 @@ $expandSize = 7px
flex-wrap: wrap
padding: 3px
box-shadow: 0 0px 15px 0px alpha(black, .1)
border-top: 2px solid alpha(black, .1)
.-btn
appearance:none
@@ -172,6 +179,18 @@ $expandSize = 7px
.-pageSizeOptions
margin: 3px 10px
.rt-noData
display:block
position:absolute
left:50%
top:50%
transform: translate(-50%, -50%)
background: alpha(white, .8)
transition: all .3s ease
z-index: 1
pointer-events: none
padding: 20px
color: alpha(black, .5)
.-loading
display:block
+100
View File
@@ -0,0 +1,100 @@
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: {}
}
},
getResolvedState (props, state) {
const resolvedState = {
..._.compactObject(this.state),
..._.compactObject(state),
..._.compactObject(this.props),
..._.compactObject(props)
}
return resolvedState
},
componentWillMount () {
this.setStateWithData(this.getDataModel(this.getResolvedState()))
},
componentDidMount () {
this.fireOnChange()
},
componentWillReceiveProps (nextProps, nextState) {
const oldState = this.getResolvedState()
const newState = this.getResolvedState(nextProps, nextState)
if (oldState.defaultSorting !== newState.defaultSorting) {
newState.sorting = newState.defaultSorting
}
// Props that trigger a data update
if (
oldState.data !== newState.data ||
oldState.columns !== newState.columns ||
oldState.pivotBy !== newState.pivotBy ||
oldState.sorting !== newState.sorting
) {
this.setStateWithData(this.getDataModel(newState))
}
},
setStateWithData (newState, cb) {
const oldState = this.getResolvedState()
const newResolvedState = this.getResolvedState({}, newState)
const { freezeWhenExpanded } = newResolvedState
// Default to unfrozen state
newResolvedState.frozen = false
// If freezeWhenExpanded is set, check for frozen conditions
if (freezeWhenExpanded) {
// if any rows are expanded, freeze the existing data and sorting
const keys = Object.keys(newResolvedState.expandedRows)
for (var i = 0; i < keys.length; i++) {
if (newResolvedState.expandedRows[keys[i]]) {
newResolvedState.frozen = true
break
}
}
}
// If the data isn't frozen and either the data or
// sorting model has changed, update the data
if (
(oldState.frozen && !newResolvedState.frozen) ||
oldState.sorting !== newResolvedState.sorting ||
(!newResolvedState.frozen && oldState.resolvedData !== newResolvedState.resolvedData)
) {
// Handle collapseOnSortingChange & collapseOnDataChange
if (
(oldState.sorting !== newResolvedState.sorting && this.props.collapseOnSortingChange) ||
(!newResolvedState.frozen && oldState.resolvedData !== newResolvedState.resolvedData && this.props.collapseOnDataChange)
) {
newResolvedState.expandedRows = {}
}
Object.assign(newResolvedState, this.getSortedData(newResolvedState))
}
// Calculate pageSize all the time
if (newResolvedState.resolvedData) {
newResolvedState.pages = newResolvedState.manual ? newResolvedState.pages : Math.ceil(newResolvedState.resolvedData.length / newResolvedState.pageSize)
}
return this.setState(newResolvedState, cb)
}
}
+402
View File
@@ -0,0 +1,402 @@
import _ from './utils'
export default {
getDataModel (newState) {
const {
columns,
pivotBy = [],
data,
pivotIDKey,
pivotValKey,
subRowsKey,
expanderColumnWidth,
SubComponent,
page,
pages,
pageSize
} = newState
// Determine Header Groups
let hasHeaderGroups = false
columns.forEach(column => {
if (column.columns) {
hasHeaderGroups = true
}
})
// Build Header Groups
const headerGroups = []
let currentSpan = []
// A convenience function to add a header and reset the currentSpan
const addHeader = (columns, column = columns[0]) => {
headerGroups.push({
...this.props.column,
...column,
columns: columns
})
currentSpan = []
}
const noSubExpanderColumns = columns.map(col => {
return {
...col,
columns: col.columns ? col.columns.filter(d => !d.expander) : undefined
}
})
let expanderColumnIndex = columns.findIndex(col => col.expander)
const needsExpander = (SubComponent || pivotBy.length) && expanderColumnIndex === -1
const columnsWithExpander = needsExpander ? [{expander: true}, ...noSubExpanderColumns] : noSubExpanderColumns
if (needsExpander) {
expanderColumnIndex = 0
}
const makeDecoratedColumn = (column) => {
const dcol = {
...this.props.column,
...column
}
if (dcol.expander) {
dcol.width = expanderColumnWidth
return dcol
}
if (typeof dcol.accessor === 'string') {
dcol.id = dcol.id || dcol.accessor
const accessorString = dcol.accessor
dcol.accessor = row => _.get(row, accessorString)
return dcol
}
if (dcol.accessor && !dcol.id) {
console.warn(dcol)
throw new Error('A column id is required if using a non-string accessor for column above.')
}
if (!dcol.accessor) {
dcol.accessor = d => undefined
}
// Ensure minWidth is not greater than maxWidth if set
if (dcol.maxWidth < dcol.minWidth) {
dcol.minWidth = dcol.maxWidth
}
return dcol
}
// Decorate the columns
const decorateAndAddToAll = (col) => {
const decoratedColumn = makeDecoratedColumn(col)
allDecoratedColumns.push(decoratedColumn)
return decoratedColumn
}
let allDecoratedColumns = []
const decoratedColumns = columnsWithExpander.map((column, i) => {
if (column.columns) {
return {
...column,
columns: column.columns.map(decorateAndAddToAll)
}
} else {
return decorateAndAddToAll(column)
}
})
// Build the visible columns, headers and flat column list
let visibleColumns = decoratedColumns.slice()
let allVisibleColumns = []
visibleColumns = visibleColumns.map((column, i) => {
if (column.columns) {
const visibleSubColumns = column.columns.filter(d => pivotBy.indexOf(d.id) > -1 ? false : _.getFirstDefined(d.show, true))
return {
...column,
columns: visibleSubColumns
}
}
return column
})
visibleColumns = visibleColumns.filter(column => {
return column.columns ? column.columns.length : pivotBy.indexOf(column.id) > -1 ? false : _.getFirstDefined(column.show, true)
})
// Move the pivot columns into a single column if needed
if (pivotBy.length) {
const pivotColumns = []
for (var i = 0; i < allDecoratedColumns.length; i++) {
if (pivotBy.indexOf(allDecoratedColumns[i].id) > -1) {
pivotColumns.push(allDecoratedColumns[i])
}
}
const pivotColumn = {
...pivotColumns[0],
pivotColumns,
expander: true
}
visibleColumns[expanderColumnIndex] = pivotColumn
}
// Build flast list of allVisibleColumns and HeaderGroups
visibleColumns.forEach((column, i) => {
if (column.columns) {
allVisibleColumns = allVisibleColumns.concat(column.columns)
if (currentSpan.length > 0) {
addHeader(currentSpan)
}
addHeader(column.columns, column)
return
}
allVisibleColumns.push(column)
currentSpan.push(column)
})
if (hasHeaderGroups && currentSpan.length > 0) {
addHeader(currentSpan)
}
// Access the data
let resolvedData = data.map((d, i) => {
const row = {
__original: d,
__index: i
}
allDecoratedColumns.forEach(column => {
if (column.expander) return
row[column.id] = column.accessor(d)
})
return row
})
// If pivoting, recursively group the data
const aggregate = (rows) => {
const aggregationValues = {}
aggregatingColumns.forEach(column => {
const values = rows.map(d => d[column.id])
aggregationValues[column.id] = column.aggregate(values, rows)
})
return aggregationValues
}
let standardColumns = pivotBy.length ? allVisibleColumns.slice(1) : allVisibleColumns
const aggregatingColumns = standardColumns.filter(d => d.aggregate)
let pivotColumn
if (pivotBy.length) {
pivotColumn = allVisibleColumns[0]
const groupRecursively = (rows, keys, i = 0) => {
// This is the last level, just return the rows
if (i === keys.length) {
return rows
}
// Group the rows together for this level
let groupedRows = Object.entries(
_.groupBy(rows, keys[i]))
.map(([key, value]) => {
return {
[pivotIDKey]: keys[i],
[pivotValKey]: key,
[keys[i]]: key,
[subRowsKey]: value
}
}
)
// Recurse into the subRows
groupedRows = groupedRows.map(rowGroup => {
let subRows = groupRecursively(rowGroup[subRowsKey], keys, i + 1)
return {
...rowGroup,
[subRowsKey]: subRows,
...aggregate(subRows)
}
})
return groupedRows
}
resolvedData = groupRecursively(resolvedData, pivotBy)
}
const newPages = _.getFirstDefined(pages, Math.ceil(resolvedData.length / pageSize))
const newPage = page > newPages ? newPage - 1 : page
return {
...newState,
resolvedData,
pivotColumn,
allVisibleColumns,
headerGroups,
allDecoratedColumns,
hasHeaderGroups,
page: Math.max(newPage, 0)
}
},
getSortedData (resolvedState) {
const {
manual,
sorting,
resolvedData
} = resolvedState
// Resolve the data from either manual data or sorted data
return {
sortedData: manual ? resolvedData : this.sortData(resolvedData, 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])
},
sortData (data, sorting) {
if (!sorting.length) {
return data
}
const sorted = _.orderBy(data, sorting.map(sort => {
return row => {
if (row[sort.id] === null || row[sort.id] === undefined) {
return -Infinity
}
return typeof row[sort.id] === 'string' ? row[sort.id].toLowerCase() : row[sort.id]
}
}), sorting.map(d => !d.desc))
return sorted.map(row => {
if (!row[this.props.subRowsKey]) {
return row
}
return {
...row,
[this.props.subRowsKey]: this.sortData(row[this.props.subRowsKey], sorting)
}
})
},
getMinRows () {
return _.getFirstDefined(this.props.minRows, this.getStateOrProp('pageSize'))
},
// User actions
onPageChange (page) {
const { onPageChange, collapseOnPageChange } = this.props
if (onPageChange) {
return onPageChange(page)
}
const newState = { page }
if (collapseOnPageChange) {
newState.expandedRows = {}
}
this.setStateWithData(
newState
, () => {
this.fireOnChange()
})
},
onPageSizeChange (newPageSize) {
const { onPageSizeChange } = this.props
const { pageSize, page } = this.getResolvedState()
// Normalize the page to display
const currentRow = pageSize * page
const newPage = Math.floor(currentRow / newPageSize)
if (onPageSizeChange) {
return onPageSizeChange(newPageSize, newPage)
}
this.setStateWithData({
pageSize: newPageSize,
page: newPage
}, () => {
this.fireOnChange()
})
},
sortColumn (column, additive) {
const { sorting } = this.getResolvedState()
const { onSortingChange } = this.props
if (onSortingChange) {
return onSortingChange(column, additive)
}
let newSorting = _.clone(sorting || []).map(d => {
d.desc = _.isSortingDesc(d)
return d
})
if (!_.isArray(column)) {
// Single-Sort
const existingIndex = newSorting.findIndex(d => d.id === column.id)
if (existingIndex > -1) {
const existing = newSorting[existingIndex]
if (existing.desc) {
if (additive) {
newSorting.splice(existingIndex, 1)
} else {
existing.desc = false
newSorting = [existing]
}
} else {
existing.desc = true
if (!additive) {
newSorting = [existing]
}
}
} else {
if (additive) {
newSorting.push({
id: column.id,
desc: false
})
} else {
newSorting = [{
id: column.id,
desc: false
}]
}
}
} else {
// Multi-Sort
const existingIndex = newSorting.findIndex(d => d.id === column[0].id)
// Existing Sorted Column
if (existingIndex > -1) {
const existing = newSorting[existingIndex]
if (existing.desc) {
if (additive) {
newSorting.splice(existingIndex, column.length)
} else {
column.forEach((d, i) => {
newSorting[existingIndex + i].desc = false
})
}
} else {
column.forEach((d, i) => {
newSorting[existingIndex + i].desc = true
})
}
if (!additive) {
newSorting = newSorting.slice(existingIndex, column.length)
}
} else {
// New Sort Column
if (additive) {
newSorting = newSorting.concat(column.map(d => ({
id: d.id,
desc: false
})))
} else {
newSorting = column.map(d => ({
id: d.id,
desc: false
}))
}
}
}
this.setStateWithData({
page: ((!sorting.length && newSorting.length) || !additive) ? 0 : this.state.page,
sorting: newSorting
}, () => {
this.fireOnChange()
})
}
}
+43 -10
View File
@@ -6,16 +6,19 @@ export default {
set,
takeRight,
last,
sortBy,
orderBy,
range,
remove,
clone,
getFirstDefined,
sum,
makeTemplateComponent,
prefixAll,
groupBy,
isArray
isArray,
splitProps,
compactObject,
isSortingDesc,
normalizeComponent
}
function get (obj, path, def) {
@@ -61,7 +64,7 @@ function range (n) {
return arr
}
function sortBy (arr, funcs, dirs) {
function orderBy (arr, funcs, dirs) {
return arr.sort((a, b) => {
for (let i = 0; i < funcs.length; i++) {
const comp = funcs[i]
@@ -75,7 +78,9 @@ function sortBy (arr, funcs, dirs) {
return desc ? 1 : -1
}
}
return 0
return dirs[0]
? a.__index - b.__index
: b.__index - b.__index
})
}
@@ -128,14 +133,10 @@ function makeTemplateComponent (compClass) {
)
}
function prefixAll (obj) {
return obj
}
function groupBy (xs, key) {
return xs.reduce((rv, x, i) => {
const resKey = typeof key === 'function' ? key(x, i) : x[key]
rv[resKey] = rv[resKey] || []
rv[resKey] = isArray(rv[resKey]) ? rv[resKey] : []
rv[resKey].push(x)
return rv
}, {})
@@ -167,3 +168,35 @@ function flattenDeep (arr, newArr = []) {
}
return newArr
}
function splitProps ({className, style, ...rest}) {
return {
className,
style,
rest
}
}
function compactObject (obj) {
const newObj = {}
for (var key in obj) {
if (obj.hasOwnProperty(key) && obj[key] !== undefined && typeof obj[key] !== 'undefined') {
newObj[key] = obj[key]
}
}
return newObj
}
function isSortingDesc (d) {
return !!(d.sort === 'desc' || d.desc === true || d.asc === false)
}
function normalizeComponent (Comp, params = {}, fallback = Comp) {
return typeof Comp === 'function' ? (
Comp.prototype.isReactComponent ? (
<Comp
{...params}
/>
) : Comp(params)
) : fallback
}
+170
View File
@@ -0,0 +1,170 @@
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
export default () => {
const data = _.map(_.range(5553), d => {
const statusChance = Math.random()
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
progress: Math.floor(Math.random() * 100),
status: statusChance > 0.66 ? 'relationship'
: statusChance > 0.33 ? 'complicated'
: 'single'
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Profile Progress',
accessor: 'progress',
render: row => (
<div
style={{
width: '100%',
height: '100%',
backgroundColor: '#dadada',
borderRadius: '2px'
}}
>
<div
style={{
width: `${row.value}%`,
height: '100%',
backgroundColor: row.value > 66 ? '#85cc00'
: row.value > 33 ? '#ffbf00'
: '#ff2e00',
borderRadius: '2px',
transition: 'all .2s ease-out'
}}
/>
</div>
)
}, {
header: 'Status',
accessor: 'status',
render: row => (
<span>
<span style={{
color: row.value === 'relationship' ? '#ff2e00'
: row.value === 'complicated' ? '#ffbf00'
: '#57d500',
transition: 'all .3s ease'
}}>
&#x25cf;
</span> {
row.value === 'relationship' ? 'In a relationship'
: row.value === 'complicated' ? `It's complicated`
: 'Single'
}
</span>
)
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
<CodeHighlight>{() => getCode()}</CodeHighlight>
</div>
)
}
function getCode () {
return `
import ReactTable from 'react-table'
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Profile Progress',
accessor: 'progress',
render: row => (
<div
style={{
width: '100%',
height: '100%',
backgroundColor: '#dadada',
borderRadius: '2px'
}}
>
<div
style={{
width: \`$\{row.value}%\`,
height: '100%',
backgroundColor: row.value > 66 ? '#85cc00'
: row.value > 33 ? '#ffbf00'
: '#ff2e00',
borderRadius: '2px',
transition: 'all .2s ease-out'
}}
/>
</div>
)
}, {
header: 'Status',
accessor: 'status',
render: row => (
<span>
<span style={{
color: row.value === 'relationship' ? '#ff2e00'
: row.value === 'complicated' ? '#ffbf00'
: '#57d500',
transition: 'all .3s ease'
}}>
&#x25cf;
</span> {
row.value === 'relationship' ? 'In a relationship'
: row.value === 'complicated' ? \`It's complicated\`
: 'Single'
}
</span>
)
}]
}]
return (
<ReactTable
data={data}
columns={columns}
defaultPageSize={10}
/>
)
`
}
+106
View File
@@ -0,0 +1,106 @@
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
export default () => {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30)
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
}]
}]
return (
<div>
<strong>Hey!</strong> Open your console! :)
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
getTdProps={(state, rowInfo, column, instance) => {
return {
onMouseEnter: e => console.log('Cell - onMouseEnter', {
state,
rowInfo,
column,
instance,
event: e
})
}
}}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
<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'
}]
}]
return (
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
getTdProps={(state, rowInfo, column, instance) => {
return {
onMouseEnter: e => console.log('Cell - onMouseEnter', {
state,
rowInfo,
column,
instance,
event: e
})
}
}}
/>
)
`
}
+106
View File
@@ -0,0 +1,106 @@
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
export default () => {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30)
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName',
render: row => {
return <span>{row.aggregated ? '...' : row.value}</span>
}
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age',
aggregate: vals => _.round(_.mean(vals)),
render: row => {
return <span>{row.aggregated ? `${row.value} (avg)` : row.value}</span>
}
}]
}, {
expander: true
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
SubComponent={() => <span>Hello</span>}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
<CodeHighlight>{() => getCode()}</CodeHighlight>
</div>
)
}
function getCode () {
return `
import ReactTable from 'react-table'
// Create some column definitions
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName',
render: row => {
return <span>{row.aggregated ? '...' : row.value}</span>
}
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age',
aggregate: vals => _.round(_.mean(vals)),
render: row => {
return <span>{row.aggregated ? \`$\{row.value} (avg)\` : row.value}</span>
}
}]
}, {
expander: true
}]
return (
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
SubComponent={() => <span>Hello</span>}
/>
)
`
}
+91
View File
@@ -0,0 +1,91 @@
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
export default () => {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30)
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName',
maxWidth: 200
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName,
width: 300
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age',
minWidth: 400
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
<CodeHighlight>{() => getCode()}</CodeHighlight>
</div>
)
}
function getCode () {
return `
import ReactTable from 'react-table'
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName',
maxWidth: 200
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName,
width: 300
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age',
minWidth: 400
}]
}]
return (
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
/>
)
`
}
+91
View File
@@ -0,0 +1,91 @@
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
export default () => {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30)
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
defaultSorting={[{
id: 'age',
desc: true
}]}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
<CodeHighlight>{() => getCode()}</CodeHighlight>
</div>
)
}
function getCode () {
return `
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
}]
}]
return (
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
defaultSorting={[{
id: 'age',
desc: true
}]}
/>
)
`
}
+114
View File
@@ -0,0 +1,114 @@
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
export default () => {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30)
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName',
footer: (
<span><strong>Popular:</strong> {
_.first(
_.reduce(
_.map(
_.groupBy(
data, d => d.firstName
)
),
(a, b) => a.length > b.length ? a : b
)
).firstName}
</span>
)
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName,
footer: (
<span><strong>Longest:</strong> {
_.reduce(
_.map(
_.groupBy(
data, d => d.lastName
),
(d, key) => key
),
(a, b) => a.length > b.length ? a : b
)}
</span>
)
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age',
footer: <span><strong>Average:</strong> {_.round(_.mean(_.map(data, d => d.age)))}</span>
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
<CodeHighlight>{() => getCode()}</CodeHighlight>
</div>
)
}
function getCode () {
return `
import ReactTable from 'react-table'
// Create some column definitions
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
}]
}]
// Display your table!
return (
<ReactTable
data={data}
columns={columns}
defaultPageSize={10}
/>
)
`
}
+173
View File
@@ -0,0 +1,173 @@
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import JSONTree from 'react-json-tree'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
const JSONtheme = {
scheme: 'monokai',
author: 'wimer hazenberg (http://www.monokai.nl)',
base00: '#272822',
base01: '#383830',
base02: '#49483e',
base03: '#75715e',
base04: '#a59f85',
base05: '#f8f8f2',
base06: '#f5f4f1',
base07: '#f9f8f5',
base08: '#f92672',
base09: '#fd971f',
base0A: '#f4bf75',
base0B: '#a6e22e',
base0C: '#a1efe4',
base0D: '#66d9ef',
base0E: '#ae81ff',
base0F: '#cc6633'
}
export default () => {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30)
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName',
footer: 'Footer'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName,
footer: 'Footer'
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age',
footer: 'Footer'
}]
}]
return (
<div>
<strong>Functional rendering</strong> simply means that you have all of the building blocks to render your own React Table however you'd like.
<br />
<br />
<br />
<br />
<strong>Decorating the standard table output</strong>
<br />
<br />
<div className='table-wrap'>
<ReactTable
data={data}
columns={columns}
>
{(state, makeTable, instance) => {
return (
<div style={{
background: '#ffcf00',
borderRadius: '5px',
overflow: 'hidden',
padding: '5px'
}}>
<pre><code>state.allVisibleColumns === {JSON.stringify(state.allVisibleColumns, null, 4)}</code></pre>
{makeTable()}
</div>
)
}}
</ReactTable>
</div>
<CodeHighlight>{() => `
import ReactTable from 'react-table'
return (
<ReactTable
data={data}
columns={columns}
>
{(state, Table, instance) => {
return (
<div style={{
background: '#ffcf00',
borderRadius: '5px',
overflow: 'hidden',
padding: '5px'
}}>
<pre><code>state.allVisibleColumns === {JSON.stringify(state.allVisibleColumns, null, 4)}</code></pre>
<Table />
</div>
)
}}
</ReactTable>
)
`}</CodeHighlight>
<br />
<br />
<strong>Need more control? This is the entire table state and component instance at your disposal!</strong>
<br />
<br />
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
>
{(state, StandardTable, instance) => {
return (
<div>
<JSONTree
data={Object.assign({}, state, {children: 'function () {...}'})}
theme={JSONtheme}
invertTheme
/>
</div>
)
}}
</ReactTable>
</div>
<br />
<CodeHighlight>{() => `
import ReactTable from 'react-table'
return (
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
>
{(state, StandardTable, instance) => {
return (
<div>
<JSONTree
data={Object.assign({}, state, {children: 'function () {...}'})}
theme={JSONtheme}
invertTheme
/>
</div>
)
}}
</ReactTable>
)
`}</CodeHighlight>
</div>
)
}
+92
View File
@@ -0,0 +1,92 @@
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
export default () => {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30)
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={[]}
noDataText='Oh Noes!'
// noDataText={() => 'Oh Noes!'} // Supports functions
// noDataText={() => <span>Oh Noes!</span>} // Supports JSX / React Components
columns={columns}
defaultPageSize={10}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
<CodeHighlight>{() => getCode()}</CodeHighlight>
</div>
)
}
function getCode () {
return `
import ReactTable from 'react-table'
// Create some column definitions
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
}]
}]
// Display your table!
return (
<ReactTable
data={[]}
noDataText='Oh Noes!'
// noDataText={() => 'Oh Noes!'} // Supports functions
// noDataText={() => <span>Oh Noes!</span>} // Supports JSX / React Components
columns={columns}
defaultPageSize={10}
/>
)
`
}
+12 -2
View File
@@ -47,6 +47,7 @@ export default () => {
<ReactTable
data={data}
columns={columns}
className='-striped -highlight'
defaultPageSize={10}
pivotBy={['firstName', 'lastName']}
SubComponent={(row) => {
@@ -99,15 +100,24 @@ const columns = [{
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
accessor: 'age',
aggregate: vals => _.round(_.mean(vals)),
render: row => {
return <span>{row.aggregated ? \`\${row.value} (avg)\` : row.value}</span>
}
}, {
header: 'Visits',
accessor: 'visits',
aggregate: vals => _.sum(vals)
}]
}]
export default (
return (
<ReactTable
data={data}
columns={columns}
defaultPageSize={10}
className='-striped -highlight'
pivotBy={['firstName', 'lastName']}
SubComponent={(row) => {
return (
+13 -31
View File
@@ -47,14 +47,9 @@ export default () => {
<ReactTable
data={data}
columns={columns}
className='-striped -highlight'
defaultPageSize={10}
pivotBy={['firstName', 'lastName']}
// expandedRows={{
// 2: true,
// 3: {
// 2: true
// }
// }}
/>
</div>
<div style={{textAlign: 'center'}}>
@@ -82,38 +77,25 @@ const columns = [{
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
accessor: 'age',
aggregate: vals => _.round(_.mean(vals)),
render: row => {
return <span>{row.aggregated ? \`\${row.value} (avg)\` : row.value}</span>
}
}, {
header: 'Visits',
accessor: 'visits',
aggregate: vals => _.sum(vals)
}]
}]
export default (
return (
<ReactTable
data={data}
columns={columns}
className='-striped -highlight'
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>
)
}}
pivotBy={['firstName', 'lastName']}
/>
)
`
+12 -2
View File
@@ -48,6 +48,7 @@ export default () => {
data={data}
columns={columns}
defaultPageSize={10}
className='-striped -highlight'
pivotBy={['firstName', 'lastName']}
SubComponent={(row) => {
return (
@@ -99,15 +100,24 @@ const columns = [{
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
accessor: 'age',
aggregate: vals => _.round(_.mean(vals)),
render: row => {
return <span>{row.aggregated ? \`\${row.value} (avg)\` : row.value}</span>
}
}, {
header: 'Visits',
accessor: 'visits',
aggregate: vals => _.sum(vals)
}]
}]
export default (
return (
<ReactTable
data={data}
columns={columns}
defaultPageSize={10}
className='-striped -highlight'
pivotBy={['firstName', 'lastName']}
SubComponent={(row) => {
return (
+10 -33
View File
@@ -48,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)
.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,
@@ -68,6 +68,7 @@ const ServerSide = React.createClass({
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
columns={[{
header: 'First Name',
accessor: 'firstName'
@@ -135,42 +136,18 @@ export default React.createClass({
})
},
render () {
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
}]
}]
return (
<ReactTable
columns={[{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
}]
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}, {
header: 'Age',
accessor: 'age'
}]}
manual // Forces table not to paginate or sort automatically, so we can handle it server-side
defaultPageSize={10}
+1
View File
@@ -36,6 +36,7 @@ export default () => {
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
+129 -63
View File
@@ -5,76 +5,138 @@ import namor from 'namor'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
export default () => {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30)
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
},
data: data
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
this.setTableOption = this.setTableOption.bind(this);
}
render() {
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
}]
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
data={data}
columns={columns}
defaultPageSize={10}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>You can put any component you want here, even another React Table!</em>
<br />
<br />
<ReactTable
data={data}
columns={columns}
defaultPageSize={3}
showPagination={false}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>It even has access to the row data: </em>
<CodeHighlight>{() => JSON.stringify(row, null, 2)}</CodeHighlight>
</div>
)
}}
/>
</div>
)
}}
/>
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>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
<CodeHighlight>{() => getCode()}</CodeHighlight>
</div>
)
}
)
}
function getCode () {
return `
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: [{
@@ -98,6 +160,7 @@ export default (
data={data}
columns={columns}
defaultPageSize={10}
{...otherOptions}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
@@ -124,4 +187,7 @@ export default (
/>
)
`
}
}
export default () => <SubComponents/>
+918 -835
View File
File diff suppressed because it is too large Load Diff