Compare commits

..
Author SHA1 Message Date
Aaron Schwartz ad803c2d6d Remove unused prop from readme. 2017-05-11 12:03:02 -07:00
Aaron Schwartz 4a9ab56cae Remove unused prop 2017-05-11 12:02:10 -07:00
Aaron Schwartz 080e82abfe Cleanup Changelog and lint errors 2017-05-11 12:00:50 -07:00
Aaron Schwartz e3753d1733 Rename showFilters->filterable, hideFilter->filterable 2017-05-11 11:38:11 -07:00
Aaron Schwartz 8f0fb3536e Standardize global and column level resizable and sortable properties 2017-05-11 09:38:15 -07:00
Aaron Schwartz c5ce633049 Cleanup Readme 2017-05-11 08:50:07 -07:00
Aaron Schwartz ea2968b14c Rename onExpanded->onExpandedChange 2017-05-10 16:56:40 -07:00
Aaron Schwartz 171ff37bcd Rename resizing->resized, defaultResizing->defaultResized, onResize->onResizedChange 2017-05-10 16:52:45 -07:00
Aaron Schwartz 7e0bca8a17 Rename expandedRows->expanded, onExpandRow->onExpanded 2017-05-10 16:37:26 -07:00
Aaron Schwartz e9c27952b5 filtering->filtered, onFilteringChange->onFilteredChange, defaultFiltering->defaultFiltered 2017-05-10 16:28:02 -07:00
Aaron Schwartz e9bdc8e3c6 Rename sorting->sorted, onSortingChange->onSortedChange, defaultSorting->defaultSorted 2017-05-10 16:14:51 -07:00
Aaron Schwartz 6be71dc4a1 Add defaultExpanded prop 2017-05-10 15:52:34 -07:00
Tanner Linsley cfdc688501 Handle edge cases in expandable hover states and event handlers 2017-05-10 15:48:29 -06:00
Tanner Linsley 7c7e688811 Use Correct PivotingOptions source 2017-05-10 15:47:46 -06:00
Tanner Linsley 9cb9b2ba75 6.0.0 2017-05-10 15:24:36 -06:00
Tanner Linsley bdefce7e03 Updated Changelog 2017-05-10 15:23:38 -06:00
Tanner Linsley 31e852f387 Fix SubComponent Story 2017-05-10 15:21:40 -06:00
Tanner Linsley dff84eb368 Finish fixing up stories with better source 2017-05-10 14:42:13 -06:00
Tanner Linsley bdf759c8f8 Better custom sorting 2017-05-10 13:57:34 -06:00
Aaron Schwartz 53c6d17b40 Fix up stories. 2017-05-09 16:45:58 -07:00
Tanner Linsley 0191b3bc55 Trying generalize expanders to work on any column 2017-05-09 13:40:35 -06:00
Tanner Linsley ad7ea2f5d3 Remove console.log 2017-05-09 13:15:14 -06:00
Tanner Linsley c24cc37c7d +Key constants, prop/callback changes, controllable filters and resizing, subRow + pivoting expansion 2017-05-09 13:12:18 -06:00
Tanner Linsley 307d37421e Resizing Fixes, custom sorting, new api names 2017-05-09 01:23:04 -06:00
Tanner Linsley 2d35148c75 Fixed Typo 2017-05-08 17:27:34 -06:00
Tanner Linsley c90914f585 Updated Renderer Keys and Stories (+ story cleanup) 2017-05-08 17:26:18 -06:00
Tanner Linsley d236097201 Better expanding and aggregation control 2017-05-08 16:24:35 -06:00
Tanner Linsley 3babdd1f66 Use separate columns for Pivots and Expanders, more render options 2017-05-08 14:54:32 -06:00
Miha ValencicandTanner Linsley ad7d31cd39 Add column id to the rowInfo object (#253)
* Add column id to the rowInfo object (passed to render). Resolves #237

* Creating a new object instead of modifying existing rowInfo; Refs #253

* Code style compliance. Refs #253
2017-05-06 10:33:17 -06:00
wonyoungandTanner Linsley ddee18cf86 Update README.md (#213)
* Update README.md

Bug fix in custom props example

* Update README.md

Bug fix in custom column props example
2017-05-05 17:22:48 -06:00
Austin HuntandTanner Linsley 1757b4dd9f Fixed documentation to match the actual implementation settings. Sorting objects use a desc prop not a asc prop. (#239) 2017-05-05 17:22:09 -06:00
Aaron SchwartzandGitHub 9d9b1fdee4 Enhance pivots (#224)
* Prevent transitions while resizing for a smoother effect.
* Disable text selection when resizing columns
* Use PivotValueComponent instead of pivotRender
* Add changelog file
2017-05-05 12:51:17 -07:00
Aaron SchwartzandGitHub ab1c020ad3 Fix sorting indicator or pivot columns. 2017-04-20 16:13:17 -07:00
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
Tanner Linsley a1e724c483 5.5.3 2017-04-17 12:00:29 -06:00
Tanner Linsley 741660c915 Use webpack to compile umd 2017-04-17 12:00:17 -06:00
Tanner Linsley 1f8062501f Better npm scripts for ci and publishing 2017-04-17 11:27:20 -06:00
Tanner Linsley fb51afd0ae Keep tags up to date with releases 2017-04-17 09:30:02 -06:00
43 changed files with 2683 additions and 2883 deletions
+8
View File
@@ -13,6 +13,7 @@ import Readme from '../README.md'
import Simple from '../stories/Simple.js'
import CellRenderers from '../stories/CellRenderers.js'
import DefaultSorting from '../stories/DefaultSorting.js'
import CustomSorting from '../stories/CustomSorting.js'
import CustomWidths from '../stories/CustomWidths.js'
import CustomComponentProps from '../stories/CustomComponentProps.js'
import ServerSide from '../stories/ServerSide.js'
@@ -26,6 +27,9 @@ import NoDataText from '../stories/NoDataText.js'
import Footers from '../stories/Footers.js'
import Filtering from '../stories/Filtering.js'
import ControlledTable from '../stories/ControlledTable.js'
import PivotingOptions from '../stories/PivotingOptions.js'
import EditableTable from '../stories/EditableTable.js'
import SubRows from '../stories/SubRows.js'
//
configure(() => {
storiesOf('1. Docs')
@@ -44,6 +48,7 @@ configure(() => {
.add('Simple Table', Simple)
.add('Cell Renderers & Custom Components', CellRenderers)
.add('Default Sorting', DefaultSorting)
.add('Custom Sorting', CustomSorting)
.add('Custom Column Widths', CustomWidths)
.add('Custom Component Props', CustomComponentProps)
.add('Server-side Data', ServerSide)
@@ -51,10 +56,13 @@ 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)
.add('Footers', Footers)
.add('Custom Filtering', Filtering)
.add('Controlled Component', ControlledTable)
.add('Editable table', EditableTable)
// .add('Sub Rows', SubRows)
}, module)
+44
View File
@@ -0,0 +1,44 @@
## 6.0.0
##### New Features
- New Renderers:
- `Aggregated` - Custom renderer for aggregated cells
- `Pivot` - Custom renderer for Pivoted Cells (utilizes `Expander` and `PivotValue`)
- `PivotValue` - Custom renderer for Pivot cell values (deprecates the undocumented `pivotRender` option)
- `Expander` - Custom renderer for Pivot cell Expander
- Added custom sorting methods per table via `defaultSortMethod` and per column via `column.sortMethod`
- Pivot columns are now visibly separate and sorted/filtered independently.
- Added `column.resizable` to override global table `resizable` option for specific columns.
- Added `column.sortable` to override global table `sortable` option for specific columns.
- Added `column.filterable` to override global table `filterable` option for specific columns.
- Added `defaultExpanded` table option.
- All callbacks can now be utilized without needing to hoist and manage the piece of state they export. That is what their prop counterparts are for, so now the corresponding prop is used instead of the callback to detect a "fully controlled" state.
- Prevent transitions while column resizing for a smoother resize effect.
- Disable text selection while resizing columns.
##### Breaking API Changes
- New Renderers:
- `Cell` - deprecates and replaces `render`
- `Header` - deprecates and replaces `header`
- `Footer` - deprecates and replaces `footer`
- `Filter`- deprecates and replaces `filterRender`
- Callbacks now provide the destination state as the primary parameter(s). This makes hoisting and controlling the state in redux or component state much easier. eg.
- `onSorting` no longer requires you to build your own toggle logic
- `onResize` no longer requires you to build your own resize logic
- Renamed `onChange` callback -> `onFetchData` which will always fire when a new data model needs to be fetched (or if not using `manual`, when new data is materialized internally).
- Renamed `filtering` -> `filtered`
- Renamed `sorting` -> `sorted`
- Renamed `expandedRows` -> `expanded`
- Renamed `resizing` -> `resized`
- Renamed `defaultResizing` -> `defaultResized`
- Renamed `defaultFiltering` -> `defaultFiltered`
- Renamed `defaultSorting` -> `defaultSorted`
- Renamed `onSortingChange` -> `onSortedChange`
- Renamed `onFilteringChange` -> `onFilteredChange`
- Renamed `onResize` -> `onResizedChange`
- Renamed `onExpandRow` -> `onExpandedChange`
- Renamed `showFilters` -> `filterable`
- Renamed `hideFilter` -> `filterable` (Column option. Note the true/false value is now flipped.)
- `cellInfo.row` and `rowInfo.row` now reference the materialize data for the table. To reference the original row, use `cellInfo.original` and `rowInfo.original`
- Removed `pivotRender` column option. You can now control how the value is displayed by overriding the `PivotValueComponent` or the individual column's `PivotValue` renderer. See [Pivoting Options Story](https://react-table.js.org/?selectedKind=2.%20Demos&selectedStory=Pivoting%20Options&full=0&down=1&left=1&panelRight=0&downPanel=kadirahq%2Fstorybook-addon-actions%2Factions-panel) for a reference on how to customize pivot column rendering.
+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
+248 -94
View File
@@ -28,8 +28,14 @@
<img alt="" src="https://img.shields.io/badge/%24-Donate-brightgreen.svg" />
</a>
## Features
## Versions
This document refers to version 6.x.x of react-table.
Previous versions:
[5.x.x Readme](https://github.com/tannerlinsley/react-table/blob/ad7d31cd3978eb45da7c6194dbab93c1e9a8594d/README.md)
## Features
- Lightweight at 7kb (and just 2kb more for styles)
- Fully customizable JSX templating
- Supports both Client-side & Server-side pagination and multi-sorting
@@ -38,7 +44,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 +74,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 +83,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
@@ -103,18 +121,18 @@ render() {
}]
const columns = [{
header: 'Name',
Header: 'Name',
accessor: 'name' // String-based value accessors!
}, {
header: 'Age',
Header: 'Age',
accessor: 'age',
render: props => <span className='number'>{props.value}</span> // Custom cell components!
Cell: props => <span className='number'>{props.value}</span> // Custom cell components!
}, {
id: 'friendName', // Required because our accessor is not a string
header: 'Friend Name',
Header: 'Friend Name',
accessor: d => d.friend.name // Custom value accessors!
}, {
header: props => <span>Friend Age</span>, // Custom header components!
Header: props => <span>Friend Age</span>, // Custom header components!
accessor: 'friend.age'
}]
@@ -141,49 +159,70 @@ 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,
freezeWhenExpanded: false,
defaultSorting: [],
showFilters: false,
defaultFiltering: [],
sortable: true,
resizable: true,
filterable: false,
defaultSorted: [],
defaultFiltered: [],
defaultResized: [],
defaultExpanded: {},
defaultFilterMethod: (filter, row, column) => {
const id = filter.pivotId || filter.id
return row[id] !== undefined ? String(row[id]).startsWith(filter.value) : true
},
resizable: true,
defaultResizing: [],
defaultSortMethod: (a, b) => {
// force null and undefined to the bottom
a = (a === null || a === undefined) ? -Infinity : a
b = (b === null || b === undefined) ? -Infinity : b
// force any string values to lowercase
a = a === 'string' ? a.toLowerCase() : a
b = b === 'string' ? b.toLowerCase() : b
// Return either 1 or -1 to indicate a sort priority
if (a > b) {
return 1
}
if (a < b) {
return -1
}
// returning 0, undefined or any falsey value will use subsequent sorts or the index as a tiebreaker
return 0
},
// Controlled State Overrides (see Fully Controlled Component section)
page: undefined,
pageSize: undefined,
sorting: undefined,
sorted: [],
filtered: [],
resized: [],
expanded: {},
// Controlled State Callbacks
onExpandSubComponent: undefined,
onPageChange: undefined,
onPageSizeChange: undefined,
onSortingChange: undefined,
onFilteringChange: undefined,
onResize: undefined,
onSortedChange: undefined,
onFilteredChange: undefined,
onResizedChange: undefined,
onExpandedChange: undefined,
// Pivoting
pivotBy: undefined,
pivotColumnWidth: 200,
// Key Constants
pivotValKey: '_pivotVal',
pivotIDKey: '_pivotID',
subRowsKey: '_subRows',
aggregatedKey: '_aggregated',
nestingLevelKey: '_nestingLevel',
originalKey: '_original',
indexKey: '_index',
groupedByPivotKey: '_groupedByPivot',
// Pivoting State Overrides (see Fully Controlled Component section)
expandedRows: {},
// Pivoting State Callbacks
onExpandRow: undefined,
// General Callbacks
onChange: () => null,
// Server-side callbacks
onFetchData: () => null,
// Classes
className: '',
@@ -216,37 +255,48 @@ These are all of the available props (and their default values) for the main `<R
// Global Column Defaults
column: {
sortable: true,
// Renderers
Cell: undefined,
Header: undefined,
Footer: undefined,
Aggregated: undefined,
Pivot: undefined,
PivotValue: undefined,
Expander: undefined,
Filter: undefined,
// Standard options
sortable: undefined, // use table default
resizable: undefined, // use table default
filterable: undefined, // use table default
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: () => ({}),
filterMethod: undefined,
hideFilter: false,
filterRender: ({filter, onFilterChange}) => (
<input type='text'
style={{
width: '100%'
}}
value={filter ? filter.value : ''}
onChange={(event) => onFilterChange(event.target.value)}
/>
)
sortMethod: undefined
},
// Global Expander Column Defaults
expanderDefaults: {
sortable: false,
resizable: false,
filterable: false,
width: 35
},
// Global Pivot Column Defaults
pivotDefaults: {},
// Text
previousText: 'Previous',
nextText: 'Next',
@@ -285,31 +335,49 @@ Or just define them as props
```javascript
[{
// Renderers - For more information, see "Renderers" section below
Cell: JSX | String | Function // Used to render a standard cell, defaults to the accessed value
Header: JSX | String | Function // Used to render the header of a column or column group
Footer: JSX | String | Function // Used to render the footer of a column
Filter: JSX | cellInfo => ( // Used to render the filter UI of a filter-enabled column
<select onChange={event => onFiltersChange(event.target.value)} value={filter ? filter.value : ''}></select>
// The value passed to onFiltersChange will be the value passed to filter.value of the filterMethod
)
Aggregated: JSX | String | Function // Used to render aggregated cells. Defaults to a comma separated list of values.
Pivot: JSX | String | Function | cellInfo => ( // Used to render a pivoted cell
<span>
<Expander/><PivotValue /> // By default, will utilize the the PivotValue and Expander components at run time
</span>
),
PivotValue: JSX | String | Function // Used to render the value inside of a Pivot cell
Expander: JSX | String | Function // Used to render the expander in both Pivot and Expander cells
// General
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,
sortable: boolean, // Overrides the table option
resizable: boolean, // Overrides the table option
filterable: boolean, // Overrides the table option
show: true, // can be used to hide a column
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
pivot: false,
// Turns this column into a special column for specifying pivot position in your column definitions.
// The `pivotDefaults` options will be applied on top of this column's options.
// 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)
expander: false,
// Turns this column into a special column for specifying expander position and options in your column definitions.
// The `expanderDefaults` options will be applied on top of this column's options.
// 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 via the `Expander` property
// 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. (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
// index == the original index of the data supplied to the table
// viewIndex == the index of the row in the current page
// Header & HeaderGroup Options
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
@@ -318,7 +386,6 @@ Or just define them as props
columns: [...], // See Header Groups section below
// Footer
footer: 'Footer Name' or JSX eg. ({data, column}) => <div>Footer 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
@@ -328,11 +395,54 @@ Or just define them as props
// filter == an object specifying which filter is being applied. Format: {id: [the filter column's id], value: [the value the user typed in the filter field], pivotId: [if filtering on a pivot column, the pivotId will be set to the pivot column's id and the `id` field will be set to the top level pivoting column]}
// row == the row of data supplied to the table
// column == the column that the filter is on
hideFilter: false, // If `showFilters` is set on the table, this option will let you selectively hide the filter on a particular row
filterRender: JSX // eg. ({filter, onFilterChange}) => <select onChange={event => onFilterChange(event.target.value)} value={filter ? filter.value : ''}></select> // The value passed to onFilterChange will be the value passed to filter.value of the filterMethod
}]
```
## Renderers
React Table supports very flexible renderers for just about everything:
- `Cell` - Renders a standard cell
- `Header` - Renders a column header or column group header
- `Footer` - Renders a column footer
- `Filter` - Renders a column's filter UI
- `Aggregated` - Renders an aggregated cell
- `Pivot` - Renders a pivoted cell (by default, will utilize `Expander` and `PivotValue` renderers)
- `PivotValue` - Renders the value inside a `Pivot` renderer
- `Expander` - Renders the Expander used in both the default `Pivot` renderer and any expander-designated column
Any of these renderers can be one of the following:
- A React Class
- JSX or any rendered react component
- Stateless functional component
- Function that returns any primitive
All of these formats receive the following props:
```javascript
{
// Row-level props
row: Object, // the materialized row of data
original: , // the original row of data
index: '', // the index of the row in the original arra
viewIndex: '', // the index of the row relative to the current view
level: '', // the nesting level of this row
nestingPath: '', // the nesting path of this row
aggregated: '', // true if this row's values were aggregated
groupedByPivot: '', // true if this row was produced by a pivot
subRows: '', // any sub rows defined by the `subRowKey` prop
// Cells-level props
isExpanded: '', // true if this row is expanded
value: '', // the materialized value of this cell
resized: '', // the resize information for this cell's column
show: '', // true if the column is visible
width: '', // the resolved width of this cell
maxWidth: '', // the resolved maxWidth of this cell
tdProps: '', // the resolved tdProps from `getTdProps` for this cell
columnProps: '', // the resolved column props from 'getProps' for this cell's column
classes: '', // the resolved array of classes for this cell
styles: '' // the resolved styles for this cell
}
```
## 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.
@@ -360,16 +470,16 @@ If your data has a field/key with a dot (`.`) you will need to supply a custom a
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',
Header: 'Favorites',
headerClassName: 'my-favorites-column-header-group'
columns: [{
header: 'Color',
Header: 'Color',
accessor: 'favorites.color'
}, {
header: 'Food',
Header: 'Food',
accessor: 'favorites.food'
} {
header: 'Actor',
Header: 'Actor',
accessor: 'favorites.actor'
}]
}]
@@ -378,7 +488,7 @@ const columns = [{
## 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
- `row` - 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)
@@ -390,9 +500,9 @@ You can use any react component or JSX to display content in column headers, cel
// 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>,
Header: () => <span><i className='fa-tasks' /> Progress</span>,
accessor: 'progress',
render: row => (
Cell: row => (
<div
style={{
width: '100%',
@@ -453,8 +563,8 @@ Every single built-in component's props can be dynamically extended using any on
getTdProps={fn}
getPaginationProps={fn}
getLoadingProps={fn}
getNoDataProps: {fn},
getResizerProps: {fn}
getNoDataProps={fn}
getResizerProps={fn}
/>
```
@@ -489,7 +599,7 @@ You can use these callbacks for dynamic styling as well!
getTrProps={(state, rowInfo, column) => {
return {
style: {
background: rowInfo.age > 20 ? 'green' : 'red'
background: rowInfo.row.age > 20 ? 'green' : 'red'
}
}
}}
@@ -514,7 +624,7 @@ const columns = [{
getProps: (state, rowInfo, column) => {
return {
style: {
background: rowInfo.name === 'Santa Clause' ? 'red' : null
background: rowInfo.row.name === 'Santa Clause' ? 'red' : null
}
}
}
@@ -535,21 +645,21 @@ Naturally when grouping rows together, you may want to aggregate the rows inside
```javascript
// In this example, we use lodash to sum and average the values, but you can use whatever you want to aggregate.
const columns = [{
header: 'Age',
Header: 'Age',
accessor: 'age',
aggregate: (values, rows) => _.round(_.mean(values)),
render: row => {
Aggregated: row => {
// You can even render the cell differently if it's an aggregated cell
return <span>{row.aggregated ? `${row.value} (avg)` : row.value}</span>
return <span>row.value (avg)</span>
}
}, {
header: 'Visits',
Header: 'Visits',
accessor: 'visits',
aggregate: (values, rows) => _.sum(values)
}]
```
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.
Pivoted columns can be sorted just like regular columns including holding down the `<shift>` button to multi-sort.
## Sub Tables and Sub Components
By adding a `SubComponent` props, you can easily add an expansion level to all root-level rows:
@@ -574,8 +684,8 @@ If you want to handle pagination, sorting, and filtering on the server, `react-t
1. Feed React Table `data` from somewhere dynamic. eg. `state`, a redux store, etc...
1. Add `manual` as a prop. This informs React Table that you'll be handling sorting and pagination server-side
1. Subscribe to the `onChange` prop. This function is called at `compomentDidMount` and any time sorting or pagination is changed by the user
1. In the `onChange` callback, request your data using the provided information in the params of the function (state and instance)
1. Subscribe to the `onFetchData` prop. This function is called at `compomentDidMount` and any time sorting, pagination or filterting is changed in the table
1. In the `onFetchData` callback, request your data using the provided information in the params of the function (current state and instance)
1. Update your data with the rows to be displayed
1. Optionally set how many pages there are total
@@ -586,15 +696,15 @@ If you want to handle pagination, sorting, and filtering on the server, `react-t
pages={this.state.pages} // should default to -1 (which means we don't know how many pages we have)
loading={this.state.loading}
manual // informs React Table that you'll be handling sorting and pagination server-side
onChange={(state, instance) => {
onFetchData={(state, instance) => {
// show the loading overlay
this.setState({loading: true})
// fetch your data
Axios.post('mysite.com/data', {
page: state.page,
pageSize: state.pageSize,
sorting: state.sorting,
filtering: state.filtering
sorted: state.sorted,
filtered: state.filtered
})
.then((res) => {
// Update react-table
@@ -619,29 +729,37 @@ Here are the props and their corresponding callbacks that control the state of t
// Props
page={0} // the index of the page you wish to display
pageSize={20} // the number of rows per page to be displayed
sorting={[{
sorting={[{ // the sorting model for the table
id: 'lastName',
asc: true
desc: true
}, {
id: 'firstName',
asc: true
}]} // the sorting model for the table
expandedRows={{
desc: true
}]}
expandedRows={{ // The nested row indexes on the current page that should appear expanded
1: true,
4: true,
5: {
2: true,
3: true
}
}} // The nested row indexes on the current page that should appear expanded
}}
filters={[{ // the current filters model
id: 'lastName',
value: 'linsley'
}]}
resizing={[{ // the current resized column model
"id": "lastName",
"value": 446.25
}]}
// Callbacks
onPageChange={(pageIndex) => {...}} // Called when the page index is changed by the user
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.
onResize={(column, event, isTouch) => {...}} // Called when a user clicks on a resizing component (the right edge of a column header)
onSortedChange={(newSorted, 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
onExpandedChange={(newExpanded, index, event) => {...}} // Called when an expander is clicked. Use this to manage `expandedRows`
onFilteredChange={(column, value) => {...}} // Called when a user enters a value into a filter input field or the value passed to the onFiltersChange handler by the filterRender option.
onResizedChange={(newResized, event) => {...}} // Called when a user clicks on a resizing component (the right edge of a column header)
/>
```
@@ -682,19 +800,51 @@ Accessing internal state and wrapping with more UI:
The possibilities are endless!
## Sorting
Sorting comes built in with React-Table. Click column header to sort by its column. Click it again to reverse the sort.
## 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!
## Filtering
Filtering can be enabled by setting the `showFilters` option on the table.
## Custom Sorting Algorithm
To override the default sorting algorithm for the whole table use the `defaultSortMethod` prop.
If you don't want particular column to be filtered you can set the `hideFilter` option on the column.
To override the sorting algorithm for a single column, use the `sortMethod` column property.
Supply a function that implements the native javascript [`Array.sort`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) interface. This is React Table's default sorting algorithm:
- `a` the first value to compare
- `b` the second value to compare
- `dir` the
```javascript
defaultSortMethod = (a, b) => {
// force null and undefined to the bottom
a = (a === null || a === undefined) ? -Infinity : a
b = (b === null || b === undefined) ? -Infinity : b
// force any string values to lowercase
a = a === 'string' ? a.toLowerCase() : a
b = b === 'string' ? b.toLowerCase() : b
// Return either 1 or -1 to indicate a sort priority
if (a > b) {
return 1
}
if (a < b) {
return -1
}
// returning 0 or undefined will use any subsequent column sorting methods or the row index as a tiebreaker
return 0
}
```
## Filtering
Filtering can be enabled by setting the `filterable` option on the table.
If you don't want particular column to be filtered you can set the `filterable={false}` option on the column.
By default the table tries to filter by checking if the row's value starts with the filter text. The default method for filtering the table can be set with the table's `defaultFilterMethod` option.
If you want to override a particular column's filtering method, you can set the `filterMethod` option on a column.
To completely override the filter that is shown, you can set the `filterRender` column option. Using this option you can specify the JSX that is shown. The option is passed an `onFilterChange` method which must be called with the the value that you wan't to pass to the `filterMethod` option whenever the filter has changed.
To completely override the filter that is shown, you can set the `Filter` column option. Using this option you can specify the JSX that is shown. The option is passed an `onChange` method which must be called with the the value that you wan't to pass to the `filterMethod` option whenever the filter has changed.
See <a href="http://react-table.js.org/?selectedKind=2.%20Demos&selectedStory=Custom%20Filtering&full=0&down=1&left=1&panelRight=0&downPanel=kadirahq%2Fstorybook-addon-actions%2Factions-panel" target="\_parent">Custom Filtering</a> demo for examples.
@@ -713,6 +863,10 @@ Object.assign(ReactTableDefaults, {
TdComponent: component,
TfootComponent: component,
ExpanderComponent: component,
AggregatedComponent: component,
PivotValueComponent: component,
PivotComponent: component,
FilterComponent: component,
PaginationComponent: component,
PreviousComponent: undefined,
NextComponent: undefined,
+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.b5270b38a18bc77dc351.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.9a120eb2943ac2bf0331.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.9a120eb2943ac2bf0331.bundle.js","sources":["webpack:///static/manager.9a120eb2943ac2bf0331.bundle.js"],"mappings":"AAAA;AAmuDA;AA64DA;AA28DA;AA00DA;AAsvEA;AAuhDA;AAsrDA;AAsiDA;AAg6DA;AA2nDA;AA++CA;AAkvDA;AAsnEA;AA2oDA;AAivCA;AA+nDA;AAkpDA;AA6lEA;AAs4DA;AAquDA;AA+pDA;AAoxDA;AAsrDA;AAizDA;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.b5270b38a18bc77dc351.bundle.js","sources":["webpack:///static/preview.b5270b38a18bc77dc351.bundle.js"],"mappings":"AAAA;AAmrDA;AA8uCA;AAqoIA;AA2wGA;AA0pPA;AA65CA;AAk2DA;AA88DA;AAg0DA;AAsgEA;AAmlDA;AAgjDA;AA2hDA;AA6+DA;AAslDA;AA4+CA;AAimDA;AA09DA;AAy4DA;AAwxCA;AAknDA;AA+qDA;AA+nEA;AA4yDA;AAwwCA;AA8tDA;AAuqGA;AA65FA;AAg3CA;AA+1CA;AAkqCA;AAqlCA;AAkgDA;AAo2CA;AAsCA;AA+jFA","sourceRoot":""}
+8 -10
View File
@@ -1,6 +1,6 @@
{
"name": "react-table",
"version": "5.5.2",
"version": "6.0.0",
"description": "A fast, lightweight, opinionated table and datagrid built on React",
"license": "MIT",
"homepage": "https://github.com/tannerlinsley/react-table#readme",
@@ -30,13 +30,16 @@
"watch:node": "onchange 'src/**/*.js' -i -- npm run build:node",
"watch:css": "onchange 'src/**/*.styl' -i -- npm run build:css",
"test": "standard",
"umd": "rimraf react-table.js && browserify lib/index.js -s reactTable -x react -t babelify -g uglifyify -o react-table.js",
"prepublish": "npm-run-all build:* && npm run umd",
"umd": "rimraf react-table.js && webpack --config umd.webpack.js",
"build": "npm-run-all build:*",
"prepublish": "npm run build && npm run umd",
"postpublish": "git push --tags",
"storybook": "start-storybook -p 8000 -c .storybook",
"docs": "build-storybook -o docs && cp .storybook/CNAME docs/CNAME"
},
"dependencies": {
"classnames": "^2.2.5"
"classnames": "^2.2.5",
"raw-loader": "^0.5.1"
},
"peerDependencies": {
"react": "^15.x.x"
@@ -49,8 +52,6 @@
"babel-preset-es2015": "6.14.0",
"babel-preset-react": "6.11.1",
"babel-preset-stage-2": "6.13.0",
"babelify": "^7.3.0",
"browserify": "13.1.0",
"github-markdown-css": "^2.4.1",
"html-loader": "^0.4.4",
"markdown-loader": "^0.1.7",
@@ -65,10 +66,7 @@
"standard": "^8.0.0",
"storybook": "^0.0.0",
"stylus": "^0.54.5",
"uglifyify": "3.0.3"
},
"browserify-shim": {
"react": "global:React"
"webpack": "^2.4.1"
},
"standard": {
"parser": "babel-eslint",
+96 -40
View File
@@ -15,49 +15,70 @@ export default {
pageSizeOptions: [5, 10, 20, 25, 50, 100],
defaultPageSize: 20,
showPageJump: true,
expanderColumnWidth: 35,
collapseOnSortingChange: true,
collapseOnPageChange: true,
collapseOnDataChange: true,
freezeWhenExpanded: false,
defaultSorting: [],
showFilters: false,
defaultFiltering: [],
sortable: true,
resizable: true,
filterable: false,
defaultSorted: [],
defaultFiltered: [],
defaultResized: [],
defaultExpanded: {},
defaultFilterMethod: (filter, row, column) => {
const id = filter.pivotId || filter.id
return row[id] !== undefined ? String(row[id]).startsWith(filter.value) : true
},
resizable: true,
defaultResizing: [],
defaultSortMethod: (a, b) => {
// force null and undefined to the bottom
a = (a === null || a === undefined) ? -Infinity : a
b = (b === null || b === undefined) ? -Infinity : b
// force any string values to lowercase
a = a === 'string' ? a.toLowerCase() : a
b = b === 'string' ? b.toLowerCase() : b
// Return either 1 or -1 to indicate a sort priority
if (a > b) {
return 1
}
if (a < b) {
return -1
}
// returning 0, undefined or any falsey value will use subsequent sorts or the index as a tiebreaker
return 0
},
// Controlled State Overrides
// Controlled State Props
// page: undefined,
// pageSize: undefined,
// sorting: undefined,
// sorted: [],
// filtered: [],
// resized: [],
// expanded: {},
// Controlled State Callbacks
onExpandSubComponent: undefined,
onPageChange: undefined,
onPageSizeChange: undefined,
onSortingChange: undefined,
onFilteringChange: undefined,
onResize: undefined,
onSortedChange: undefined,
onFilteredChange: undefined,
onResizedChange: undefined,
onExpandedChange: undefined,
// Pivoting
pivotBy: undefined,
pivotColumnWidth: 200,
// Key Constants
pivotValKey: '_pivotVal',
pivotIDKey: '_pivotID',
subRowsKey: '_subRows',
aggregatedKey: '_aggregated',
nestingLevelKey: '_nestingLevel',
originalKey: '_original',
indexKey: '_index',
groupedByPivotKey: '_groupedByPivot',
// Pivoting State Overrides
// expandedRows: {},
// Pivoting State Callbacks
onExpandRow: undefined,
// General Callbacks
onChange: () => null,
// Server-side Callbacks
onFetchData: () => null,
// Classes
className: '',
@@ -89,35 +110,49 @@ export default {
// Global Column Defaults
column: {
sortable: true,
// Renderers
Cell: undefined,
Header: undefined,
Footer: undefined,
Aggregated: undefined,
Pivot: undefined,
PivotValue: undefined,
Expander: undefined,
Filter: undefined,
// All Columns
sortable: undefined, // use table default
resizable: undefined, // use table default
filterable: undefined, // use table default
show: true,
minWidth: 100,
// Cells only
render: undefined,
className: '',
style: {},
getProps: emptyObj,
// Pivot only
aggregate: undefined,
// Headers only
header: undefined,
headerClassName: '',
headerStyle: {},
getHeaderProps: emptyObj,
// Footers only
footer: undefined,
footerClassName: '',
footerStyle: {},
getFooterProps: emptyObj,
filterMethod: undefined,
hideFilter: false,
filterRender: ({filter, onFilterChange}) => (
<input type='text'
style={{
width: '100%'
}}
value={filter ? filter.value : ''}
onChange={(event) => onFilterChange(event.target.value)}
/>
)
sortMethod: undefined
},
// Global Expander Column Defaults
expanderDefaults: {
sortable: false,
resizable: false,
filterable: false,
width: 35
},
pivotDefaults: {
// extend the defaults for pivoted columns here
},
// Text
@@ -150,14 +185,35 @@ export default {
},
TdComponent: _.makeTemplateComponent('rt-td'),
TfootComponent: _.makeTemplateComponent('rt-tfoot'),
ExpanderComponent: ({isExpanded, ...rest}) => {
FilterComponent: ({filter, onChange}) => (
<input type='text'
style={{
width: '100%'
}}
value={filter ? filter.value : ''}
onChange={(event) => onChange(event.target.value)}
/>
),
ExpanderComponent: ({isExpanded}) => (
<div className={classnames('rt-expander', isExpanded && '-open')}>
&bull;
</div>
),
PivotValueComponent: ({subRows, value}) => (
<span>{value} {subRows && `(${subRows.length})`}</span>
),
AggregatedComponent: ({subRows, column}) => {
const previewValues = subRows
.filter(d => typeof d[column.id] !== 'undefined')
.map((row, i) => (
<span key={i}>{row[column.id]}{i < subRows.length - 1 ? ', ' : ''}</span>
))
return (
<div
className={classnames('rt-expander', isExpanded && '-open')}
{...rest}
>&bull;</div>
<span>{previewValues}</span>
)
},
PivotComponent: undefined, // this is a computed default generated using
// the ExpanderComponent and PivotValueComponent at run-time in methods.js
PaginationComponent: Pagination,
PreviousComponent: undefined,
NextComponent: undefined,
+324 -437
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.fireFetchData = this.fireFetchData.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,
sorted: props.defaultSorted,
expanded: props.defaultExpanded,
filtered: props.defaultFiltered,
resized: props.defaultResized,
currentlyResizing: false,
skipNextSort: false
}
}
render () {
const resolvedState = this.getResolvedState()
@@ -41,25 +72,31 @@ export default React.createClass({
getNoDataProps,
getResizerProps,
showPagination,
expanderColumnWidth,
manual,
loadingText,
noDataText,
showFilters,
sortable,
resizable,
filterable,
// Pivoting State
pivotIDKey,
pivotValKey,
pivotBy,
subRowsKey,
aggregatedKey,
originalKey,
indexKey,
groupedByPivotKey,
// State
loading,
pageSize,
page,
sorting,
filtering,
resizing,
sorted,
filtered,
resized,
expanded,
pages,
// Pivoting State
pivotValKey,
subRowsKey,
expandedRows,
onExpandRow,
onExpandedChange,
// Components
TableComponent,
TheadComponent,
@@ -69,19 +106,24 @@ export default React.createClass({
ThComponent,
TdComponent,
TfootComponent,
ExpanderComponent,
PaginationComponent,
LoadingComponent,
SubComponent,
NoDataComponent,
ResizerComponent,
ExpanderComponent,
PivotValueComponent,
PivotComponent,
AggregatedComponent,
FilterComponent,
// Data model
resolvedData,
allVisibleColumns,
headerGroups,
hasHeaderGroups,
// Sorted Data
sortedData
sortedData,
currentlyResizing
} = resolvedState
// Pagination
@@ -91,7 +133,8 @@ export default React.createClass({
const minRows = this.getMinRows()
const padRows = _.range(Math.max(minRows - pageRows.length, 0))
const hasColumnFooter = allVisibleColumns.some(d => d.footer)
const hasColumnFooter = allVisibleColumns.some(d => d.Footer)
const hasFilters = filterable || allVisibleColumns.some(d => d.filterable)
const recurseRowsViewIndex = (rows, path = [], index = -1) => {
return [
@@ -102,7 +145,7 @@ export default React.createClass({
_viewIndex: index
}
const newPath = path.concat([i])
if (rowWithViewIndex[subRowsKey] && _.get(expandedRows, newPath)) {
if (rowWithViewIndex[subRowsKey] && _.get(expanded, newPath)) {
[rowWithViewIndex[subRowsKey], index] = recurseRowsViewIndex(rowWithViewIndex[subRowsKey], newPath, index)
}
return rowWithViewIndex
@@ -117,8 +160,8 @@ export default React.createClass({
const canNext = page + 1 < pages
const rowMinWidth = _.sum(allVisibleColumns.map(d => {
const resized = resizing.find(x => x.id === d.id) || {}
return _.getFirstDefined(resized.value, d.width, d.minWidth)
const resizedColumn = resized.find(x => x.id === d.id) || {}
return _.getFirstDefined(resizedColumn.value, d.width, d.minWidth)
}))
let rowIndex = -1
@@ -162,18 +205,11 @@ export default React.createClass({
}
const makeHeaderGroup = (column, i) => {
const flex = _.sum(column.columns.map(d => {
const resized = resizing.find(x => x.id === d.id) || {}
return d.width || resized.value ? 0 : d.minWidth
}))
const width = _.sum(column.columns.map(d => {
const resized = resizing.find(x => x.id === d.id) || {}
return _.getFirstDefined(resized.value, d.width, d.minWidth)
}))
const maxWidth = _.sum(column.columns.map(d => {
const resized = resizing.find(x => x.id === d.id) || {}
return _.getFirstDefined(resized.value, d.width, d.maxWidth)
}))
const resizedValue = col => (resized.find(x => x.id === col.id) || {}).value
const flex = _.sum(column.columns.map(col => col.width || resizedValue(col) ? 0 : col.minWidth))
const width = _.sum(column.columns.map(col => _.getFirstDefined(resizedValue(col), col.width, col.minWidth)))
const maxWidth = _.sum(column.columns.map(col => _.getFirstDefined(resizedValue(col), col.width, col.maxWidth)))
const theadGroupThProps = _.splitProps(getTheadGroupThProps(finalState, undefined, column, this))
const columnHeaderProps = _.splitProps(column.getHeaderProps(finalState, undefined, column, this))
@@ -200,42 +236,9 @@ 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}
key={i + '-' + column.id}
className={classnames(
classes
)}
@@ -245,7 +248,7 @@ export default React.createClass({
}}
{...rest}
>
{_.normalizeComponent(column.header, {
{_.normalizeComponent(column.Header, {
data: sortedData,
column: column
})}
@@ -277,11 +280,11 @@ export default React.createClass({
}
const makeHeader = (column, i) => {
const resized = resizing.find(x => x.id === column.id) || {}
const sort = sorting.find(d => d.id === column.id)
const resizedCol = resized.find(x => x.id === column.id) || {}
const sort = sorted.find(d => d.id === column.id)
const show = typeof column.show === 'function' ? column.show() : column.show
const width = _.getFirstDefined(resized.value, column.width, column.minWidth)
const maxWidth = _.getFirstDefined(resized.value, column.width, column.maxWidth)
const width = _.getFirstDefined(resizedCol.value, column.width, column.minWidth)
const maxWidth = _.getFirstDefined(resizedCol.value, column.width, column.maxWidth)
const theadThProps = _.splitProps(getTheadThProps(finalState, undefined, column, this))
const columnHeaderProps = _.splitProps(column.getHeaderProps(finalState, undefined, column, this))
@@ -302,83 +305,28 @@ export default React.createClass({
...columnHeaderProps.rest
}
const resizer = resizable ? (
const isResizable = _.getFirstDefined(column.resizable, resizable, false)
const resizer = isResizable ? (
<ResizerComponent
onMouseDown={e => this.resizeColumnStart(column, e, false)}
onTouchStart={e => this.resizeColumnStart(column, e, true)}
{...resizerProps}
/>
) : null
if (column.expander) {
if (column.pivotColumns) {
const pivotSort = sorting.find(d => d.id === column.id)
return (
<ThComponent
key={i}
className={classnames(
'rt-pivot-header',
'rt-resizable-header',
column.sortable && '-cursor-pointer',
classes,
pivotSort ? (pivotSort.desc ? '-sort-desc' : '-sort-asc') : ''
)}
style={{
...styles,
flex: `${width} 0 auto`,
width: `${width}px`,
maxWidth: `${maxWidth}px`
}}
toggleSort={(e) => {
column.sortable && this.sortColumn(column.pivotColumns, e.shiftKey)
}}
{...rest}
>
<div className='rt-resizable-header-content'>
{column.pivotColumns.map((pivotColumn, i) => {
return (
<span key={pivotColumn.id}>
{_.normalizeComponent(pivotColumn.header, {
data: sortedData,
column: column
})}
{i < column.pivotColumns.length - 1 && (
<ExpanderComponent />
)}
</span>
)
})}
</div>
{resizer}
</ThComponent>
)
}
return (
<ThComponent
key={i}
className={classnames(
'rt-expander-header',
classes
)}
style={{
...styles,
flex: `0 0 auto`,
width: `${expanderColumnWidth}px`
}}
{...rest}
/>
)
}
const isSortable = _.getFirstDefined(column.sortable, sortable, false)
return (
<ThComponent
key={i}
key={i + '-' + column.id}
className={classnames(
classes,
'rt-resizable-header',
sort ? (sort.desc ? '-sort-desc' : '-sort-asc') : '',
column.sortable && '-cursor-pointer',
isSortable && '-cursor-pointer',
!show && '-hidden',
pivotBy && pivotBy.slice(0, -1).includes(column.id) && 'rt-header-pivot'
)}
style={{
...styles,
@@ -387,12 +335,12 @@ export default React.createClass({
maxWidth: `${maxWidth}px`
}}
toggleSort={(e) => {
column.sortable && this.sortColumn(column, e.shiftKey)
isSortable && this.sortColumn(column, e.shiftKey)
}}
{...rest}
>
<div className='rt-resizable-header-content'>
{_.normalizeComponent(column.header, {
{_.normalizeComponent(column.Header, {
data: sortedData,
column: column
})}
@@ -426,9 +374,9 @@ export default React.createClass({
}
const makeFilter = (column, i) => {
const resized = resizing.find(x => x.id === column.id) || {}
const width = _.getFirstDefined(resized.value, column.width, column.minWidth)
const maxWidth = _.getFirstDefined(resized.value, column.width, column.maxWidth)
const resizedCol = resized.find(x => x.id === column.id) || {}
const width = _.getFirstDefined(resizedCol.value, column.width, column.minWidth)
const maxWidth = _.getFirstDefined(resizedCol.value, column.width, column.maxWidth)
const theadFilterThProps = _.splitProps(getTheadFilterThProps(finalState, undefined, column, this))
const columnHeaderProps = _.splitProps(column.getHeaderProps(finalState, undefined, column, this))
@@ -449,74 +397,15 @@ export default React.createClass({
...columnHeaderProps.rest
}
if (column.expander) {
if (column.pivotColumns) {
const pivotCols = []
for (let i = 0; i < column.pivotColumns.length; i++) {
const col = column.pivotColumns[i]
const filter = filtering.find(filter => filter.id === column.id && filter.pivotId === col.id)
pivotCols.push(
<span key={col.id}
style={{flex: 1}}>
{!col.hideFilter ? (
_.normalizeComponent(col.filterRender,
{
col,
filter,
onFilterChange: (value) => (this.filterColumn(column, value, col))
},
defaults.column.filterRender
)
) : null}
</span>
)
if (i < column.pivotColumns.length - 1) {
pivotCols.push(<ExpanderComponent key={col.id + '-' + i} />)
}
}
return (
<ThComponent
key={i}
className={classnames(
'rt-pivot-header',
column.sortable && '-cursor-pointer',
classes
)}
style={{
...styles,
flex: `${width} 0 auto`,
width: `${width}px`,
maxWidth: `${maxWidth}px`,
display: 'flex'
}}
{...rest}
>
{pivotCols}
</ThComponent>
)
}
return (
<ThComponent
key={i}
className={classnames(
'rt-expander-header',
classes
)}
style={{
...styles,
flex: `0 0 auto`,
width: `${expanderColumnWidth}px`
}}
{...rest}
/>
)
}
const filter = filtered.find(filter => filter.id === column.id)
const filter = filtering.find(filter => filter.id === column.id)
const ResolvedFilterComponent = column.Filter || FilterComponent
const isFilterable = _.getFirstDefined(column.filterable, filterable, false)
return (
<ThComponent
key={i}
key={i + '-' + column.id}
className={classnames(
classes
)}
@@ -528,14 +417,14 @@ export default React.createClass({
}}
{...rest}
>
{!column.hideFilter ? (
_.normalizeComponent(column.filterRender,
{isFilterable ? (
_.normalizeComponent(ResolvedFilterComponent,
{
column,
filter,
onFilterChange: (value) => (this.filterColumn(column, value))
onChange: (value) => (this.filterColumn(column, value))
},
defaults.column.filterRender
defaultProps.column.Filter
)
) : null}
</ThComponent>
@@ -544,16 +433,17 @@ export default React.createClass({
const makePageRow = (row, i, path = []) => {
const rowInfo = {
row: row.__original,
rowValues: row,
index: row.__index,
original: row[originalKey],
row: row,
index: row[indexKey],
viewIndex: ++rowIndex,
level: path.length,
nestingPath: path.concat([i]),
aggregated: !!row[subRowsKey],
aggregated: row[aggregatedKey],
groupedByPivot: row[groupedByPivotKey],
subRows: row[subRowsKey]
}
const isExpanded = _.get(expandedRows, rowInfo.nestingPath)
const isExpanded = _.get(expanded, rowInfo.nestingPath)
const trGroupProps = getTrGroupProps(finalState, rowInfo, undefined, this)
const trProps = _.splitProps(getTrProps(finalState, rowInfo, undefined, this))
return (
@@ -570,10 +460,10 @@ export default React.createClass({
{...trProps.rest}
>
{allVisibleColumns.map((column, i2) => {
const resized = resizing.find(x => x.id === column.id) || {}
const resizedCol = resized.find(x => x.id === column.id) || {}
const show = typeof column.show === 'function' ? column.show() : column.show
const width = _.getFirstDefined(resized.value, column.width, column.minWidth)
const maxWidth = _.getFirstDefined(resized.value, column.width, column.maxWidth)
const width = _.getFirstDefined(resizedCol.value, column.width, column.minWidth)
const maxWidth = _.getFirstDefined(resizedCol.value, column.width, column.maxWidth)
const tdProps = _.splitProps(getTdProps(finalState, rowInfo, column, this))
const columnProps = _.splitProps(column.getProps(finalState, rowInfo, column, this))
@@ -589,96 +479,128 @@ export default React.createClass({
...columnProps.style
}
if (column.expander) {
const onTdClick = (e) => {
if (onExpandRow) {
return onExpandRow(rowInfo.nestingPath, e)
}
let newExpandedRows = _.clone(expandedRows)
if (isExpanded) {
return this.setStateWithData({
expandedRows: _.set(newExpandedRows, rowInfo.nestingPath, false)
})
}
return this.setStateWithData({
expandedRows: _.set(newExpandedRows, rowInfo.nestingPath, {})
})
}
if (column.pivotColumns) {
// Return the pivot expander cell
const PivotCell = column.pivotRender
return (
<TdComponent
key={i2}
className={classnames(
'rt-pivot',
classes
)}
style={{
...styles,
paddingLeft: rowInfo.nestingPath.length === 1 ? undefined : `${30 * (rowInfo.nestingPath.length - 1)}px`,
flex: `${width} 0 auto`,
width: `${width}px`,
maxWidth: `${maxWidth}px`
}}
{...tdProps.rest}
onClick={onTdClick}
>
{rowInfo.subRows ? (
<span>
<ExpanderComponent
isExpanded={isExpanded}
/>
{column && column.pivotRender ? (
<PivotCell
{...rowInfo}
value={rowInfo.rowValues[pivotValKey]}
/>
) : <span>{row[pivotValKey]} ({rowInfo.subRows.length})</span>}
</span>
) : SubComponent ? (
<span>
<ExpanderComponent
isExpanded={isExpanded}
/>
</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>
)
const cellInfo = {
...rowInfo,
isExpanded,
column: {...column},
value: rowInfo.row[column.id],
pivoted: column.pivoted,
expander: column.expander,
resized,
show,
width,
maxWidth,
tdProps,
columnProps,
classes,
styles
}
// Return regular cell
const value = cellInfo.value
let interactionProps
let isBranch
let isPreview
const onExpanderClick = (e) => {
let newExpanded = _.clone(expanded)
if (isExpanded) {
newExpanded = _.set(newExpanded, cellInfo.nestingPath, false)
} else {
newExpanded = _.set(newExpanded, cellInfo.nestingPath, {})
}
if (onExpandedChange) {
onExpandedChange(newExpanded, cellInfo.nestingPath, e)
}
// If expanded is being controlled, don't manage internal state
if (this.props.expanded) {
return
}
return this.setStateWithData({
expanded: newExpanded
})
}
// Default to a standard cell
let resolvedCell = _.normalizeComponent(column.Cell, cellInfo, value)
// Resolve Renderers
const ResolvedAggregatedComponent = column.Aggregated || (!column.aggregate ? AggregatedComponent : column.Cell)
const ResolvedExpanderComponent = column.Expander || ExpanderComponent
const ResolvedPivotValueComponent = column.PivotValue || PivotValueComponent
const DefaultResolvedPivotComponent = PivotComponent || (
props => (
<div>
<ResolvedExpanderComponent {...props} />
<ResolvedPivotValueComponent {...props} />
</div>
)
)
const ResolvedPivotComponent = column.Pivot || DefaultResolvedPivotComponent
// Is this cell expandable?
if (cellInfo.pivoted || cellInfo.expander) {
// Make it expandable by defualt
cellInfo.expandable = true
interactionProps = {
onClick: onExpanderClick
}
// If pivoted, has no subRows, and does not have a subComponent, do not make expandable
if (cellInfo.pivoted) {
if (!cellInfo.subRows) {
if (!SubComponent) {
cellInfo.expandable = false
interactionProps = {}
}
}
}
}
if (cellInfo.pivoted) {
// Is this column a branch?
isBranch = rowInfo.row[pivotIDKey] === column.id &&
cellInfo.subRows
// Should this column be blank?
isPreview = pivotBy.indexOf(column.id) > pivotBy.indexOf(rowInfo.row[pivotIDKey]) &&
cellInfo.subRows
// Pivot Cell Render Override
if (isBranch) {
// isPivot
resolvedCell = _.normalizeComponent(ResolvedPivotComponent, {
...cellInfo,
value: row[pivotValKey]
}, row[pivotValKey])
} else if (isPreview) {
// Show the pivot preview
resolvedCell = _.normalizeComponent(ResolvedAggregatedComponent, cellInfo, value)
} else {
resolvedCell = null
}
} else if (cellInfo.aggregated) {
resolvedCell = _.normalizeComponent(ResolvedAggregatedComponent, cellInfo, value)
}
if (cellInfo.expander) {
resolvedCell = _.normalizeComponent(ResolvedExpanderComponent, cellInfo, row[pivotValKey])
if (pivotBy) {
if (cellInfo.groupedByPivot) {
resolvedCell = null
}
if (!cellInfo.subRows && !SubComponent) {
resolvedCell = null
}
}
}
// Return the cell
return (
<TdComponent
key={i2}
key={i2 + '-' + column.id}
className={classnames(
classes,
!show && 'hidden'
!show && 'hidden',
cellInfo.expandable && 'rt-expandable',
(isBranch || isPreview) && 'rt-pivot'
)}
style={{
...styles,
@@ -687,11 +609,9 @@ export default React.createClass({
maxWidth: `${maxWidth}px`
}}
{...tdProps.rest}
{...interactionProps}
>
{_.normalizeComponent(column.render, {
...rowInfo,
value: rowInfo.rowValues[column.id]
}, rowInfo.rowValues[column.id])}
{resolvedCell}
</TdComponent>
)
})}
@@ -717,54 +637,58 @@ export default React.createClass({
<TrComponent
className={classnames(
'-padRow',
(pageRows.length + i) % 2 ? '-even' : '-odd',
trProps.className,
)}
style={trProps.style || {}}
>
{allVisibleColumns.map((column, i2) => {
const resized = resizing.find(x => x.id === column.id) || {}
const show = typeof column.show === 'function' ? column.show() : column.show
const width = _.getFirstDefined(resized.value, column.width, column.minWidth)
const maxWidth = _.getFirstDefined(resized.value, column.width, column.maxWidth)
const tdProps = _.splitProps(getTdProps(finalState, undefined, column, this))
const columnProps = _.splitProps(column.getProps(finalState, undefined, column, this))
const classes = [
tdProps.className,
column.className,
columnProps.className
]
const styles = {
...tdProps.style,
...column.style,
...columnProps.style
}
return (
<TdComponent
key={i2}
className={classnames(
classes,
!show && 'hidden'
)}
style={{
...styles,
flex: `${width} 0 auto`,
width: `${width}px`,
maxWidth: `${maxWidth}px`
}}
{...tdProps.rest}
>
&nbsp;
</TdComponent>
)
})}
{allVisibleColumns.map(makePadColumn)}
</TrComponent>
</TrGroupComponent>
)
}
const makePadColumn = (column, i) => {
const resizedCol = resized.find(x => x.id === column.id) || {}
const show = typeof column.show === 'function' ? column.show() : column.show
let width = _.getFirstDefined(resizedCol.value, column.width, column.minWidth)
let flex = width
let maxWidth = _.getFirstDefined(resizedCol.value, column.width, column.maxWidth)
const tdProps = _.splitProps(getTdProps(finalState, undefined, column, this))
const columnProps = _.splitProps(column.getProps(finalState, undefined, column, this))
const classes = [
tdProps.className,
column.className,
columnProps.className
]
const styles = {
...tdProps.style,
...column.style,
...columnProps.style
}
return (
<TdComponent
key={i + '-' + column.id}
className={classnames(
classes,
!show && 'hidden'
)}
style={{
...styles,
flex: `${flex} 0 auto`,
width: `${width}px`,
maxWidth: `${maxWidth}px`
}}
{...tdProps.rest}
>
&nbsp;
</TdComponent>
)
}
const makeColumnFooters = () => {
const tFootProps = getTfootProps(finalState, undefined, undefined, this)
const tFootTrProps = _.splitProps(getTfootTrProps(finalState, undefined, undefined, this))
@@ -784,100 +708,60 @@ export default React.createClass({
style={tFootTrProps.style}
{...tFootTrProps.rest}
>
{allVisibleColumns.map((column, i2) => {
const resized = resizing.find(x => x.id === column.id) || {}
const show = typeof column.show === 'function' ? column.show() : column.show
const width = _.getFirstDefined(resized.value, column.width, column.minWidth)
const maxWidth = _.getFirstDefined(resized.value, column.width, column.maxWidth)
const tFootTdProps = _.splitProps(getTfootTdProps(finalState, undefined, undefined, this))
const columnProps = _.splitProps(column.getProps(finalState, undefined, column, this))
const columnFooterProps = _.splitProps(column.getFooterProps(finalState, undefined, column, this))
const classes = [
tFootTdProps.className,
column.className,
columnProps.className,
columnFooterProps.className
]
const styles = {
...tFootTdProps.style,
...column.style,
...columnProps.style,
...columnFooterProps.style
}
if (column.expander) {
if (column.pivotColumns) {
return (
<TdComponent
key={i2}
className={classnames(
'rt-pivot',
classes
)}
style={{
...styles,
flex: `${width} 0 auto`,
width: `${width}px`,
maxWidth: `${maxWidth}px`
}}
{...columnProps.rest}
{...tFootTdProps.rest}
{...columnFooterProps.rest}
>
{_.normalizeComponent(column.footer)}
</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
return (
<TdComponent
key={i2}
className={classnames(
classes,
!show && 'hidden'
)}
style={{
...styles,
flex: `${width} 0 auto`,
width: `${width}px`,
maxWidth: `${maxWidth}px`
}}
{...columnProps.rest}
{...tFootTdProps.rest}
{...columnFooterProps.rest}
>
{_.normalizeComponent(column.footer, {
data: sortedData,
column: column
})}
</TdComponent>
)
})}
{allVisibleColumns.map(makeColumnFooter)}
</TrComponent>
</TfootComponent>
)
}
const makeColumnFooter = (column, i) => {
const resizedCol = resized.find(x => x.id === column.id) || {}
const show = typeof column.show === 'function' ? column.show() : column.show
const width = _.getFirstDefined(resizedCol.value, column.width, column.minWidth)
const maxWidth = _.getFirstDefined(resizedCol.value, column.width, column.maxWidth)
const tFootTdProps = _.splitProps(getTfootTdProps(finalState, undefined, undefined, this))
const columnProps = _.splitProps(column.getProps(finalState, undefined, column, this))
const columnFooterProps = _.splitProps(column.getFooterProps(finalState, undefined, column, this))
const classes = [
tFootTdProps.className,
column.className,
columnProps.className,
columnFooterProps.className
]
const styles = {
...tFootTdProps.style,
...column.style,
...columnProps.style,
...columnFooterProps.style
}
return (
<TdComponent
key={i + '-' + column.id}
className={classnames(
classes,
!show && 'hidden'
)}
style={{
...styles,
flex: `${width} 0 auto`,
width: `${width}px`,
maxWidth: `${maxWidth}px`
}}
{...columnProps.rest}
{...tFootTdProps.rest}
{...columnFooterProps.rest}
>
{_.normalizeComponent(column.Footer, {
data: sortedData,
column: column
})}
</TdComponent>
)
}
const rootProps = _.splitProps(getProps(finalState, undefined, undefined, this))
const tableProps = _.splitProps(getTableProps(finalState, undefined, undefined, this))
const tBodyProps = _.splitProps(getTbodyProps(finalState, undefined, undefined, this))
@@ -900,13 +784,16 @@ export default React.createClass({
{...rootProps.rest}
>
<TableComponent
className={classnames(tableProps.className)}
className={classnames(
tableProps.className,
currentlyResizing ? 'rt-resizing' : ''
)}
style={tableProps.style}
{...tableProps.rest}
>
{hasHeaderGroups ? makeHeaderGroups() : null}
{makeHeaders()}
{showFilters ? makeFilters() : null}
{hasFilters ? makeFilters() : null}
<TbodyComponent
className={classnames(tBodyProps.className)}
style={{
@@ -951,4 +838,4 @@ export default React.createClass({
// childProps are optionally passed to a function-as-a-child
return children ? children(finalState, makeTable, this) : makeTable()
}
})
}
+33 -1
View File
@@ -65,6 +65,31 @@ $expandSize = 7px
overflow: hidden
text-overflow: ellipsis
.rt-header-pivot
border-right-color: #f7f7f7
.rt-header-pivot:after, .rt-header-pivot:before
left: 100%
top: 50%
border: solid transparent
content: " "
height: 0
width: 0
position: absolute
pointer-events: none
.rt-header-pivot:after
border-color: rgba(255, 255, 255, 0)
border-left-color: #FFF
border-width: 8px
margin-top: -8px
.rt-header-pivot:before
border-color: rgba(102, 102, 102, 0)
border-left-color: #f7f7f7
border-width: 10px
margin-top: -10px
.rt-tbody
display: flex
flex-direction: column
@@ -77,7 +102,7 @@ $expandSize = 7px
border-right:1px solid alpha(black, .02)
&:last-child
border-right:0
.rt-pivot
.rt-expandable
cursor: pointer
.rt-tr-group
display: flex
@@ -287,3 +312,10 @@ $expandSize = 7px
border-color: #999 transparent transparent
border-style: solid
border-width: 5px 5px 2.5px
.rt-resizing
.rt-th
.rt-td
transition: none!important
cursor: col-resize
user-select none
+37 -52
View File
@@ -1,67 +1,52 @@
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()
},
this.fireFetchData()
}
componentWillReceiveProps (nextProps, nextState) {
const oldState = this.getResolvedState()
const newState = this.getResolvedState(nextProps, nextState)
if (oldState.defaultSorting !== newState.defaultSorting) {
newState.sorting = newState.defaultSorting
}
// Do a deep compare of new and old `defaultOption` and
// if they are different reset `option = defaultOption`
const defaultableOptions = ['sorted', 'filtered', 'resized', 'expanded']
defaultableOptions.forEach(x => {
const defaultName = `default${x.charAt(0).toUpperCase() + x.slice(1)}`
if (JSON.stringify(oldState[defaultName]) !== JSON.stringify(newState[defaultName])) {
newState[x] = newState[defaultName]
}
})
if ((oldState.showFilters !== newState.showFilters) ||
(oldState.showFilters !== newState.showFilters)) {
newState.filtering = newState.defaultFiltering
}
// If they change these table options, we need to reset defaults
// or else we could get into a state where the user has changed the UI
// and then disabled the ability to change it back.
// e.g. If `filterable` has changed, set `filtered = defaultFiltered`
const resettableOptions = ['sortable', 'filterable', 'resizable']
resettableOptions.forEach(x => {
if (oldState[x] !== newState[x]) {
const baseName = x.replace('able', '')
const optionName = `${baseName}ed`
const defaultName = `default${optionName.charAt(0).toUpperCase() + optionName.slice(1)}`
newState[optionName] = newState[defaultName]
}
})
// Props that trigger a data update
if (
oldState.data !== newState.data ||
oldState.columns !== newState.columns ||
oldState.pivotBy !== newState.pivotBy ||
oldState.sorting !== newState.sorting ||
oldState.showFilters !== newState.showFilters ||
oldState.filtering !== newState.filtering
oldState.sorted !== newState.sorted ||
oldState.filtered !== newState.filtered
) {
this.setStateWithData(this.getDataModel(newState))
}
},
}
setStateWithData (newState, cb) {
const oldState = this.getResolvedState()
@@ -74,9 +59,9 @@ export default {
// 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)
const keys = Object.keys(newResolvedState.expanded)
for (var i = 0; i < keys.length; i++) {
if (newResolvedState.expandedRows[keys[i]]) {
if (newResolvedState.expanded[keys[i]]) {
newResolvedState.frozen = true
break
}
@@ -87,19 +72,19 @@ export default {
// sorting model has changed, update the data
if (
(oldState.frozen && !newResolvedState.frozen) ||
oldState.sorting !== newResolvedState.sorting ||
oldState.filtering !== newResolvedState.filtering ||
oldState.sorted !== newResolvedState.sorted ||
oldState.filtered !== newResolvedState.filtered ||
oldState.showFilters !== newResolvedState.showFilters ||
(!newResolvedState.frozen && oldState.resolvedData !== newResolvedState.resolvedData)
) {
// Handle collapseOnSortingChange & collapseOnDataChange
// Handle collapseOnsortedChange & collapseOnDataChange
if (
(oldState.sorting !== newResolvedState.sorting && this.props.collapseOnSortingChange) ||
(oldState.filtering !== newResolvedState.filtering) ||
(oldState.sorted !== newResolvedState.sorted && this.props.collapseOnSortingChange) ||
(oldState.filtered !== newResolvedState.filtered) ||
(oldState.showFilters !== newResolvedState.showFilters) ||
(!newResolvedState.frozen && oldState.resolvedData !== newResolvedState.resolvedData && this.props.collapseOnDataChange)
) {
newResolvedState.expandedRows = {}
newResolvedState.expanded = {}
}
Object.assign(newResolvedState, this.getSortedData(newResolvedState))
+256 -164
View File
@@ -1,6 +1,17 @@
import React from 'react'
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 +20,11 @@ export default {
pivotIDKey,
pivotValKey,
subRowsKey,
expanderColumnWidth,
aggregatedKey,
nestingLevelKey,
originalKey,
indexKey,
groupedByPivotKey,
SubComponent
} = newState
@@ -21,43 +36,33 @@ export default {
}
})
// Build Header Groups
const headerGroups = []
let currentSpan = []
let columnsWithExpander = [...columns]
// 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 = []
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)
}
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
// If we have SubComponent's we need to make sure we have an expander column
if (SubComponent && !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 (column.expander) {
dcol = {
...this.props.column,
...this.props.expanderDefaults,
...column
}
} else {
dcol = {
...this.props.column,
...column
}
}
if (typeof dcol.accessor === 'string') {
@@ -121,20 +126,53 @@ export default {
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
// Find any custom pivot location
const pivotIndex = visibleColumns.findIndex(col => col.pivot)
// Handle Pivot Columns
if (pivotBy.length) {
// Retrieve the pivot columns in the correct pivot order
const pivotColumns = []
for (var i = 0; i < allDecoratedColumns.length; i++) {
if (pivotBy.indexOf(allDecoratedColumns[i].id) > -1) {
pivotColumns.push(allDecoratedColumns[i])
pivotBy.forEach(pivotID => {
const found = allDecoratedColumns.find(d => d.id === pivotID)
if (found) {
pivotColumns.push(found)
}
})
let pivotColumnGroup = {
header: () => <strong>Group</strong>,
columns: pivotColumns.map(col => ({
...this.props.pivotDefaults,
...col,
pivoted: true
}))
}
const pivotColumn = {
...pivotColumns[0],
pivotColumns,
expander: true
// Place the pivotColumns back into the visibleColumns
if (pivotIndex >= 0) {
pivotColumnGroup = {
...visibleColumns[pivotIndex],
...pivotColumnGroup
}
visibleColumns.splice(pivotIndex, 1, pivotColumnGroup)
} else {
visibleColumns.unshift(pivotColumnGroup)
}
visibleColumns[expanderColumnIndex] = pivotColumn
}
// Build Header Groups
const headerGroups = []
let currentSpan = []
// A convenience function to add a header and reset the currentSpan
const addHeader = (columns, column) => {
headerGroups.push({
...this.props.column,
...column,
columns: columns
})
currentSpan = []
}
// Build flast list of allVisibleColumns and HeaderGroups
@@ -155,17 +193,23 @@ export default {
}
// Access the data
let resolvedData = data.map((d, i) => {
const accessRow = (d, i, level = 0) => {
const row = {
__original: d,
__index: i
[originalKey]: d,
[indexKey]: i,
[subRowsKey]: d[subRowsKey],
[nestingLevelKey]: level
}
allDecoratedColumns.forEach(column => {
if (column.expander) return
row[column.id] = column.accessor(d)
})
if (row[subRowsKey]) {
row[subRowsKey] = row[subRowsKey].map((d, i) => accessRow(d, i, level + 1))
}
return row
})
}
let resolvedData = data.map((d, i) => accessRow(d, i))
// If pivoting, recursively group the data
const aggregate = (rows) => {
@@ -176,11 +220,10 @@ export default {
})
return aggregationValues
}
let standardColumns = pivotBy.length ? allVisibleColumns.slice(1) : allVisibleColumns
const aggregatingColumns = standardColumns.filter(d => d.aggregate)
let pivotColumn
// TODO: Make it possible to fabricate nested rows without pivoting
const aggregatingColumns = allVisibleColumns.filter(d => !d.expander && d.aggregate)
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) {
@@ -194,7 +237,9 @@ export default {
[pivotIDKey]: keys[i],
[pivotValKey]: key,
[keys[i]]: key,
[subRowsKey]: value
[subRowsKey]: value,
[nestingLevelKey]: i,
[groupedByPivotKey]: true
}
})
// Recurse into the subRows
@@ -203,6 +248,7 @@ export default {
return {
...rowGroup,
[subRowsKey]: subRows,
[aggregatedKey]: true,
...aggregate(subRows)
}
})
@@ -214,53 +260,79 @@ export default {
return {
...newState,
resolvedData,
pivotColumn,
allVisibleColumns,
headerGroups,
allDecoratedColumns,
hasHeaderGroups
}
},
}
getSortedData (resolvedState) {
const {
manual,
sorting,
filtering,
showFilters,
sorted,
filtered,
defaultFilterMethod,
resolvedData,
allVisibleColumns
allVisibleColumns,
allDecoratedColumns
} = resolvedState
const sortMethodsByColumnID = {}
allDecoratedColumns
.filter(col => col.sortMethod)
.forEach(col => {
sortMethodsByColumnID[col.id] = col.sortMethod
})
// Resolve the data from either manual data or sorted data
return {
sortedData: manual ? resolvedData : this.sortData(this.filterData(resolvedData, showFilters, filtering, defaultFilterMethod, allVisibleColumns), sorting)
sortedData: manual ? resolvedData : this.sortData(
this.filterData(
resolvedData,
filtered,
defaultFilterMethod,
allVisibleColumns
),
sorted,
sortMethodsByColumnID
)
}
},
fireOnChange () {
this.props.onChange(this.getResolvedState(), this)
},
}
fireFetchData () {
this.props.onFetchData(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) {
}
filterData (data, filtered, defaultFilterMethod, allVisibleColumns) {
let filteredData = data
if (showFilters && filtering.length) {
filteredData = filtering.reduce(
if (filtered.length) {
filteredData = filtered.reduce(
(filteredSoFar, nextFilter) => {
return filteredSoFar.filter(
(row) => {
let column
if (nextFilter.pivotId) {
const parentColumn = allVisibleColumns.find(x => x.id === nextFilter.id)
column = parentColumn.pivotColumns.find(x => x.id === nextFilter.pivotId)
} else {
column = allVisibleColumns.find(x => x.id === nextFilter.id)
column = allVisibleColumns.find(x => x.id === nextFilter.id || (x.pivotColumns && x.pivotColumns.some(y => y.id === nextFilter.id)))
// Could possibly be in pivotColumns
if (column.id !== nextFilter.id && column.pivotColumns) {
column = column.pivotColumns.find(x => x.id === nextFilter.id)
}
// Don't filter hidden columns or columns that have had their filters disabled
if (!column || column.filterable === false) {
return true
}
const filterMethod = column.filterMethod || defaultFilterMethod
@@ -279,7 +351,7 @@ export default {
}
return {
...row,
[this.props.subRowsKey]: this.filterData(row[this.props.subRowsKey], showFilters, filtering, defaultFilterMethod, allVisibleColumns)
[this.props.subRowsKey]: this.filterData(row[this.props.subRowsKey], filtered, defaultFilterMethod, allVisibleColumns)
}
}).filter(row => {
if (!row[this.props.subRowsKey]) {
@@ -290,52 +362,62 @@ export default {
}
return filteredData
},
sortData (data, sorting) {
if (!sorting.length) {
}
sortData (data, sorted, sortMethodsByColumnID = {}) {
if (!sorted.length) {
return data
}
const sorted = _.orderBy(data, sorting.map(sort => {
return row => {
if (row[sort.id] === null || row[sort.id] === undefined) {
return -Infinity
const sortedData = (this.props.orderByMethod || _.orderBy)(
data,
sorted.map(sort => {
// Support custom sorting methods for each column
if (sortMethodsByColumnID[sort.id]) {
return (a, b) => {
return sortMethodsByColumnID[sort.id](a[sort.id], b[sort.id])
}
}
return typeof row[sort.id] === 'string' ? row[sort.id].toLowerCase() : row[sort.id]
}
}), sorting.map(d => !d.desc))
return (a, b) => {
return this.props.defaultSortMethod(a[sort.id], b[sort.id])
}
}),
sorted.map(d => !d.desc),
this.props.indexKey
)
return sorted.map(row => {
sortedData.forEach(row => {
if (!row[this.props.subRowsKey]) {
return row
}
return {
...row,
[this.props.subRowsKey]: this.sortData(row[this.props.subRowsKey], sorting)
return
}
row[this.props.subRowsKey] = this.sortData(row[this.props.subRowsKey], sorted, sortMethodsByColumnID)
})
},
return sortedData
}
getMinRows () {
return _.getFirstDefined(this.props.minRows, this.getStateOrProp('pageSize'))
},
}
// User actions
onPageChange (page) {
const {onPageChange, collapseOnPageChange} = this.props
if (onPageChange) {
return onPageChange(page)
onPageChange && onPageChange(page)
// If controlled, do not keep track of state
if (typeof this.props.page !== 'undefined') {
this.fireFetchData()
return
}
const newState = {page}
if (collapseOnPageChange) {
newState.expandedRows = {}
newState.expanded = {}
}
this.setStateWithData(
newState
, () => {
this.fireOnChange()
})
},
this.setStateWithData(newState, () => {
this.fireFetchData()
})
}
onPageSizeChange (newPageSize) {
const {onPageSizeChange} = this.props
const {pageSize, page} = this.getResolvedState()
@@ -344,19 +426,22 @@ export default {
const currentRow = pageSize * page
const newPage = Math.floor(currentRow / newPageSize)
if (onPageSizeChange) {
return onPageSizeChange(newPageSize, newPage)
onPageSizeChange && onPageSizeChange(newPageSize, newPage)
if (typeof this.props.page !== 'undefined') {
this.fireFetchData()
return
}
this.setStateWithData({
pageSize: newPageSize,
page: newPage
}, () => {
this.fireOnChange()
this.fireFetchData()
})
},
}
sortColumn (column, additive) {
const {sorting, skipNextSort} = this.getResolvedState()
const {sorted, skipNextSort} = this.getResolvedState()
// we can't stop event propagation from the column resize move handlers
// attached to the document because of react's synthetic events
@@ -369,40 +454,38 @@ export default {
return
}
const {onSortingChange} = this.props
if (onSortingChange) {
return onSortingChange(column, additive)
}
let newSorting = _.clone(sorting || []).map(d => {
const {onSortedChange} = this.props
let newSorted = _.clone(sorted || []).map(d => {
d.desc = _.isSortingDesc(d)
return d
})
if (!_.isArray(column)) {
// Single-Sort
const existingIndex = newSorting.findIndex(d => d.id === column.id)
const existingIndex = newSorted.findIndex(d => d.id === column.id)
if (existingIndex > -1) {
const existing = newSorting[existingIndex]
const existing = newSorted[existingIndex]
if (existing.desc) {
if (additive) {
newSorting.splice(existingIndex, 1)
newSorted.splice(existingIndex, 1)
} else {
existing.desc = false
newSorting = [existing]
newSorted = [existing]
}
} else {
existing.desc = true
if (!additive) {
newSorting = [existing]
newSorted = [existing]
}
}
} else {
if (additive) {
newSorting.push({
newSorted.push({
id: column.id,
desc: false
})
} else {
newSorting = [{
newSorted = [{
id: column.id,
desc: false
}]
@@ -410,90 +493,89 @@ export default {
}
} else {
// Multi-Sort
const existingIndex = newSorting.findIndex(d => d.id === column[0].id)
const existingIndex = newSorted.findIndex(d => d.id === column[0].id)
// Existing Sorted Column
if (existingIndex > -1) {
const existing = newSorting[existingIndex]
const existing = newSorted[existingIndex]
if (existing.desc) {
if (additive) {
newSorting.splice(existingIndex, column.length)
newSorted.splice(existingIndex, column.length)
} else {
column.forEach((d, i) => {
newSorting[existingIndex + i].desc = false
newSorted[existingIndex + i].desc = false
})
}
} else {
column.forEach((d, i) => {
newSorting[existingIndex + i].desc = true
newSorted[existingIndex + i].desc = true
})
}
if (!additive) {
newSorting = newSorting.slice(existingIndex, column.length)
newSorted = newSorted.slice(existingIndex, column.length)
}
} else {
// New Sort Column
if (additive) {
newSorting = newSorting.concat(column.map(d => ({
newSorted = newSorted.concat(column.map(d => ({
id: d.id,
desc: false
})))
} else {
newSorting = column.map(d => ({
newSorted = column.map(d => ({
id: d.id,
desc: false
}))
}
}
}
this.setStateWithData({
page: ((!sorting.length && newSorting.length) || !additive) ? 0 : this.state.page,
sorting: newSorting
}, () => {
this.fireOnChange()
})
},
filterColumn (column, value, pivotColumn) {
const {filtering} = this.getResolvedState()
const {onFilteringChange} = this.props
if (onFilteringChange) {
return onFilteringChange(column, value, pivotColumn)
// If controlled, do not keep track of state
onSortedChange && onSortedChange(newSorted, column, additive)
if (typeof this.props.sorted !== 'undefined') {
this.fireFetchData()
return
}
this.setStateWithData({
page: ((!sorted.length && newSorted.length) || !additive) ? 0 : this.state.page,
sorted: newSorted
}, () => {
this.fireFetchData()
})
}
filterColumn (column, value) {
const {filtered} = this.getResolvedState()
const {onFilteredChange} = this.props
// Remove old filter first if it exists
const newFiltering = (filtering || []).filter(x => {
const newFiltering = (filtered || []).filter(x => {
if (x.id !== column.id) {
return true
}
if (x.pivotId) {
if (pivotColumn) {
return x.pivotId !== pivotColumn.id
}
return true
}
})
if (value !== '') {
newFiltering.push({
id: column.id,
value: value,
pivotId: pivotColumn ? pivotColumn.id : undefined
value: value
})
}
this.setStateWithData({
filtering: newFiltering
}, () => {
this.fireOnChange()
})
},
resizeColumnStart (column, event, isTouch) {
const {onResize} = this.props
onFilteredChange && onFilteredChange(newFiltering, column, value)
if (onResize) {
return onResize(column, event, isTouch)
// If filters is being controlled, do not manage state internally
if (this.props.filtered) {
this.fireFetchData()
return
}
this.setStateWithData({
filtered: newFiltering
}, () => {
this.fireFetchData()
})
}
resizeColumnStart (column, event, isTouch) {
const parentWidth = event.target.parentElement.getBoundingClientRect().width
let pageX
@@ -520,7 +602,8 @@ export default {
document.addEventListener('mouseleave', this.resizeColumnEnd)
}
})
},
}
resizeColumnEnd (event) {
let isTouch = event.type === 'touchend' || event.type === 'touchcancel'
@@ -541,15 +624,18 @@ export default {
// event resize will not sort the column.
if (!isTouch) {
this.setStateWithData({
skipNextSort: true
skipNextSort: true,
currentlyResizing: false
})
}
},
}
resizeColumnMoving (event) {
const {resizing, currentlyResizing} = this.getResolvedState()
const {onResizedChange} = this.props
const {resized, currentlyResizing} = this.getResolvedState()
// Delete old value
const newResizing = resizing.filter(x => x.id !== currentlyResizing.id)
const newResized = resized.filter(x => x.id !== currentlyResizing.id)
let pageX
@@ -562,13 +648,19 @@ export default {
// Set the min size to 10 to account for margin and border or else the group headers don't line up correctly
const newWidth = Math.max(currentlyResizing.parentWidth + pageX - currentlyResizing.startX, 11)
newResizing.push({
newResized.push({
id: currentlyResizing.id,
value: newWidth
})
onResizedChange && onResizedChange(newResized, event)
if (this.props.resized) {
return
}
this.setStateWithData({
resizing: newResizing
resized: newResized
})
}
}
+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>
)
}
})
}
+8 -11
View File
@@ -64,23 +64,20 @@ function range (n) {
return arr
}
function orderBy (arr, funcs, dirs) {
return arr.sort((a, b) => {
function orderBy (arr, funcs, dirs, indexKey) {
return arr.sort((rowA, rowB) => {
for (let i = 0; i < funcs.length; i++) {
const comp = funcs[i]
const ca = comp(a)
const cb = comp(b)
const desc = dirs[i] === false || dirs[i] === 'desc'
if (ca > cb) {
return desc ? -1 : 1
}
if (ca < cb) {
return desc ? 1 : -1
const sortInt = comp(rowA, rowB)
if (sortInt) {
return desc ? -sortInt : sortInt
}
}
// Use the row index for tie breakers
return dirs[0]
? a.__index - b.__index
: b.__index - a.__index
? rowA[indexKey] - rowB[indexKey]
: rowB[indexKey] - rowA[indexKey]
})
}
+89 -152
View File
@@ -2,170 +2,107 @@ 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'
}
})
class Story extends React.Component {
render () {
const data = _.map(_.range(5553), d => {
const statusChance = Math.random()
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
progress: Math.floor(Math.random() * 100),
status: statusChance > 0.66 ? 'relationship'
: statusChance > 0.33 ? 'complicated'
: 'single'
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
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: 'Profile Progress',
accessor: 'progress',
render: row => (
<div
style={{
width: '100%',
height: '100%',
backgroundColor: '#dadada',
borderRadius: '2px'
}}
>
Header: 'Info',
columns: [{
Header: 'Profile Progress',
accessor: 'progress',
Cell: row => (
<div
style={{
width: `${row.value}%`,
width: '100%',
height: '100%',
backgroundColor: row.value > 66 ? '#85cc00'
: row.value > 33 ? '#ffbf00'
: '#ff2e00',
borderRadius: '2px',
transition: 'all .2s ease-out'
backgroundColor: '#dadada',
borderRadius: '2px'
}}
>
<div
style={{
width: `${row.value}%`,
height: '100%',
backgroundColor: row.value > 66 ? '#85cc00'
: row.value > 33 ? '#ffbf00'
: '#ff2e00',
borderRadius: '2px',
transition: 'all .2s ease-out'
}}
/>
</div>
)
}, {
Header: 'Status',
accessor: 'status',
Cell: row => (
<span>
<span style={{
color: row.value === 'relationship' ? '#ff2e00'
: row.value === 'complicated' ? '#ffbf00'
: '#57d500',
transition: 'all .3s ease'
}}>
&#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>
)
}, {
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 style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</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 `
import ReactTable from 'react-table'
// Source Code
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw-loader!./CellRenderers')
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
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
/>
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
`
}
+38 -103
View File
@@ -2,7 +2,6 @@ import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
const data = _.map(_.range(5553), d => {
@@ -14,48 +13,36 @@ const data = _.map(_.range(5553), d => {
})
const columns = [{
header: 'Name',
Header: 'Name',
columns: [{
header: 'First Name',
Header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
Header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
Header: 'Info',
columns: [{
header: 'Age',
Header: 'Age',
accessor: 'age'
}]
}]
class ControlledTable extends React.Component {
constructor() {
class Story extends React.Component {
constructor () {
super()
this.sortChange = this.sortChange.bind(this)
this.state = {
sorting: [],
sorted: [],
page: 0,
pageSize: 10
pageSize: 10,
expanded: {},
resized: [],
filtered: []
}
}
sortChange(column, shift) {
if(shift)
alert('Shift click not implemented in this demo')
var sort = {id: column.id}
if(this.state.sorting.length && this.state.sorting[0].id == column.id)
this.state.sorting[0].asc ? sort.desc = true : sort.asc = true
else
sort.asc = true
this.setState({
sorting: [sort]
})
}
render() {
render () {
return (
<div>
<div className='table-wrap'>
@@ -63,91 +50,39 @@ class ControlledTable extends React.Component {
className='-striped -highlight'
data={data}
columns={columns}
sorting={this.state.sorting}
onSortingChange={this.sortChange}
pivotBy={['lastName']}
filterable
// Controlled Props
sorted={this.state.sorted}
page={this.state.page}
onPageChange={page => this.setState({page})}
pageSize={this.state.pageSize}
expanded={this.state.expanded}
resized={this.state.resized}
filtered={this.state.filtered}
// Callbacks
onSortedChange={sorted => this.setState({sorted})}
onPageChange={page => this.setState({page})}
onPageSizeChange={(pageSize, page) => this.setState({page, pageSize})}
onExpandedChange={expanded => this.setState({expanded})}
onResizedChange={resized => this.setState({resized})}
onFilteredChange={filtered => this.setState({filtered})}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: For simplicity, multi-sort is not implemented in this demo</em>
</div>
<CodeHighlight>{() => getCode()}</CodeHighlight>
<br />
<pre><code><strong>this.state ===</strong> {JSON.stringify(this.state, null, 2)}</code></pre>
<br />
</div>
)
}
}
function getCode () {
return `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)
}
})
// Source Code
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw-loader!./ControlledTable')
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
}]
}]
class ControlledTable extends React.Component {
constructor() {
super()
this.sortChange = this.sortChange.bind(this)
this.state = {
sorting: [],
page: 0,
pageSize: 10
}
}
sortChange(column, shift) {
if(shift)
alert('Shift click not implemented in this demo')
var sort = {id: column.id}
if(this.state.sorting.length && this.state.sorting[0].id == column.id)
this.state.sorting[0].asc ? sort.desc = true : sort.asc = true
else
sort.asc = true
this.setState({
sorting: [sort]
})
}
render() {
return (
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
sorting={this.state.sorting}
onSortingChange={this.sortChange}
page={this.state.page}
onPageChange={page => this.setState({page})}
pageSize={this.state.pageSize}
onPageSizeChange={(pageSize, page) => this.setState({page, pageSize})}
/>
)
}
}`
}
export default () => <ControlledTable />
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
+66 -97
View File
@@ -2,105 +2,74 @@ 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) => {
class Story extends React.Component {
render () {
const data = _.map(_.range(5553), d => {
return {
onMouseEnter: e => console.log('Cell - onMouseEnter', {
state,
rowInfo,
column,
instance,
event: e
})
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30)
}
}}
/>
)
`
})
const columns = [{
Header: 'Name',
columns: [{
Header: 'First Name',
accessor: 'firstName'
}, {
Header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
Header: 'Info',
columns: [{
Header: 'Age',
accessor: 'age'
}]
}]
return (
<div>
<strong>Hey!</strong> Open your console! :)
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
getTdProps={(state, rowInfo, column, instance) => {
return {
onMouseEnter: e => console.log('Cell - onMouseEnter', {
state,
rowInfo,
column,
instance,
event: e
})
}
}}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
</div>
)
}
}
// Source Code
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw-loader!./CustomComponentProps')
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
+65 -91
View File
@@ -2,105 +2,79 @@ 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>
class Story extends React.Component {
render () {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({words: 1, numLen: 0}),
lastName: namor.generate({words: 1, numLen: 0}),
age: Math.floor(Math.random() * 30)
}
})
const columns = [{
Header: 'Name',
columns: [{
Header: 'First Name',
accessor: 'firstName',
Footer: () => <div style={{textAlign: 'center'}}>First Name</div>
}, {
Header: 'Last Name',
accessor: 'lastName',
Footer: () => <div style={{textAlign: 'center'}}>Last Name</div>
}]
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
Header: 'Info',
columns: [{
Header: 'Age',
accessor: 'age',
Footer: () => <div style={{textAlign: 'center'}}>Age</div>
}]
}, {
Header: 'Expand',
columns: [{
expander: true,
Header: () => (<strong>More</strong>),
width: 65,
Expander: ({isExpanded, ...rest}) => (
<div>
{isExpanded ? <span>&#x2299;</span> : <span>&#x2295;</span>}
</div>
),
style: {cursor: 'pointer', fontSize: 25, padding: '0', textAlign: 'center', userSelect: 'none'},
Footer: () => <span>&hearts;</span>
}]
}]
}, {
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>}
/>
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
SubComponent={() => <span>Hello</span>}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
</div>
<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'
// Source Code
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw-loader!./CustomExpanderPosition')
// 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>}
/>
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
`
}
+77
View File
@@ -0,0 +1,77 @@
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import ReactTable from '../src/index'
class Story extends React.Component {
render () {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30)
}
})
const columns = [{
Header: 'Name',
columns: [{
Header: 'First Name (Sorted by Length, A-Z)',
accessor: 'firstName',
sortMethod: (a, b) => {
if (a.length === b.length) {
return a > b ? 1 : -1
}
return a.length > b.length ? 1 : -1
}
}, {
Header: 'Last Name (Sorted in reverse, A-Z)',
id: 'lastName',
accessor: d => d.lastName,
sortMethod: (a, b) => {
if (a === b) {
return 0
}
const aReverse = a.split('').reverse().join('')
const bReverse = b.split('').reverse().join('')
return aReverse > bReverse ? 1 : -1
}
}]
}, {
Header: 'Info',
columns: [{
Header: 'Age',
accessor: 'age'
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
</div>
)
}
}
// Source Code
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw-loader!./CustomSorting')
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
+51 -76
View File
@@ -2,90 +2,65 @@ 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)
}
})
class Story extends React.Component {
render () {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30)
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName',
maxWidth: 200
const columns = [{
Header: 'Name',
columns: [{
Header: 'First Name',
accessor: 'firstName',
maxWidth: 200
}, {
Header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName,
width: 300
}]
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName,
width: 300
Header: 'Info',
columns: [{
Header: 'Age',
accessor: 'age',
minWidth: 400
}]
}]
}, {
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}
/>
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
</div>
<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'
// Source Code
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw-loader!./CustomWidths')
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}
/>
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
`
}
+53 -77
View File
@@ -2,90 +2,66 @@ 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)
}
})
class Story extends React.Component {
render () {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30)
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
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
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
defaultSorting={[{
id: 'age',
desc: true
}]}
/>
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
defaultSorted={[{
id: 'age',
desc: true
}]}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
</div>
<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'
}]
}]
// Source Code
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw-loader!./DefaultSorting')
return (
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
defaultSorting={[{
id: 'age',
desc: true
}]}
/>
)
`
}
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
+69
View File
@@ -0,0 +1,69 @@
import React from 'react'
import ReactTable from '../src/index'
class Story extends React.Component {
constructor (props, context) {
super(props, context)
this.renderEditable = this.renderEditable.bind(this)
this.state = {
data: [
{ firstName: 'Lucy', lastName: 'Marks' },
{ firstName: 'Bejamin', lastName: 'Pike' }
]
}
this.columns = [
{
Header: 'First Name',
accessor: 'firstName',
Cell: this.renderEditable
},
{
Header: 'Last Name',
accessor: 'lastName',
Cell: this.renderEditable
},
{
Header: 'Full Name',
id: 'full',
accessor: d => d.firstName + ' ' + d.lastName
}
]
}
renderEditable (cellInfo) {
return (<div style={{ backgroundColor: '#fafafa' }} contentEditable suppressContentEditableWarning onBlur={(e) => {
const data = [...this.state.data]
data[cellInfo.index][cellInfo.column.id] = e.target.textContent
this.setState({data: data})
}}>{this.state.data[cellInfo.index][cellInfo.column.id]}</div>)
}
render () {
return (
<div className='table-wrap' style={{marginBottom: '20px'}}>
<p>First two columns are editable just by clicking into them using the <code>contentEditable</code> attribute. Last column (Full Name) is computed from the first two.</p>
<ReactTable
data={this.state.data}
columns={this.columns}
defaultPageSize={2}
showPageSizeOptions={false}
showPagination={false}
/>
</div>
)
}
}
// Source Code
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw-loader!./EditableTable')
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
+51 -122
View File
@@ -3,10 +3,10 @@ import _ from 'lodash'
import namor from 'namor'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
class Filtering extends React.Component {
class Story extends React.Component {
constructor (props) {
super(props)
@@ -28,7 +28,9 @@ class Filtering extends React.Component {
collapseOnPageChange: true,
collapseOnDataChange: true,
freezeWhenExpanded: false,
showFilters: true
filterable: true,
sortable: true,
resizable: true
},
data: data
}
@@ -38,27 +40,27 @@ class Filtering extends React.Component {
render () {
const columns = [{
header: 'Name',
Header: 'Name',
columns: [{
header: 'First Name',
Header: 'First Name',
accessor: 'firstName',
filterMethod: (filter, row) => (row[filter.id].startsWith(filter.value) && row[filter.id].endsWith(filter.value))
}, {
header: 'Last Name',
Header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName,
filterMethod: (filter, row) => (row[filter.id].includes(filter.value))
}]
}, {
header: 'Info',
Header: 'Info',
columns: [{
header: 'Age',
Header: 'Age',
accessor: 'age'
}, {
header: 'Over 21',
Header: 'Over 21',
accessor: 'age',
id: 'over',
render: ({value}) => (value >= 21 ? 'Yes' : 'No'),
Cell: ({value}) => (value >= 21 ? 'Yes' : 'No'),
filterMethod: (filter, row) => {
if (filter.value === 'all') {
return true
@@ -68,14 +70,15 @@ class Filtering extends React.Component {
}
return row[filter.id] < 21
},
filterRender: ({filter, onFilterChange}) => (
Filter: ({filter, onChange}) => (
<select
onChange={event => onFilterChange(event.target.value)}
onChange={event => onChange(event.target.value)}
style={{width: '100%'}}
value={filter ? filter.value : 'all'}>
<option value="all"></option>
<option value="true">Can Drink</option>
<option value="false">Can't Drink</option>
value={filter ? filter.value : 'all'}
>
<option value='all' />
<option value='true'>Can Drink</option>
<option value='false'>Can't Drink</option>
</select>
)
}
@@ -88,23 +91,23 @@ class Filtering extends React.Component {
<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>
)
})
}
{
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>
@@ -148,21 +151,20 @@ class Filtering extends React.Component {
<div>
<h1>Custom Filters In This Example</h1>
<p>The default filter for all columns of a table if it is not specified in the configuration is set to match
on values that start with the filter text. Example: age.startsWith("2").</p>
on values that start with the filter text. Example: age.startsWith("2").</p>
<p>This example overrides the default filter behavior by setting
the <strong>defaultFilterMethod</strong> table option to match on values that are exactly equal to the
filter text. Example: age == "23")</p>
filter text. Example: age == "23")</p>
<p>Each column can also be customized with the column <strong>filterMethod</strong> option:</p>
<p>In this example the firstName column filters on the value starting with and ending with the filter
value.</p>
value.</p>
<p>In this example the lastName column filters on the value including the filter value anywhere in its
text.</p>
<p>To completely override the filter that is shown, you can set the <strong>filterRender</strong> column
text.</p>
<p>To completely override the filter that is shown, you can set the <strong>Filter</strong> column
option. Using this option you can specify the JSX that is shown. The option is passed
an <strong>onFilterChange</strong> method that must be called with the value that you wan't to
an <strong>onChange</strong> method that must be called with the value that you wan't to
pass to the <strong>filterMethod</strong> option whenever the filter has changed.</p>
</div>
<CodeHighlight>{() => this.getCode()}</CodeHighlight>
</div>
)
}
@@ -178,87 +180,14 @@ class Filtering extends React.Component {
}
})
}
getCode () {
return `
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName',
filterMethod: (filter, row) => (row[filter.id].startsWith(filter.value) && row[filter.id].endsWith(filter.value))
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName,
filterMethod: (filter, row) => (row[filter.id].includes(filter.value))
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
}, {
header: 'Over 21',
accessor: 'age',
id: 'over',
render: ({value}) => (value >= 21 ? 'Yes' : 'No'),
filterMethod: (filter, row) => {
if (filter.value === 'all') {
return true
}
if (filter.value === 'true') {
return row[filter.id] >= 21
}
return row[filter.id] < 21
},
filterRender: ({filter, onFilterChange}) => (
<select
onChange={event => onFilterChange(event.target.value)}
style={{width: '100%'}}
value={filter ? filter.value : 'all'}>
<option value="all"></option>
<option value="true">Can Drink</option>
<option value="false">Can't Drink</option>
</select>
)
}]
}]
export default (
<ReactTable
data={data}
columns={columns}
defaultPageSize={10}
defaultFilterMethod={(filter, row) => (String(row[filter.id]) === filter.value)}
{...otherOptions}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>You can put any component you want here, even another React Table!</em>
<br />
<br />
<ReactTable
data={data}
columns={columns}
defaultPageSize={3}
showPagination={false}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>It even has access to the row data: </em>
<CodeHighlight>{() => JSON.stringify(row, null, 2)}</CodeHighlight>
</div>
)
}}
/>
</div>
)
}}
/>
)
`
}
}
export default () => <Filtering />
// Source Code
const source = require('!raw-loader!./Filtering')
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
+71 -123
View File
@@ -2,142 +2,90 @@ 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)
}
})
class Story extends React.Component {
render () {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30)
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName',
footer: (
<span><strong>Popular:</strong> {
_.first(
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.firstName
)
data, d => d.lastName
),
(d, key) => key
),
(a, b) => a.length > b.length ? a : b
)
).firstName}
</span>
)
)}
</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>
}]
}]
}, {
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}
/>
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
</div>
<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'
// Source Code
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw-loader!./Footers')
// Create some column definitions
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>
}]
}]
// Display your table!
return (
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
/>
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
`
}
+95 -132
View File
@@ -3,7 +3,6 @@ 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 = {
@@ -27,147 +26,111 @@ const JSONtheme = {
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)
}
})
class Story extends React.Component {
render () {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30)
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName',
footer: 'Footer'
const columns = [{
Header: 'Name',
columns: [{
Header: 'First Name',
accessor: 'firstName',
Footer: 'Footer'
}, {
Header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName,
Footer: 'Footer'
}]
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName,
footer: 'Footer'
Header: 'Info',
columns: [{
Header: 'Age',
accessor: 'age',
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.
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 />
<br />
<br />
<br />
<br />
<strong>Decorating the standard table output</strong>
<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 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>
)
}}
</ReactTable>
)
`}</CodeHighlight>
<br />
<br />
<br />
<br />
<strong>Need more control? This is the entire table state and component instance at your disposal!</strong>
<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 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>
)
}}
</ReactTable>
)
`}</CodeHighlight>
</div>
)
<br />
</div>
)
}
}
// Source Code
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw-loader!./FunctionalRendering')
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
+44 -80
View File
@@ -1,92 +1,56 @@
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'
class Story extends React.Component {
render () {
const columns = [{
Header: 'Name',
columns: [{
Header: 'First Name',
accessor: 'firstName'
}, {
Header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: '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
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}
/>
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={[]}
noDataText='Oh Noes!'
// noDataText={() => 'Oh Noes!'} // Supports functions
// noDataText={() => <span>Oh Noes!</span>} // Supports JSX / React Components
columns={columns}
defaultPageSize={10}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
</div>
<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'
// Source Code
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw-loader!./NoDataText')
// 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}
/>
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
`
}
+74 -126
View File
@@ -2,147 +2,95 @@ 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(100000), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30),
visits: Math.floor(Math.random() * 100)
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age',
aggregate: vals => _.round(_.mean(vals)),
render: row => {
return <span>{row.aggregated ? `${row.value} (avg)` : row.value}</span>
class Story extends React.Component {
render () {
const data = _.map(_.range(100000), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30),
visits: Math.floor(Math.random() * 100)
}
})
const columns = [{
Header: 'Name',
columns: [{
Header: 'First Name',
accessor: 'firstName'
}, {
Header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Visits',
accessor: 'visits',
aggregate: vals => _.sum(vals)
Header: 'Info',
columns: [{
Header: 'Age',
accessor: 'age',
aggregate: vals => _.round(_.mean(vals)),
Aggregated: row => {
return <span>{row.value} (avg)</span>
}
}, {
Header: 'Visits',
accessor: 'visits',
aggregate: vals => _.sum(vals)
}]
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
data={data}
columns={columns}
className='-striped -highlight'
defaultPageSize={10}
pivotBy={['firstName', 'lastName']}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>You can put any component you want here, even another React Table!</em>
<br />
<br />
<ReactTable
data={data}
columns={columns}
defaultPageSize={3}
showPagination={false}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>It even has access to the row data: </em>
<CodeHighlight>{() => JSON.stringify(row, null, 2)}</CodeHighlight>
</div>
)
}}
/>
</div>
)
}}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
<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 => _.round(_.mean(vals)),
render: row => {
return <span>{row.aggregated ? \`\${row.value} (avg)\` : row.value}</span>
}
}, {
header: 'Visits',
accessor: 'visits',
aggregate: vals => _.sum(vals)
}]
}]
return (
<ReactTable
data={data}
columns={columns}
defaultPageSize={10}
className='-striped -highlight'
pivotBy={['firstName', 'lastName']}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>You can put any component you want here, even another React Table!</em>
<br />
<br />
return (
<div>
<div className='table-wrap'>
<ReactTable
data={data}
columns={columns}
defaultPageSize={3}
showPagination={false}
className='-striped -highlight'
defaultPageSize={10}
pivotBy={['firstName', 'lastName']}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>It even has access to the row data: </em>
<CodeHighlight>{() => JSON.stringify(row, null, 2)}</CodeHighlight>
<em>You can put any component you want here, even another React Table!</em>
<br />
<br />
<ReactTable
data={data}
columns={columns}
defaultPageSize={3}
showPagination={false}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>It even has access to the row data: </em>
<CodeHighlight>{() => JSON.stringify(row, null, 2)}</CodeHighlight>
</div>
)
}}
/>
</div>
)
}}
/>
</div>
)
}}
/>
)
`
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
</div>
)
}
}
// Source Code
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw-loader!./OneHundredKRows')
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
+58 -87
View File
@@ -2,101 +2,72 @@ 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(10000), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30),
visits: Math.floor(Math.random() * 100)
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age',
aggregate: vals => _.round(_.mean(vals)),
render: row => {
return <span>{row.aggregated ? `${row.value} (avg)` : row.value}</span>
class Story extends React.Component {
render () {
const data = _.map(_.range(1000), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30),
visits: Math.floor(Math.random() * 100)
}
})
const columns = [{
Header: 'Name',
columns: [{
Header: 'First Name',
accessor: 'firstName'
}, {
Header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Visits',
accessor: 'visits',
aggregate: vals => _.sum(vals)
Header: 'Info',
columns: [{
Header: 'Age',
accessor: 'age',
aggregate: vals => _.round(_.mean(vals)),
Aggregated: row => {
return <span>{row.value} (avg)</span>
}
}, {
Header: 'Visits',
accessor: 'visits',
aggregate: vals => _.sum(vals)
}]
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
data={data}
columns={columns}
className='-striped -highlight'
defaultPageSize={10}
pivotBy={['firstName', 'lastName']}
/>
return (
<div>
<div className='table-wrap'>
<ReactTable
data={data}
columns={columns}
className='-striped -highlight'
defaultPageSize={10}
pivotBy={['firstName', 'lastName']}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
</div>
<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 => _.round(_.mean(vals)),
render: row => {
return <span>{row.aggregated ? \`\${row.value} (avg)\` : row.value}</span>
}
}, {
header: 'Visits',
accessor: 'visits',
aggregate: vals => _.sum(vals)
}]
}]
// Source Code
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw-loader!./Pivoting')
return (
<ReactTable
data={data}
columns={columns}
className='-striped -highlight'
defaultPageSize={10}
pivotBy={['firstName', 'lastName']}
/>
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
`
}
+131
View File
@@ -0,0 +1,131 @@
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import ReactTable from '../src/index'
class Story extends React.Component {
render () {
const data = _.map(_.range(1000), d => {
return {
firstName: namor.generate({words: 1, numLen: 0}),
lastName: namor.generate({words: 1, numLen: 0}),
age: Math.floor(Math.random() * 30),
visits: Math.floor(Math.random() * 100)
}
})
const columns = [{
Header: 'Name',
columns: [{
Header: 'First Name',
accessor: 'firstName',
PivotValue: ({value}) => <span style={{color: 'darkred'}}>{value}</span>
}, {
Header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName,
PivotValue: ({value}) => <span style={{color: 'darkblue'}}>{value}</span>,
Footer: () => <div style={{textAlign: 'center'}}><strong>Pivot Column Footer</strong></div>
}]
}, {
Header: 'Info',
columns: [{
Header: 'Age',
accessor: 'age',
aggregate: vals => {
return _.round(_.mean(vals))
},
Aggregated: row => <span>{row.value} (avg)</span>
}, {
Header: 'Visits',
accessor: 'visits',
aggregate: vals => _.sum(vals),
filterable: false
}]
}, {
pivot: true,
Header: () => <strong>Overridden Pivot Column Header Group</strong>
}, {
expander: true
}]
const subtableColumns = [{
Header: 'Name',
columns: [{
Header: 'First Name',
accessor: 'firstName'
}, {
Header: 'Last Name',
id: 'lastName'
}]
}, {
Header: 'Info',
columns: [{
Header: 'Age',
accessor: 'age'
}, {
Header: 'Visits',
accessor: 'visits'
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
data={data}
columns={columns}
defaultPageSize={10}
className='-striped -highlight'
pivotBy={['firstName', 'lastName']}
defaultSorted={[{id: 'firstName', desc: false}, {id: 'lastName', desc: true}]}
collapseOnSortingChange={false}
filterable
ExpanderComponent={({isExpanded, ...rest}) => (
isExpanded ? <span> &#10136; </span> : <span> &#10137; </span>
)}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>You can put any component you want here, even another React Table!</em>
<br />
<br />
<ReactTable
data={data}
columns={subtableColumns}
defaultPageSize={3}
showPagination={false}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>It even has access to the row data: </em>
<CodeHighlight>{() => JSON.stringify(row, null, 2)}</CodeHighlight>
</div>
)
}}
/>
</div>
)
}}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
</div>
)
}
}
// Source Code
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw-loader!./PivotingOptions')
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
+77 -132
View File
@@ -2,153 +2,98 @@ 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)
}
})
class Story extends React.Component {
render () {
const data = _.map(_.range(1000), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30),
visits: Math.floor(Math.random() * 100)
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
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',
aggregate: vals => _.round(_.mean(vals)),
Aggregated: row => {
return <span>{row.value} (avg)</span>
},
filterMethod: (filter, row) => (filter.value === `${row[filter.id]} (avg)`)
}, {
Header: 'Visits',
accessor: 'visits',
aggregate: vals => _.sum(vals),
filterable: false
}]
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age',
aggregate: vals => _.round(_.mean(vals)),
render: row => {
return <span>{row.aggregated ? `${row.value} (avg)` : row.value}</span>
},
filterMethod: (filter, row) => (filter.value == `${row[filter.id]} (avg)`)
}, {
header: 'Visits',
accessor: 'visits',
aggregate: vals => _.sum(vals),
hideFilter: true
}]
}]
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}
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 => _.round(_.mean(vals)),
render: row => {
return <span>{row.aggregated ? \`\${row.value} (avg)\` : row.value}</span>
},
filterMethod: (filter, row) => (filter.value == \`\${row[filter.id]} (avg)\`)
}, {
header: 'Visits',
accessor: 'visits',
aggregate: vals => _.sum(vals),
hideFilter: true
}]
}]
return (
<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 />
return (
<div>
<div className='table-wrap'>
<ReactTable
data={data}
columns={columns}
defaultPageSize={3}
showPagination={false}
defaultPageSize={10}
className='-striped -highlight'
pivotBy={['firstName', 'lastName']}
filterable
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>It even has access to the row data: </em>
<CodeHighlight>{() => JSON.stringify(row, null, 2)}</CodeHighlight>
<em>You can put any component you want here, even another React Table!</em>
<br />
<br />
<ReactTable
data={data}
columns={columns}
defaultPageSize={3}
showPagination={false}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>It even has access to the row data: </em>
<CodeHighlight>{() => JSON.stringify(row, null, 2)}</CodeHighlight>
</div>
)
}}
/>
</div>
)
}}
/>
</div>
)
}}
/>
)
`
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
</div>
)
}
}
// Source Code
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw-loader!./PivotingSubComponents')
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
+29 -85
View File
@@ -2,7 +2,6 @@ import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
const rawData = _.map(_.range(3424), d => {
@@ -14,29 +13,29 @@ const rawData = _.map(_.range(3424), d => {
})
// Now let's mock the server. It's job is simple: use the table model to sort and return the page data
const requestData = (pageSize, page, sorting, filtering) => {
const requestData = (pageSize, page, sorted, filtered) => {
return new Promise((resolve, reject) => {
// On the server, you'll likely use SQL or noSQL or some other query language to do this.
// For this mock, we'll just use lodash
let filteredData = rawData;
if (filtering.length) {
filteredData = filtering.reduce(
let filteredData = rawData
if (filtered.length) {
filteredData = filtered.reduce(
(filteredSoFar, nextFilter) => {
return filteredSoFar.filter(
(row) => {
return (row[nextFilter.id]+"").includes(nextFilter.value)
return (row[nextFilter.id] + '').includes(nextFilter.value)
})
}
, filteredData)
}
const sortedData = _.orderBy(filteredData, sorting.map(sort => {
const sortedData = _.orderBy(filteredData, sorted.map(sort => {
return row => {
if (row[sort.id] === null || row[sort.id] === undefined) {
return -Infinity
}
return typeof row[sort.id] === 'string' ? row[sort.id].toLowerCase() : row[sort.id]
}
}), sorting.map(d => d.desc ? 'desc' : 'asc'))
}), sorted.map(d => d.desc ? 'desc' : 'asc'))
// Be sure to send back the rows to be displayed and any other pertinent information, like how many pages there are total.
const res = {
@@ -49,23 +48,23 @@ const requestData = (pageSize, page, sorting, filtering) => {
})
}
const ServerSide = React.createClass({
getInitialState () {
// To handle our data server-side, we need a few things in the state to help us out:
return {
class Story extends React.Component {
constructor () {
super()
this.state = {
data: [],
pages: null,
loading: true
}
},
this.fetchData = this.fetchData.bind(this)
}
fetchData (state, instance) {
// Whenever the table model changes, or the user sorts or changes pages, this method gets called and passed the current table model.
// You can set the `loading` prop of the table to true to use the built-in one or show you're own loading bar if you want.
this.setState({loading: true})
// Request the data however you want. Here, we'll use our mocked service we created earlier
requestData(state.pageSize, state.page, state.sorting, state.filtering)
requestData(state.pageSize, state.page, state.sorted, state.filtered)
.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,
@@ -73,7 +72,7 @@ const ServerSide = React.createClass({
loading: false
})
})
},
}
render () {
return (
<div>
@@ -81,96 +80,41 @@ const ServerSide = React.createClass({
<ReactTable
className='-striped -highlight'
columns={[{
header: 'First Name',
Header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
Header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}, {
header: 'Age',
Header: 'Age',
accessor: 'age'
}]}
manual // Forces table not to paginate or sort automatically, so we can handle it server-side
defaultPageSize={10}
showFilters={true}
filterable
data={this.state.data} // Set the rows to be displayed
pages={this.state.pages} // Display the total number of pages
loading={this.state.loading} // Display the loading overlay when we need it
onChange={this.fetchData} // Request new data when things change
onFetchData={this.fetchData} // Request new data when things change
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
<CodeHighlight>{() => getCode()}</CodeHighlight>
</div>
)
}
})
}
// Source Code
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw-loader!./ServerSide')
export default () => (
<ServerSide />
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
function getCode () {
return `
import ReactTable from 'react-table'
import Axios from 'axios'
export default React.createClass({
getInitialState () {
// To handle our data server-side, we need to keep track of our table state
return {
data: [],
pages: null,
loading: true
}
},
fetchData (state, instance) {
// Whenever the table model changes (sorting, pagination, etc), 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 loading notice, or show you're own loading bar if you want.
this.setState({loading: true})
// Request the data from a server however you want! Be sure to send the bits of the table model that it may neeed.
Axios.post('mysite.com/data', {
pageSize: state.pageSize,
page: state.page,
sorting: state.sorting,
filtering: state.filtering
})
.then((res) => {
// Now update your state!
this.setState({
data: res.rows,
pages: res.pages,
loading: false
})
})
},
render () {
return (
<ReactTable
columns={[{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}, {
header: 'Age',
accessor: 'age'
}]}
manual // Forces table not to paginate or sort automatically, so we can handle it server-side
defaultPageSize={10}
showFilters={true}
data={this.state.data} // Set the rows to be displayed
pages={this.state.pages} // Display the total number of pages
loading={this.state.loading} // Display the loading overlay when we need it
onChange={this.fetchData} // Request new data when things change
/>
}
})
`
}
+54 -72
View File
@@ -2,86 +2,68 @@ 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)
}
})
class Story extends React.Component {
render () {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30),
children: _.map(_.range(10), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30)
}
})
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
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
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
/>
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
</div>
<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 CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw-loader!./Simple')
// 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
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
/>
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
`
}
+44 -93
View File
@@ -2,12 +2,10 @@ import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
class SubComponents extends React.Component {
constructor(props) {
class Story extends React.Component {
constructor (props) {
super(props)
const data = _.map(_.range(5553), d => {
@@ -28,58 +26,57 @@ class SubComponents extends React.Component {
collapseOnPageChange: true,
collapseOnDataChange: true,
freezeWhenExpanded: false,
showFilters: false
filterable: false,
sortable: true,
resizable: true
},
data: data
}
this.setTableOption = this.setTableOption.bind(this);
this.setTableOption = this.setTableOption.bind(this)
}
render() {
render () {
const columns = [{
header: 'Name',
Header: 'Name',
columns: [{
header: 'First Name',
Header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
Header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
Header: 'Info',
columns: [{
header: 'Age',
Header: 'Age',
accessor: 'age'
}]
}]
return (
<div>
<div style={{float: "left"}}>
<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>
)
})
}
{
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>
@@ -119,15 +116,14 @@ class SubComponents extends React.Component {
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
<CodeHighlight>{() => this.getCode()}</CodeHighlight>
</div>
)
}
setTableOption(event) {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
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,
@@ -135,60 +131,15 @@ class SubComponents extends React.Component {
}
})
}
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'
}]
}]
export default (
<ReactTable
data={data}
columns={columns}
defaultPageSize={10}
{...otherOptions}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>You can put any component you want here, even another React Table!</em>
<br />
<br />
<ReactTable
data={data}
columns={columns}
defaultPageSize={3}
showPagination={false}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>It even has access to the row data: </em>
<CodeHighlight>{() => JSON.stringify(row, null, 2)}</CodeHighlight>
</div>
)
}}
/>
</div>
)
}}
/>
)
`
}
}
export default () => <SubComponents/>
// Source Code
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw-loader!./SubComponents')
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
+77
View File
@@ -0,0 +1,77 @@
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import ReactTable from '../src/index'
class Story extends React.Component {
render () {
const data = _.map(_.range(5553), d => {
const children = _.map(_.range(10), d => {
const grandChildren = _.map(_.range(10), d => {
return {
age: Math.floor(Math.random() * 30)
}
})
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30),
children: grandChildren
}
})
return {
lastName: namor.generate({ words: 1, numLen: 0 }),
firstName: children.map(d => d.firstName),
age: Math.floor(Math.random() * 30),
children
}
})
const columns = [{
Header: 'Name',
columns: [{
Header: 'First Name',
accessor: 'firstName',
expander: true
}, {
Header: 'Last Name',
accessor: 'lastName'
}]
}, {
Header: 'Info',
columns: [{
Header: 'Age',
accessor: 'age'
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
subRowsKey='children'
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
</div>
)
}
}
// Source Code
const CodeHighlight = require('./components/codeHighlight').default
const source = require('!raw-loader!./SubRows')
export default () => (
<div>
<Story />
<CodeHighlight>{() => source}</CodeHighlight>
</div>
)
+20
View File
@@ -0,0 +1,20 @@
const webpack = require('webpack')
module.exports = {
entry: './lib/index.js',
output: {
filename: './react-table.js',
libraryTarget: 'umd',
library: 'ReactTable'
},
externals: {
react: {
root: 'React',
commonjs2: 'react',
commonjs: 'react',
amd: 'react'
}
},
plugins: [
new webpack.optimize.UglifyJsPlugin()
]
}
+195 -345
View File
File diff suppressed because it is too large Load Diff