Compare commits

..
2 Commits
Author SHA1 Message Date
Tanner Linsley 2fe97f921f 3.0.0 2016-10-31 01:44:13 -06:00
Tanner Linsley 9a0369ee33 Major changes for server-side data 2016-10-31 01:44:07 -06:00
57 changed files with 60391 additions and 10955 deletions
-2
View File
@@ -3,5 +3,3 @@ lib/
react-table.js
react-table.css
*.log
.idea
.DS_Store
-1
View File
@@ -1 +0,0 @@
react-table.js.org
-58
View File
@@ -1,58 +0,0 @@
import React from 'react'
import { configure, storiesOf } from '@kadira/storybook'
import './reset.css'
import './fonts.css'
import './layout.css'
import '../stories/utils/prism.css'
import 'github-markdown-css/github-markdown.css'
import '../react-table.css'
//
import Readme from '../README.md'
//
import Simple from '../stories/Simple.js'
import CellRenderers from '../stories/CellRenderers.js'
import DefaultSorting from '../stories/DefaultSorting.js'
import CustomWidths from '../stories/CustomWidths.js'
import CustomComponentProps from '../stories/CustomComponentProps.js'
import ServerSide from '../stories/ServerSide.js'
import SubComponents from '../stories/SubComponents.js'
import Pivoting from '../stories/Pivoting.js'
import PivotingSubComponents from '../stories/PivotingSubComponents.js'
import OneHundredKRows from '../stories/OneHundredKRows.js'
import FunctionalRendering from '../stories/FunctionalRendering.js'
import CustomExpanderPosition from '../stories/CustomExpanderPosition.js'
import NoDataText from '../stories/NoDataText.js'
import Footers from '../stories/Footers.js'
import Filtering from '../stories/Filtering.js'
//
configure(() => {
storiesOf('1. Docs')
.add('Readme', () => {
const ReadmeCmp = React.createClass({
render () {
return <span className='markdown-body' dangerouslySetInnerHTML={{__html: Readme}} />
},
componentDidMount () {
global.Prism.highlightAll()
}
})
return <ReadmeCmp />
})
storiesOf('2. Demos')
.add('Simple Table', Simple)
.add('Cell Renderers & Custom Components', CellRenderers)
.add('Default Sorting', DefaultSorting)
.add('Custom Column Widths', CustomWidths)
.add('Custom Component Props', CustomComponentProps)
.add('Server-side Data', ServerSide)
.add('Sub Components', SubComponents)
.add('Pivoting & Aggregation', Pivoting)
.add('Pivoting & Aggregation w/ Sub Components', PivotingSubComponents)
.add('100k Rows w/ Pivoting & Sub Components', OneHundredKRows)
.add('Functional Rendering', FunctionalRendering)
.add('Custom Expander Position', CustomExpanderPosition)
.add('Custom "No Data" Text', NoDataText)
.add('Footers', Footers)
.add('Custom Filtering', Filtering)
}, module)
-17
View File
@@ -1,17 +0,0 @@
@import url("https://fonts.googleapis.com/css?family=Open+Sans:300,600");
body {
background: #fff;
font-family: 'Open Sans', sans-serif;
font-weight: 300;
}
h1 {
font-size: 24px;
font-weight: bold;
margin-bottom: 15px;
margin-top: 5px;
}
p {
margin-bottom: 15px;
}
-7
View File
@@ -1,7 +0,0 @@
body{
padding: 20px;
}
strong {
font-weight: bold
}
-48
View File
@@ -1,48 +0,0 @@
/* http://meyerweb.com/eric/tools/css/reset/
v2.0 | 20110126
License: none (public domain)
*/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
/*ol, ul {
list-style: none;
}*/
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
-27
View File
@@ -1,27 +0,0 @@
const path = require('path')
// load the default config generator.
const genDefaultConfig = require('@kadira/storybook/dist/server/config/defaults/webpack.config.js')
module.exports = (config, env) => {
config = genDefaultConfig(config, env)
Object.assign(config, {
module: Object.assign(config.module, {
loaders: config.module.loaders.concat([{
test: /\.md$/,
loader: 'html!markdown',
include: path.resolve(__dirname, '../')
}, {
test: /\.html$/,
loader: 'html',
query: {
minimize: true
},
include: path.resolve(__dirname, '../')
}])
})
})
return config
}
+101 -537
View File
@@ -1,90 +1,39 @@
<div align="center">
<a href="https://github.com/tannerlinsley/react-table" target="\_parent"><img src="https://github.com/tannerlinsley/react-table/raw/master/media/Banner.png" alt="React Table Logo" style="width:450px;"/></a>
<br />
<br />
![react-table](https://github.com/tannerlinsley/react-table/raw/master/media/Banner.png)
</div>
# react-table
A fast, lightweight, opinionated table and datagrid built on React
# React Table
`react-table` is a **lightweight, fast and extendable datagrid** built for React
<a href="https://travis-ci.org/tannerlinsley/react-table" target="\_parent">
<img alt="" src="https://travis-ci.org/tannerlinsley/react-table.svg?branch=master" />
</a>
<a href="https://npmjs.com/package/react-table" target="\_parent">
<img alt="" src="https://img.shields.io/npm/dm/react-table.svg" />
</a>
<a href="https://react-chat-signup.herokuapp.com/" target="\_parent">
<img alt="" src="https://img.shields.io/badge/slack-react--chat-blue.svg" />
</a>
<a href="https://github.com/tannerlinsley/react-table" target="\_parent">
<img alt="" src="https://img.shields.io/github/stars/tannerlinsley/react-table.svg?style=social&label=Star" />
</a>
<a href="https://twitter.com/tannerlinsley" target="\_parent">
<img alt="" src="https://img.shields.io/twitter/follow/tannerlinsley.svg?style=social&label=Follow" />
</a>
<a href="https://cash.me/$tannerlinsley" target="\_parent">
<img alt="" src="https://img.shields.io/badge/%24-Donate-brightgreen.svg" />
</a>
[![Build Status](https://travis-ci.org/tannerlinsley/react-table.svg?branch=master)](https://travis-ci.org/tannerlinsley/react-table)
[![react-table on Slack](https://img.shields.io/badge/slack-react--table-blue.svg)](https://react-table-slack.herokuapp.com/)
## Features
- Lightweight at 7kb (and just 2kb more for styles)
- Fully customizable JSX templating
- Supports both Client-side & Server-side pagination and multi-sorting
- Column Pivoting & Aggregation
- Lightweight at 3kb (and just 2kb more for styles)
- Fully customizable JSX and callbacks for everything
- Supports both Client-side & Server-side pagination and sorting
- Minimal design & easily themeable
- 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>
## [Demo](http://react-table.zabapps.com)
## Table of Contents
- [Installation](#installation)
- [Installation](#nstallation)
- [Example](#example)
- [Data](#data)
- [Props](#props)
- [Default Props](#default-props)
- [Columns](#columns)
- [Column Header Groups](#column-header-groups)
- [Custom Cell and Header Rendering](#custom-cell-and-header-rendering)
- [Styles](#styles)
- [Custom Props](#custom-props)
- [Pivoting and Aggregation](#pivoting-and-aggregation)
- [Sub Tables and Sub Components](#sub-tables-and-sub-components)
- [Header Groups](#header-groups)
- [Server-side Data](#server-side-data)
- [Fully Controlled Component](#fully-controlled-component)
- [Functional Rendering](#functional-rendering)
- [Multi-Sort](#multi-sort)
- [Multi-sort](#multi-sort)
- [Component Overrides](#component-overrides)
- [Contributing](#contributing)
- [Scripts](#scripts)
- [Used By](#used-by)
<a name="installation"></a>
## Installation
1. Install React Table as a dependency
```bash
$ npm install react-table
# or
$ yarn add react-table
```
2. Import the `react-table` module
```javascript
// ES6
import ReactTable from 'react-table'
// ES5
var ReactTable = require('react-table').default
```
3. Import styles by including `react-table.css` anywhere on the page
```javascript
// JS (Webpack)
import 'react-table/react-table.css'
// html
<link rel="stylesheet" href="node_modules/react-table/react-table.css">
```
<a name="example"></a>
## Example
```javascript
import ReactTable from 'react-table'
@@ -102,138 +51,60 @@ const data = [{
const columns = [{
header: 'Name',
accessor: 'name' // String-based value accessors!
accessor: 'name',
}, {
header: 'Age',
accessor: 'age',
render: props => <span className='number'>{props.value}</span> // Custom cell components!
accessor: 'age'
}, {
header: 'Friend Name',
accessor: d => d.friend.name // Custom value accessors!
accessor: d => d.friend.name
}, {
header: props => <span>Friend Age</span>, // Custom header components!
header: 'Friend Age',
accessor: 'friend.age'
}]
<ReactTable
data={data}
data=[data]
columns={columns}
/>
```
<a name="data"></a>
## Data
Simply pass the `data` prop anything that resembles an array or object. Client-side sorting and pagination are built in, and your table will update gracefully as you change any props. [Server-side data](#server-side-data) is also supported!
Every React-Table instance requires you to set the `data` prop. To use client-side data, simply pass the `data` prop anything that resembles an array or object. Client-side filtering and pagination is built in, and your table will update gracefully if you change any props. [Server-side data](#server-side-data) is also supported.
## Props
These are all of the available props (and their default values) for the main `<ReactTable />` component.
<a name="default-props"></a>
## Default Props
These are the default props for the main react component `<ReactTable />`
```javascript
{
// General
data: [],
loading: false,
showPagination: true,
showPageSizeOptions: true,
pageSizeOptions: [5, 10, 20, 25, 50, 100],
defaultPageSize: 20,
showPageJump: true,
expanderColumnWidth: 35,
collapseOnSortingChange: true,
collapseOnPageChange: true,
collapseOnDataChange: true,
freezeWhenExpanded: false,
defaultSorting: [],
showFilters: false,
defaultFiltering: [],
defaultFilterMethod: (filter, row) => (row[filter.id] == filter.value),
// Controlled State Overrides (see Fully Controlled Component section)
page: undefined,
pageSize: undefined,
sorting: undefined
// Controlled State Callbacks
onExpandSubComponent: undefined,
onPageChange: undefined,
onPageSizeChange: undefined,
onSortingChange: undefined,
onFilteringChange: undefined,
// Pivoting
pivotBy: undefined,
pivotColumnWidth: 200,
pivotValKey: '_pivotVal',
pivotIDKey: '_pivotID',
subRowsKey: '_subRows',
// Pivoting State Overrides (see Fully Controlled Component section)
expandedRows: {},
// Pivoting State Callbacks
onExpandRow: undefined,
// General Callbacks
onChange: () => null,
// Classes
className: '',
style: {},
// Component decorators
getProps: () => ({}),
getTableProps: () => ({}),
getTheadGroupProps: () => ({}),
getTheadGroupTrProps: () => ({}),
getTheadGroupThProps: () => ({}),
getTheadProps: () => ({}),
getTheadTrProps: () => ({}),
getTheadThProps: () => ({}),
getTheadFilterProps: () => ({}),
getTheadFilterTrProps: () => ({}),
getTheadFilterThProps: () => ({}),
getTbodyProps: () => ({}),
getTrGroupProps: () => ({}),
getTrProps: () => ({}),
getThProps: () => ({}),
getTdProps: () => ({}),
getTfootProps: () => ({}),
getTfootTrProps: () => ({}),
getTfootThProps: () => ({}),
getPaginationProps: () => ({}),
getLoadingProps: () => ({}),
getNoDataProps: () => ({}),
// Global Column Defaults
column: {
sortable: true,
show: true,
minWidth: 100,
// Cells only
render: undefined,
className: '',
style: {},
getProps: () => ({}),
// Headers only
header: undefined,
headerClassName: '',
headerStyle: {},
getHeaderProps: () => ({})
// Footers only
footer: undefined,
footerClassName: '',
footerStyle: {},
getFooterProps: () => ({}),
filterMethod: undefined
},
pageSize: 20,
minRows: 0, // Ensure this many rows are always rendered, regardless of rows on page
// Text
previousText: 'Previous',
nextText: 'Next',
loadingText: 'Loading...',
noDataText: 'No rows found',
pageText: 'Page',
ofText: 'of',
rowsText: 'rows',
nextText: 'Next'
// Classes
className: '-striped -highlight', // The most top level className for the component
tableClassName: '', // ClassName for the `table` element
theadClassName: '', // ClassName for the `thead` element
tbodyClassName: '', // ClassName for the `tbody` element
trClassName: '', // ClassName for all `tr` elements
trClassCallback: row => null, // A call back to dynamically add classes (via the classnames module) to a row element
paginationClassName: '' // ClassName for `pagination` element
// Styles
style: {}, // Main style object for the component
tableStyle: {}, // style object for the `table` component
theadStyle: {}, // style object for the `thead` component
tbodyStyle: {}, // style object for the `tbody` component
trStyle: {}, // style object for the `tr` component
trStyleCallback: row => {}, // A call back to dynamically add styles to a row element
thStyle: {}, // style object for the `th` component
tdStyle: {}, // style object for the `td` component
paginationStyle: {}, // style object for the `paginination` component
}
```
@@ -243,44 +114,42 @@ You can easily override the core defaults like so:
import { ReactTableDefaults } from 'react-table'
Object.assign(ReactTableDefaults, {
defaultPageSize: 10,
pageSize: 10,
minRows: 3,
// etc...
})
```
Or just define them as props
Or just define them on the component per-instance
```javascript
<ReactTable
defaultPageSize={10}
pageSize={10}
minRows={3}
// etc...
/>
/>
```
<a name="columns"></a>
## Columns
`<ReactTable/>` requires a `columns` prop, which is an array of objects containing the following properties
Every React-Table instance requires a `columns` prop, which is an array of objects containing the following properties
```javascript
[{
// General
accessor: 'propertyName' // or Accessor eg. (row) => row.propertyName (see "Accessors" section for more details)
accessor: 'propertyName' or Accessor eg. (row) => row.propertyName,
id: 'myProperty', // Conditional - A unique ID is required if the accessor is not a string or if you would like to override the column name used in server-side calls
sortable: true,
show: true, // can be used to hide a column
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
sort: 'asc' or 'desc',
show: true,
minWidth: Number // Allows the column to flex above this minimum amount
// 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
innerClassName: '', // Set the classname of the `.-td-inner` element of the column
innerStyle: {}, // Set the style of the `.-td-inner` element of the column
render: JSX eg. ({value, rowValues, row, index, viewIndex}) => <span>{value}</span>, // Provide a JSX element or stateless function to render whatever you want as the column's cell with access to the entire row
// 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
@@ -288,57 +157,28 @@ Or just define them as props
// 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>,
header: 'Header Name' or JSX 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
headerInnerClassName: '', // Set the classname of the `.-th-inner` element of the column
headerInnerStyle: {}, // Set the style of the `.th-inner` element of the column
// Header Groups only
columns: [...] // See Header Groups section below
// Footer
footer: 'Header Name' or JSX eg. ({data, column}) => <div>Header Name</div>,
footerClassName: '', // Set the classname of the `td` element of the column's footer
footerStyle: {}, // Set the style of the `td` element of the column's footer
getFooterProps: (state, rowInfo, column, instance) => ({}) // A function that returns props to decorate the `td` element of the column's footer
// Filtering
filterMethod: (filter, row, column) => {return true} // A function returning a boolean that specifies the filtering logic for the column
// filter == an object specifying which filter is being applied. Format: {id: [the filter column's id], value: [the value the user typed in the filter field]}
// row == the row of data supplied to the table
// column == the column that the filter is on
}]
```
## Accessors
Accessors are functions that return the value to populate the row's value for the column.
This lets the render function not have to worry about accessing the correct data, the value is automatically populated in it's props.
<a name="styles"></a>
## Styles
React-table is built to be dropped into existing applications or styled from the ground up, but if you'd like a decent starting point, you can optionally include our default theme `react-table.css`. We think it looks great, honestly :)
If a `string` or `array` is passed the default accessor is used.
The default accessor will parse the input into an array and recursively flatten it.
Any values that contain a dot (`.`) will be split.
Any values that contain bracket (`[]`) will be split.
This array is then used as the path to the value to return.
("$" is the placeholder value that would be returned by the default accessor)
| value | path | data |
|--------------|-----------------|------------------------|
| "a" | ["a"] | {"a": $} |
| "a.b" | ["a", "b"] | {"a": {"b": $}} |
| "a[0]" | ["a", "0"] | {"a": [$]} |
| ["a.b", "c"] | ["a", "b", "c"] | {"a": {"b": {"c": $}}} |
*NOTE*
If your data has a field/key with a dot (`.`) you will need to supply a custom accessor.
## Column Header Groups
To group columns with another header column, just nest your columns in a header column. Header columns utilize the same header properties as regular columns.
<a name="header-groups"></a>
## Header Groups
To group columns with another header column, just nest your columns in a header column like so:
```javascript
const columns = [{
header: 'Favorites',
headerClassName: 'my-favorites-column-header-group'
columns: [{
header: 'Color',
accessor: 'favorites.color'
@@ -352,204 +192,13 @@ 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
- `index` - The index of the row
- `viewIndex` - the index of the row relative to the current page
- `level` - The nesting depth (zero-indexed)
- `nestingPath` - The nesting path of the row
- `aggregated` - A boolean stating if the row is an aggregation row
- `subRows` - An array of any expandable sub-rows contained in this row
```javascript
// This column uses a stateless component to produce a different colored bar depending on the value
// You can also use stateful components or any other function that returns JSX
const columns = [{
header: () => <span><i className='fa-tasks' /> Progress</span>,
accessor: 'progress',
render: row => (
<div
style={{
width: '100%',
height: '100%',
backgroundColor: '#dadada',
borderRadius: '2px'
}}
>
<div
style={{
width: `${row.value}%`,
height: '100%',
backgroundColor: row.value > 66 ? '#85cc00'
: row.value > 33 ? '#ffbf00'
: '#ff2e00',
borderRadius: '2px',
transition: 'all .2s ease-out'
}}
/>
</div>
)
}]
```
## Styles
- React-table ships with a minimal and clean stylesheet to get you on your feet quickly.
- The stylesheet is located at `react-table/react-table.css`.
- There are countless ways to import a stylesheet. If you have questions on how to do so, consult the documentation of your build system.
#### Classes
- Adding a `-striped` className to ReactTable will slightly color odd numbered rows for legibility
- Adding a `-highlight` className to ReactTable will highlight any row as you hover over it
#### CSS
We think the default styles looks great! But, if you prefer a more custom look, all of the included styles are easily overridable. Every single component contains a unique class that makes it super easy to customize. Just go for it!
#### JS Styles
Every single react-table element and `get[ComponentName]Props` callback supports `classname` and `style` props.
## Custom Props
#### Built-in Components
Every single built-in component's props can be dynamically extended using any one of these prop-callbacks:
```javascript
<ReactTable
getProps={fn}
getTableProps={fn}
getTheadGroupProps={fn}
getTheadGroupTrProps={fn}
getTheadGroupThProps={fn}
getTheadProps={fn}
getTheadTrProps={fn}
getTheadThProps={fn}
getTbodyProps={fn}
getTrGroupProps={fn}
getTrProps={fn}
getThProps={fn}
getTdProps={fn}
getPaginationProps={fn}
getLoadingProps={fn}
/>
```
These callbacks are executed with each render of the element with four parameters:
1. Table State
2. RowInfo (undefined if not applicable)
3. Column (undefined if not applicable)
4. React Table Instance
This makes it extremely easy to add, say... a row click callback!
```javascript
// When any Td element is clicked, we'll log out some information
<ReactTable
getTdProps={(state, rowInfo, column, instance) => {
return {
onClick: e => {
console.log('A Td Element was clicked!')
console.log('it produced this event:', e)
console.log('It was in this column:', column)
console.log('It was in this row:', rowInfo)
console.log('It was in this table instance:', instance)
}
}
}}
/>
```
You can use these callbacks for dynamic styling as well!
```javascript
// Any Tr element will be green if its (row.age > 20)
<ReactTable
getTrProps={(state, rowInfo, column) => {
return {
style: {
background: rowInfo.age > 20 ? 'green' : 'red'
}
}
}}
/>
```
#### Column Components
Just as core components can have dynamic props, columns and column headers can too!
You can utilize either of these prop callbacks on columns:
```javascript
const columns = [{
getHeaderProps: () => (...),
getProps: () => (...)
}]
```
In a similar fashion these can be used to dynamically style just about anything!
```javascript
// This columns cells will be red if (row.name === Santa Clause)
const columns = [{
getProps: (state, rowInfo, column) => {
return {
style: {
background: rowInfo.name === 'Santa Clause' ? 'red' : null
}
}
}
}]
```
## Pivoting and Aggregation
Pivoting the table will group records together based on their accessed values and allow the rows in that group to be expanded underneath it.
To pivot, pass an array of `columnID`'s to `pivotBy`. Remember, a column's `id` is either the one that you assign it (when using a custom accessors) or its `accessor` string.
```javascript
<ReactTable
...
pivotBy={['lastName', 'age']}
/>
```
Naturally when grouping rows together, you may want to aggregate the rows inside it into the grouped column. No aggregation is done by default, however, it is very simple to aggregate any pivoted columns:
```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',
accessor: 'age',
aggregate: (values, rows) => _.round(_.mean(values)),
render: row => {
// You can even render the cell differently if it's an aggregated cell
return <span>{row.aggregated ? `${row.value} (avg)` : row.value}</span>
}
}, {
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.
## Sub Tables and Sub Components
By adding a `SubComponent` props, you can easily add an expansion level to all root-level rows:
```javascript
<ReactTable
data={data}
columns={columns}
defaultPageSize={10}
SubComponent={(row) => {
return (
<div>
You can put any component you want here, even another React Table! You even have access to the row-level data if you need! Spark-charts, drill-throughs, infographics... the possibilities are endless!
</div>
)
}}
/>
```
<a name="server-side-data"></a>
## Server-side Data
If you want to handle pagination, sorting, and filtering on the server, `react-table` makes it easy on you.
If you want to handle pagination, and sorting on the server, `react-table` makes it easy on you.
1. Feed React Table `data` from somewhere dynamic. eg. `state`, a redux store, etc...
1. Add `manual` as a prop. This informs React Table that you'll be handling sorting and pagination server-side
1. Subscribe to the `onChange` prop. This function is called at `compomentDidMount` and any time sorting or pagination is changed by the user
1. Subscribe to the `onChange` prop. This function is called 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. Update your data with the rows to be displayed
1. Optionally set how many pages there are total
@@ -559,137 +208,57 @@ If you want to handle pagination, sorting, and filtering on the server, `react-t
...
data={this.state.data} // should default to []
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) => {
// 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
sorting: state.sorting
})
.then((res) => {
// Update react-table
this.setState({
data: res.data.rows,
pages: res.data.pages,
loading: false
pages: res.data.pages
})
})
}}
/>
```
For a detailed example, take a peek at our <a href="https://github.com/tannerlinsley/react-table/blob/master/stories/ServerSide.js" target="\_parent">async table mockup</a>
## Fully Controlled Component
React Table by default works fantastically out of the box, but you can achieve even more control and customization if you choose to maintain the state yourself. It is very easy to do, even if you only want to manage *parts* of the state.
Here are the props and their corresponding callbacks that control the state of the a table:
```javascript
<ReactTable
// Props
page={0} // the index of the page you wish to display
pageSize={20} // the number of rows per page to be displayed
sorting={[{
id: 'lastName',
asc: true
}, {
id: 'firstName',
asc: true
}]} // the sorting model for the table
expandedRows={{
1: true,
4: true,
5: {
2: true,
3: true
}
}} // The nested row indexes on the current page that should appear expanded
// 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, event) => {...}} // Called when a user enters a value into a filter input field. The event is the onChange event of the input field.
/>
```
## Functional Rendering
Possibly one of the coolest features of React-Table is its ability to expose internal components and state for custom render logic. The easiest way to do this is to pass a function as the child of `<ReactTable />`.
The function you pass will be called with the following items:
- Fully-resolved state of the table
- A function that returns the standard table component
- The instance of the component
You can then return any JSX or react you want! This turns out to be perfect for:
- Accessing the internal state of the table without a `ref`
- Decorating the table or extending it with your own UI
- Building your own custom display logic
Accessing internal state and wrapping with more UI:
```javascript
<ReactTable
data={data}
columns={columns}
>
{(state, makeTable, instance) => {
return (
<div style={{
background: '#ffcf00',
borderRadius: '5px',
overflow: 'hidden',
padding: '5px'
}}>
<pre><code>state.allVisibleColumns === {JSON.stringify(state.allVisibleColumns, null, 4)}</code></pre>
{makeTable()}
</div>
)
}}
</ReactTable>
```
The possibilities are endless!
For a detailed example, take a peek at our [async table mockup](https://github.com/tannerlinsley/react-table/blob/master/example/src/screens/async.js)
<a name="multi-sort"></a>
## 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!
<a name="component-overrides"></a>
## Component Overrides
Though we confidently stand by the markup and architecture behind it, `react-table` does offer the ability to change the core componentry it uses to render everything. You can extend or override these internal components by passing a react component to it's corresponding prop on either the global props or on a one-off basis like so:
Though we wouldn't suggest it, `react-table` has the ability to change the core componentry it used to render it's table. You can do so by assigning a react component to it's corresponding global prop, or on a one-off basis like so:
```javascript
// Change the global default
import { ReactTableDefaults } from 'react-table'
Object.assign(ReactTableDefaults, {
TableComponent: component,
TheadComponent: component,
TbodyComponent: component,
TrGroupComponent: component,
TrComponent: component,
ThComponent: component
TdComponent: component,
TfootComponent: component,
ExpanderComponent: component,
PaginationComponent: component,
PreviousComponent: undefined,
NextComponent: undefined,
LoadingComponent: component,
NoDataComponent: component,
tableComponent: Component,
theadComponent: Component,
tbodyComponent: Component,
trComponent: Component,
thComponent: Component,
tdComponent: Component,
paginationComponent: Component,
previousComponent: Component,
nextComponent: Component,
loadingComponent: Component
})
// Or change per instance
<ReactTable
TableComponent={Component},
TheadComponent={Component},
tableComponent={Component},
theadComponent={Component},
// etc...
/>
```
If you choose to change the core components React-Table uses to render, you must make sure your replacement components consume and utilize all of the supplied and inherited props that are needed for that component to function properly. We would suggest investigating <a href="https://github.com/tannerlinsley/react-table/blob/master/src/index.js" target="\_parent">the source</a> for the component you wish to replace.
If you choose to change the core components React-Table uses to render, you must make sure your components support and utilized all of the neeeded features for that component to work properly. For a broad reference on how to do this, investigate [the source](https://github.com/tannerlinsley/react-table/blob/master/src/index.js) for the component you wish to replace.
## Contributing
@@ -697,22 +266,17 @@ To suggest a feature, create an issue if it does not already exist.
If you would like to help develop a suggested feature follow these steps:
- Fork this repo
- `$ yarn`
- `$ yarn run storybook`
- `npm install`
- `npm watch`
- Implement your changes to files in the `src/` directory
- View changes as you code via our <a href="https://github.com/storybooks/react-storybook" target="\_parent">React Storybook</a> `localhost:8000`
- Make changes to stories in `/stories`, or create a new one if needed
- Submit PR for review
#### Scripts
If you would like to preview your changes, you can link and utilize the example like so:
- `$ yarn run storybook` Runs the storybook server
- `$ yarn run test` Runs the test suite
- `$ yarn run prepublish` Builds the distributable bundle
- `$ yarn run docs` Builds the website/docs from the storybook for github pages
## Used By
<a href='https://nozzle.io' target="\_parent">
<img src='https://nozzle.io/img/logo-blue.png' alt='Nozzle Logo' style='width:300px;'/>
</a>
- `npm link`
- `cd example`
- `npm install`
- `npm link react-table`
- `npm watch`
- Make changes to the example in `src/screens/index.js` if needed
- View changes at `localhost:8000`
-1
View File
@@ -1 +0,0 @@
react-table.js.org
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

-22
View File
@@ -1,22 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script>
if (window.parent !== window) {
window.__REACT_DEVTOOLS_GLOBAL_HOOK__ = window.parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
}
</script>
<title>React Storybook</title>
</head>
<body>
<div id="root"></div>
<div id="error-display"></div>
<script src="static/preview.ea1bdf726a82703c8f6f.bundle.js"></script>
</body>
</html>
-44
View File
@@ -1,44 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="storybook-version" content="2.35.3">
<title>React Storybook</title>
<style>
/*
When resizing panels, the drag event breaks if the cursor
moves over the iframe. Add the 'dragging' class to the body
at drag start and remove it when the drag ends.
*/
.dragging iframe {
pointer-events: none;
}
/* Styling the fuzzy search box placeholders */
.searchBox::-webkit-input-placeholder { /* Chrome/Opera/Safari */
color: #ddd;
font-size: 16px;
}
.searchBox::-moz-placeholder { /* Firefox 19+ */
color: #ddd;
font-size: 16px;
}
.searchBox:focus{
border-color: #EEE !important;
}
.btn:hover{
background-color: #eee
}
</style>
</head>
<body style="margin: 0;">
<div id="root"></div>
<script src="static/manager.064c8fe6b78907f0a142.bundle.js"></script>
</body>
</html>
File diff suppressed because one or more lines are too long
@@ -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
@@ -1 +0,0 @@
{"version":3,"file":"static/preview.ea1bdf726a82703c8f6f.bundle.js","sources":["webpack:///static/preview.ea1bdf726a82703c8f6f.bundle.js"],"mappings":"AAAA;AAkuDA;AAo/DA;AAgrFA;AAmmFA;AA07OA;AAuwFA;AAwtDA;AA+jEA;AA4uDA;AAi8DA;AA+lDA;AA4yDA;AA28CA;AAw7DA;AAooDA;AA67CA;AAiqDA;AAynEA;AAwxDA;AA+rCA;AA+mDA;AA2lDA;AAkqEA;AAs2DA;AA2zDA;AAo4CA;AAksFA;AAmjGA;AAksDA;AA02CA;AAgoCA;AAm/CA;AA+4CA;AAsCA;AA+jFA","sourceRoot":""}
+1
View File
@@ -0,0 +1 @@
# Jumpsuit Getting Started
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

+171
View File
File diff suppressed because one or more lines are too long
+59138
View File
File diff suppressed because one or more lines are too long
+13
View File
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>React-Table Demo</title>
<link rel="stylesheet" href="/app.css" charset="utf-8">
</head>
<body>
<div id="app"></div>
<script src="/app.js"></script>
<script async defer src="https://buttons.github.io/buttons.js"></script>
</body>
</html>
+28
View File
@@ -0,0 +1,28 @@
var fs = require('fs')
var path = require('path')
var stylus = require('stylus')
var nib = require('nib')
var stylusEntry = path.resolve('src/app.styl')
module.exports = {
styles: {
extensions: ['.css', '.styl'],
action: buildStyles
}
}
function buildStyles () {
return new Promise(function (resolve, reject) {
stylus.render(fs.readFileSync(stylusEntry, 'utf8'), {
'include css': true,
'hoist atrules': true,
compress: process.env.NODE_ENV === 'production',
paths: [path.resolve('src')],
use: nib()
}, function (err, css) {
if (err) reject(err)
else resolve(css)
})
})
}
+26
View File
@@ -0,0 +1,26 @@
{
"name": "react-table-example",
"version": "0.0.1",
"description": "Jumpsuit getting started example",
"license": "MIT",
"private": true,
"repository": {
"type": "git",
"url": "git+https://github.com/jumpsuit/jumpsuit.git"
},
"scripts": {
"watch": "jumpsuit watch",
"build": "jumpsuit build"
},
"devDependencies": {
"nib": "^1.1.0",
"standard": "^8.4.0",
"stylus": "^0.54.5"
},
"dependencies": {
"jumpsuit": "^0.7.5",
"lodash": "^4.16.4",
"namor": "^0.3.0",
"react-table": "^2.0.0"
}
}
+5
View File
@@ -0,0 +1,5 @@
import { Render } from 'jumpsuit'
// import App from 'screens/async'
import App from 'screens/index'
Render(null, <App />)
+79
View File
@@ -0,0 +1,79 @@
// -----------------------------------------------------------------------------
// Globals
// -----------------------------------------------------------------------------
@import url('https://fonts.googleapis.com/css?family=Open+Sans:300,600')
@import 'nib'
global-reset()
// -----------------------------------------------------------------------------
// vendor styles
// -----------------------------------------------------------------------------
@import '../node_modules/react-table/react-table.css'
// -----------------------------------------------------------------------------
// variables
// -----------------------------------------------------------------------------
$fnt-open-sans = 'Open Sans', sans-serif
$react = #25d8fd
// -----------------------------------------------------------------------------
// styles
// -----------------------------------------------------------------------------
*
box-sizing border-box
html
min-height 100vh
body
background: white
font-family: $fnt-open-sans
font-weight: 300
padding-bottom: 50px
h1
font-size: 2.5em
color: white
a
color: darken($react, 20%)
font-weight: bold
text-decoration: none
strong
font-weight: bold
.logo
width: 400px
.container
display: flex
flex-direction: column
align-items: center
justify-content: center
min-height: 100vh
padding-top: 20px
.github-addon
font-size: 20px
padding: 10px
.table-wrap
width: 700px
padding: 10px
border-radius: 5px
box-shadow: 0 0 20px 0 alpha(black, .2)
.ReactTable
thead
th
td
&.-sort-asc
box-shadow:inset 0 3px 0 0 alpha(black, .6)
&.-sort-desc
box-shadow:inset 0 -3px 0 0 alpha(black, .6)
Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

+13
View File
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>React-Table Demo</title>
<link rel="stylesheet" href="/app.css" charset="utf-8">
</head>
<body>
<div id="app"></div>
<script src="/app.js"></script>
<script async defer src="https://buttons.github.io/buttons.js"></script>
</body>
</html>
+134
View File
@@ -0,0 +1,134 @@
import { Component } from 'jumpsuit'
import _ from 'lodash'
import namor from 'namor'
import ReactTable from 'react-table'
// Let's mock some data to play around with
const rawData = _.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)
}
})
// 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) => {
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
const sortedData = _.orderBy(rawData, sorting.map(sort => {
return row => {
if (row[sort.id] === null || row[sort.id] === undefined) {
return -Infinity
}
return typeof row[sort.id] === 'string' ? row[sort.id].toLowerCase() : row[sort.id]
}
}), sorting.map(d => d.asc ? 'asc' : 'desc'))
// Be sure to send back the rows to be displayed and any other pertinent information, like how many pages there are total.
const res = {
rows: sortedData.slice(pageSize * page, (pageSize * page) + pageSize),
pages: Math.ceil(rawData.length / pageSize)
}
// Here we'll simulate a server response with 500ms of delay.
setTimeout(() => resolve(res), 500)
})
}
export default Component({
getInitialState () {
// To handle our data server-side, we need a few things in the state to help us out:
return {
data: [],
pages: null,
loading: true
}
},
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)
.then((res) => {
// 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,
pages: res.pages,
loading: false
})
})
},
render () {
return (
<div className='container'>
<div style={{textAlign: 'center'}}>
<h1>
<span style={{position: 'absolute', textIndent: '-9999em'}}>
react-table <strong>server-side demo</strong>
</span>
<img src='/Banner.png' className='logo' />
</h1>
<br />
<div>
<a
className='github-button'
href='https://github.com/tannerlinsley/react-table'
target='_blank'
data-style='mega'
data-count-href='/tannerlinsley/react-table/stargazers'
data-count-api='/repos/tannerlinsley/react-table#stargazers_count'
data-count-aria-label='# stargazers on GitHub'
aria-label='Star tannerlinsley/react-table on GitHub'>
Star
</a>
</div>
<br />
<div className='github-addon'>
<a
target='_blank'
href='https://github.com/tannerlinsley/react-table'>
View on Github
</a>
</div>
<br />
<br />
</div>
<div className='table-wrap'>
<ReactTable
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'
}]
}]}
manual // Forces table not to paginate or sort automatically, so we can handle it server-side
pageSize={5}
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
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
</div>
)
}
})
+82
View File
@@ -0,0 +1,82 @@
import { Component } from 'jumpsuit'
import _ from 'lodash'
import namor from 'namor'
import ReactTable from 'react-table'
export default Component({
render () {
const data = _.map(_.range(5000), 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 className='container'>
<div style={{textAlign: 'center'}}>
<h1>
<span style={{position: 'absolute', textIndent: '-9999em'}}>
react-table <strong>demo</strong>
</span>
<img src='/Banner.png' className='logo' />
</h1>
<br />
<div>
<a
className='github-button'
href='https://github.com/tannerlinsley/react-table'
target='_blank'
data-style='mega'
data-count-href='/tannerlinsley/react-table/stargazers'
data-count-api='/repos/tannerlinsley/react-table#stargazers_count'
data-count-aria-label='# stargazers on GitHub'
aria-label='Star tannerlinsley/react-table on GitHub'>
Star
</a>
</div>
<br />
<div className='github-addon'>
<a
target='_blank'
href='https://github.com/tannerlinsley/react-table'>
View on Github
</a>
</div>
<br />
<br />
</div>
<div className='table-wrap'>
<ReactTable
data={data}
columns={columns}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
</div>
)
}
})
+4
View File
@@ -0,0 +1,4 @@
{
"name": "react-table",
"root": "dist"
}
+8 -26
View File
@@ -1,6 +1,6 @@
{
"name": "react-table",
"version": "5.3.4",
"version": "3.0.0",
"description": "A fast, lightweight, opinionated table and datagrid built on React",
"license": "MIT",
"homepage": "https://github.com/tannerlinsley/react-table#readme",
@@ -16,7 +16,6 @@
],
"main": "lib/index.js",
"files": [
"src/",
"lib/",
"react-table.js",
"react-table.css",
@@ -24,26 +23,20 @@
],
"scripts": {
"build:node": "babel src --out-dir lib --source-maps inline",
"build:css": "rimraf react-table.css && stylus src/index.styl --compress -o react-table.css && yarn run css:autoprefix",
"css:autoprefix": "postcss --use autoprefixer react-table.css -r",
"watch": "npm-run-all --parallel watch:*",
"watch:node": "onchange 'src/**/*.js' -i -- npm run build:node",
"watch:css": "onchange 'src/**/*.styl' -i -- npm run build:css",
"build:css": "rm -rf react-table.css && stylus src/index.styl --use ./node_modules/nib/lib/nib.js --compress -o react-table.css",
"watch": "onchange 'src/**' -i -- npm-run-all build:*",
"test": "standard",
"umd": "rimraf react-table.js && browserify lib/index.js -s reactTable -x react -t babelify -g uglifyify -o react-table.js",
"umd": "rm -rf react-table.js && browserify lib/index.js -s reactTable -x react -t babelify -g uglifyify -o react-table.js",
"prepublish": "npm-run-all build:* && npm run umd",
"storybook": "start-storybook -p 8000 -c .storybook",
"docs": "build-storybook -o docs && cp .storybook/CNAME docs/CNAME"
"postpublish": "git push --tags"
},
"dependencies": {
"classnames": "^2.2.5"
},
"peerDependencies": {
"react": "^15.x.x"
"react": "^15.3.1"
},
"devDependencies": {
"@kadira/storybook": "^2.35.1",
"autoprefixer": "^6.7.0",
"babel-cli": "6.14.0",
"babel-eslint": "6.1.2",
"babel-preset-es2015": "6.14.0",
@@ -51,19 +44,10 @@
"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",
"namor": "^0.3.0",
"nib": "^1.1.2",
"npm-run-all": "^3.1.1",
"onchange": "^3.0.2",
"postcss-cli": "^2.6.0",
"react": "^15.4.2",
"react-dom": "^15.4.2",
"react-json-tree": "^0.10.1",
"rimraf": "^2.6.1",
"standard": "^8.0.0",
"storybook": "^0.0.0",
"stylus": "^0.54.5",
"uglifyify": "3.0.3"
},
@@ -77,9 +61,7 @@
"dist",
"lib",
"example",
"react-table.js",
"stories",
"docs"
"react-table.js"
]
},
"babel": {
-161
View File
@@ -1,161 +0,0 @@
import React from 'react'
import classnames from 'classnames'
//
import _ from './utils'
import Pagination from './pagination'
const emptyObj = () => ({})
export default {
// General
data: [],
loading: false,
showPagination: true,
showPageSizeOptions: true,
pageSizeOptions: [5, 10, 20, 25, 50, 100],
defaultPageSize: 20,
showPageJump: true,
expanderColumnWidth: 35,
collapseOnSortingChange: true,
collapseOnPageChange: true,
collapseOnDataChange: true,
freezeWhenExpanded: false,
defaultSorting: [],
showFilters: false,
defaultFiltering: [],
defaultFilterMethod: (filter, row, column) => (row[filter.id] === filter.value),
// Controlled State Overrides
// page: undefined,
// pageSize: undefined,
// sorting: undefined,
// Controlled State Callbacks
onExpandSubComponent: undefined,
onPageChange: undefined,
onPageSizeChange: undefined,
onSortingChange: undefined,
onFilteringChange: undefined,
// Pivoting
pivotBy: undefined,
pivotColumnWidth: 200,
pivotValKey: '_pivotVal',
pivotIDKey: '_pivotID',
subRowsKey: '_subRows',
// Pivoting State Overrides
// expandedRows: {},
// Pivoting State Callbacks
onExpandRow: undefined,
// General Callbacks
onChange: () => null,
// Classes
className: '',
style: {},
// Component decorators
getProps: emptyObj,
getTableProps: emptyObj,
getTheadGroupProps: emptyObj,
getTheadGroupTrProps: emptyObj,
getTheadGroupThProps: emptyObj,
getTheadProps: emptyObj,
getTheadTrProps: emptyObj,
getTheadThProps: emptyObj,
getTheadFilterProps: emptyObj,
getTheadFilterTrProps: emptyObj,
getTheadFilterThProps: emptyObj,
getTbodyProps: emptyObj,
getTrGroupProps: emptyObj,
getTrProps: emptyObj,
getTdProps: emptyObj,
getTfootProps: emptyObj,
getTfootTrProps: emptyObj,
getTfootTdProps: emptyObj,
getPaginationProps: emptyObj,
getLoadingProps: emptyObj,
getNoDataProps: emptyObj,
// Global Column Defaults
column: {
sortable: true,
show: true,
minWidth: 100,
// Cells only
render: undefined,
className: '',
style: {},
getProps: emptyObj,
// Headers only
header: undefined,
headerClassName: '',
headerStyle: {},
getHeaderProps: emptyObj,
// Footers only
footer: undefined,
footerClassName: '',
footerStyle: {},
getFooterProps: emptyObj,
filterMethod: undefined
},
// Text
previousText: 'Previous',
nextText: 'Next',
loadingText: 'Loading...',
noDataText: 'No rows found',
pageText: 'Page',
ofText: 'of',
rowsText: 'rows',
// Components
TableComponent: _.makeTemplateComponent('rt-table'),
TheadComponent: _.makeTemplateComponent('rt-thead'),
TbodyComponent: _.makeTemplateComponent('rt-tbody'),
TrGroupComponent: _.makeTemplateComponent('rt-tr-group'),
TrComponent: _.makeTemplateComponent('rt-tr'),
ThComponent: ({toggleSort, className, children, ...rest}) => {
return (
<div
className={classnames(className, 'rt-th')}
onClick={e => {
toggleSort && toggleSort(e)
}}
{...rest}
>
{children}
</div>
)
},
TdComponent: _.makeTemplateComponent('rt-td'),
TfootComponent: _.makeTemplateComponent('rt-tfoot'),
ExpanderComponent: ({isExpanded, ...rest}) => {
return (
<div
className={classnames('rt-expander', isExpanded && '-open')}
{...rest}
>&bull;</div>
)
},
PaginationComponent: Pagination,
PreviousComponent: undefined,
NextComponent: undefined,
LoadingComponent: ({className, loading, loadingText, ...rest}) => (
<div className={classnames(
'-loading',
{'-active': loading},
className
)}
{...rest}
>
<div className='-loading-inner'>
{loadingText}
</div>
</div>
),
NoDataComponent: _.makeTemplateComponent('rt-noData')
}
+450 -880
View File
File diff suppressed because it is too large Load Diff
+100 -161
View File
@@ -1,41 +1,91 @@
@import 'nib'
$easeOutQuad = cubic-bezier(0.250, 0.460, 0.450, 0.940)
$easeOutBack = cubic-bezier(0.175, 0.885, 0.320, 1.275)
$expandSize = 7px
.ReactTable
position:relative
border: 1px solid alpha(black, .1)
*
box-sizing: border-box
.rt-table
display: flex
flex-direction: column
align-items: stretch
table
width: 100%
border-collapse: collapse
overflow: auto
border: 1px solid alpha(black, .1)
display: block
overflow-x: auto
.-td
.-th
&-inner
white-space: nowrap
text-overflow: ellipsis
padding: 7px 5px
overflow: hidden
z-index:0
transition: .3s ease
transition-property: width, min-width, padding, opacity
th
td
&:hover
.-td
.-th
&-inner
position:relative
overflow:visible
z-index:1
text-shadow:
0 0 1px white,
0 0 2px white,
1px 0 3px white,
1px 0 4px white,
2px 0 5px white,
2px 0 6px white,
3px 0 7px white,
3px 0 8px white,
4px 0 9px white,
4px 0 10px white,
5px 0 11px white,
5px 0 12px white,
6px 0 13px white,
6px 0 14px white,
7px 0 15px white,
7px 0 16px white,
8px 0 17px white,
8px 0 18px white,
9px 0 19px white,
9px 0 20px white
> *
text-shadow: none
&.-hidden
border:0 !important
opacity: 0 !important
.-th-inner
.-td-inner
width: 0 !important
min-width: 0 !important
padding: 0 !important
thead
box-shadow: 0px 5px 20px 0 alpha(black, .1)
z-index: 0
.rt-thead
display: flex
flex-direction: column
&.-headerGroups
background: alpha(black, .03)
border-bottom: 1px solid alpha(black, .05)
&.-filters
border-bottom: 1px solid alpha(black, 0.05)
th
td
background: alpha(black, .03)
.rt-th
border-right: 1px solid alpha(black, 0.02)
&.-header
box-shadow: 0 2px 15px 0px alpha(black, .15)
.rt-tr
tr
text-align:center
.rt-th
.rt-td
th
td
width: 1%
background: white
font-weight:500
color: $darkColor
border-right: 1px solid alpha(black, .05)
transition box-shadow .3s $easeOutBack
box-shadow:inset 0 0 0 0 transparent
@@ -45,99 +95,40 @@ $expandSize = 7px
box-shadow:inset 0 -3px 0 0 alpha(black, .6)
&.-cursor-pointer
cursor: pointer
&:last-child
border-right: 0
.rt-tbody
display: flex
flex-direction: column
// z-index:0
.rt-tr-group
tbody
z-index:0
tr
border-bottom: solid 1px alpha(black, .05)
&:last-child
border-bottom: 0
.rt-td
&:first-child td
box-shadow: inset 0 20px 20px -20px alpha(black, .2)
td
border-right:1px solid alpha(black, .02)
&:last-child
border-right:0
.rt-pivot
cursor: pointer
.rt-tr-group
display: flex
flex-direction: column
align-items: stretch
.rt-tr
display: inline-flex
.rt-th
.rt-td
flex: 1 0 0px
white-space: nowrap
text-overflow: ellipsis
padding: 7px 5px
overflow: hidden
transition: .3s ease
transition-property: width, min-width, padding, opacity
&.-hidden
width: 0 !important
min-width: 0 !important
padding: 0 !important
border:0 !important
opacity: 0 !important
.rt-expander
display: inline-block
position:relative
margin: 0
color: transparent
margin: 0 10px
&:after
content: ''
position: absolute
width: 0
height: 0
top:50%
left:50%
transform: translate(-50%, -50%) rotate(-90deg)
border-left: ($expandSize * .72) solid transparent
border-right: ($expandSize * .72) solid transparent
border-top: $expandSize solid alpha(black, .8)
transition: all .3s $easeOutBack
cursor: pointer
&.-open:after
transform: translate(-50%, -50%) rotate(0deg)
.rt-tfoot
display: flex
flex-direction: column
box-shadow: 0 0px 15px 0px alpha(black, .15)
.rt-td
border-right:1px solid alpha(black, .05)
&:last-child
border-right:0
&.-striped
.rt-tr.-odd
&.striped
tbody tr:nth-child(even)
background: alpha(black, .03)
&.-highlight
.rt-tbody
.rt-tr:not(.-padRow):hover
background: alpha(black, .05)
&.highlight
tbody tr:hover
background: alpha(black, .05)
.-pagination
z-index: 1
width:100%
display:flex
margin-top:5px
justify-content: space-between
align-items: stretch
align-items: center
flex-wrap: wrap
padding: 3px
box-shadow: 0 0px 15px 0px alpha(black, .1)
border-top: 2px solid alpha(black, .1)
.-btn
appearance:none
display:block
width:100%
height: 100%
border: 0
border-radius: 3px
padding: 6px
@@ -156,47 +147,22 @@ $expandSize = 7px
background: alpha(black, .3)
color: white
.-previous
.-next
.-left
.-center
.-right
flex: 1
// min-width:150px
margin-bottom:5px
.-left
.-right
text-align: center
.-center
flex: 1.5
text-align:center
margin-bottom:0
display: flex
flex-direction: row
flex-wrap: wrap
align-items: center
justify-content: space-around
padding: 0 5px
.-pageInfo
display: inline-block
margin: 3px 10px
white-space: nowrap
.-pageJump
display:inline-block
input
width: 70px
text-align:center
.-pageSizeOptions
margin: 3px 10px
.rt-noData
display:block
position:absolute
left:50%
top:50%
transform: translate(-50%, -50%)
background: alpha(white, .8)
transition: all .3s ease
z-index: 1
pointer-events: none
padding: 20px
color: alpha(black, .5)
.-loading
display:block
@@ -228,30 +194,3 @@ $expandSize = 7px
pointer-events: all
> div
transform: translateY(50%)
input
select
appearance: none
border: 1px solid rgba(0,0,0,0.1)
background: white
padding: 5px 7px
font-size: inherit
border-radius: 3px
font-weight: normal
outline:none
.select-wrap
position:relative
display:inline-block
select
padding: 5px 15px 5px 7px
min-width:100px
&:after
content: ''
position: absolute
right: 8px
top: 50%
transform: translate(0, -50%)
border-color: #999 transparent transparent
border-style: solid
border-width: 5px 5px 2.5px
-112
View File
@@ -1,112 +0,0 @@
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
}
},
getResolvedState (props, state) {
const resolvedState = {
..._.compactObject(this.state),
..._.compactObject(state),
..._.compactObject(this.props),
..._.compactObject(props)
}
return resolvedState
},
componentWillMount () {
this.setStateWithData(this.getDataModel(this.getResolvedState()))
},
componentDidMount () {
this.fireOnChange()
},
componentWillReceiveProps (nextProps, nextState) {
const oldState = this.getResolvedState()
const newState = this.getResolvedState(nextProps, nextState)
if (oldState.defaultSorting !== newState.defaultSorting) {
newState.sorting = newState.defaultSorting
}
if ((oldState.showFilters !== newState.showFilters) ||
(oldState.showFilters !== newState.showFilters)) {
newState.filtering = newState.defaultFiltering
}
// Props that trigger a data update
if (
oldState.data !== newState.data ||
oldState.columns !== newState.columns ||
oldState.pivotBy !== newState.pivotBy ||
oldState.sorting !== newState.sorting ||
oldState.showFilters !== newState.showFilters ||
oldState.filtering !== newState.filtering
) {
this.setStateWithData(this.getDataModel(newState))
}
},
setStateWithData (newState, cb) {
const oldState = this.getResolvedState()
const newResolvedState = this.getResolvedState({}, newState)
const {freezeWhenExpanded} = newResolvedState
// Default to unfrozen state
newResolvedState.frozen = false
// If freezeWhenExpanded is set, check for frozen conditions
if (freezeWhenExpanded) {
// if any rows are expanded, freeze the existing data and sorting
const keys = Object.keys(newResolvedState.expandedRows)
for (var i = 0; i < keys.length; i++) {
if (newResolvedState.expandedRows[keys[i]]) {
newResolvedState.frozen = true
break
}
}
}
// If the data isn't frozen and either the data or
// sorting model has changed, update the data
if (
(oldState.frozen && !newResolvedState.frozen) ||
oldState.sorting !== newResolvedState.sorting ||
oldState.filtering !== newResolvedState.filtering ||
oldState.showFilters !== newResolvedState.showFilters ||
(!newResolvedState.frozen && oldState.resolvedData !== newResolvedState.resolvedData)
) {
// Handle collapseOnSortingChange & collapseOnDataChange
if (
(oldState.sorting !== newResolvedState.sorting && this.props.collapseOnSortingChange) ||
(oldState.filtering !== newResolvedState.filtering) ||
(oldState.showFilters !== newResolvedState.showFilters) ||
(!newResolvedState.frozen && oldState.resolvedData !== newResolvedState.resolvedData && this.props.collapseOnDataChange)
) {
newResolvedState.expandedRows = {}
}
Object.assign(newResolvedState, this.getSortedData(newResolvedState))
}
// Calculate pageSize all the time
if (newResolvedState.sortedData) {
newResolvedState.pages = newResolvedState.manual ? newResolvedState.pages : Math.ceil(newResolvedState.sortedData.length / newResolvedState.pageSize)
}
return this.setState(newResolvedState, cb)
}
}
-447
View File
@@ -1,447 +0,0 @@
import _ from './utils'
export default {
getDataModel (newState) {
const {
columns,
pivotBy = [],
data,
pivotIDKey,
pivotValKey,
subRowsKey,
expanderColumnWidth,
SubComponent,
page,
pages,
pageSize
} = newState
// Determine Header Groups
let hasHeaderGroups = false
columns.forEach(column => {
if (column.columns) {
hasHeaderGroups = true
}
})
// Build Header Groups
const headerGroups = []
let currentSpan = []
// A convenience function to add a header and reset the currentSpan
const addHeader = (columns, column = columns[0]) => {
headerGroups.push({
...this.props.column,
...column,
columns: columns
})
currentSpan = []
}
const noSubExpanderColumns = columns.map(col => {
return {
...col,
columns: col.columns ? col.columns.filter(d => !d.expander) : undefined
}
})
let expanderColumnIndex = columns.findIndex(col => col.expander)
const needsExpander = (SubComponent || pivotBy.length) && expanderColumnIndex === -1
const columnsWithExpander = needsExpander ? [{expander: true}, ...noSubExpanderColumns] : noSubExpanderColumns
if (needsExpander) {
expanderColumnIndex = 0
}
const makeDecoratedColumn = (column) => {
const dcol = {
...this.props.column,
...column
}
if (dcol.expander) {
dcol.width = expanderColumnWidth
return dcol
}
if (typeof dcol.accessor === 'string') {
dcol.id = dcol.id || dcol.accessor
const accessorString = dcol.accessor
dcol.accessor = row => _.get(row, accessorString)
return dcol
}
if (dcol.accessor && !dcol.id) {
console.warn(dcol)
throw new Error('A column id is required if using a non-string accessor for column above.')
}
if (!dcol.accessor) {
dcol.accessor = d => undefined
}
// Ensure minWidth is not greater than maxWidth if set
if (dcol.maxWidth < dcol.minWidth) {
dcol.minWidth = dcol.maxWidth
}
return dcol
}
// Decorate the columns
const decorateAndAddToAll = (col) => {
const decoratedColumn = makeDecoratedColumn(col)
allDecoratedColumns.push(decoratedColumn)
return decoratedColumn
}
let allDecoratedColumns = []
const decoratedColumns = columnsWithExpander.map((column, i) => {
if (column.columns) {
return {
...column,
columns: column.columns.map(decorateAndAddToAll)
}
} else {
return decorateAndAddToAll(column)
}
})
// Build the visible columns, headers and flat column list
let visibleColumns = decoratedColumns.slice()
let allVisibleColumns = []
visibleColumns = visibleColumns.map((column, i) => {
if (column.columns) {
const visibleSubColumns = column.columns.filter(d => pivotBy.indexOf(d.id) > -1 ? false : _.getFirstDefined(d.show, true))
return {
...column,
columns: visibleSubColumns
}
}
return column
})
visibleColumns = visibleColumns.filter(column => {
return column.columns ? column.columns.length : pivotBy.indexOf(column.id) > -1 ? false : _.getFirstDefined(column.show, true)
})
// Move the pivot columns into a single column if needed
if (pivotBy.length) {
const pivotColumns = []
for (var i = 0; i < allDecoratedColumns.length; i++) {
if (pivotBy.indexOf(allDecoratedColumns[i].id) > -1) {
pivotColumns.push(allDecoratedColumns[i])
}
}
const pivotColumn = {
...pivotColumns[0],
pivotColumns,
expander: true
}
visibleColumns[expanderColumnIndex] = pivotColumn
}
// Build flast list of allVisibleColumns and HeaderGroups
visibleColumns.forEach((column, i) => {
if (column.columns) {
allVisibleColumns = allVisibleColumns.concat(column.columns)
if (currentSpan.length > 0) {
addHeader(currentSpan)
}
addHeader(column.columns, column)
return
}
allVisibleColumns.push(column)
currentSpan.push(column)
})
if (hasHeaderGroups && currentSpan.length > 0) {
addHeader(currentSpan)
}
// Access the data
let resolvedData = data.map((d, i) => {
const row = {
__original: d,
__index: i
}
allDecoratedColumns.forEach(column => {
if (column.expander) return
row[column.id] = column.accessor(d)
})
return row
})
// If pivoting, recursively group the data
const aggregate = (rows) => {
const aggregationValues = {}
aggregatingColumns.forEach(column => {
const values = rows.map(d => d[column.id])
aggregationValues[column.id] = column.aggregate(values, rows)
})
return aggregationValues
}
let standardColumns = pivotBy.length ? allVisibleColumns.slice(1) : allVisibleColumns
const aggregatingColumns = standardColumns.filter(d => d.aggregate)
let pivotColumn
if (pivotBy.length) {
pivotColumn = allVisibleColumns[0]
const groupRecursively = (rows, keys, i = 0) => {
// This is the last level, just return the rows
if (i === keys.length) {
return rows
}
// Group the rows together for this level
let groupedRows = Object.entries(
_.groupBy(rows, keys[i]))
.map(([key, value]) => {
return {
[pivotIDKey]: keys[i],
[pivotValKey]: key,
[keys[i]]: key,
[subRowsKey]: value
}
})
// Recurse into the subRows
groupedRows = groupedRows.map(rowGroup => {
let subRows = groupRecursively(rowGroup[subRowsKey], keys, i + 1)
return {
...rowGroup,
[subRowsKey]: subRows,
...aggregate(subRows)
}
})
return groupedRows
}
resolvedData = groupRecursively(resolvedData, pivotBy)
}
const newPages = _.getFirstDefined(pages, Math.ceil(resolvedData.length / pageSize))
const newPage = page > newPages ? newPage - 1 : page
return {
...newState,
resolvedData,
pivotColumn,
allVisibleColumns,
headerGroups,
allDecoratedColumns,
hasHeaderGroups,
page: Math.max(newPage, 0)
}
},
getSortedData (resolvedState) {
const {
manual,
sorting,
filtering,
showFilters,
defaultFilterMethod,
resolvedData,
allVisibleColumns
} = resolvedState
// Resolve the data from either manual data or sorted data
return {
sortedData: manual ? resolvedData : this.sortData(resolvedData, sorting, showFilters, filtering, defaultFilterMethod, allVisibleColumns)
}
},
fireOnChange () {
this.props.onChange(this.getResolvedState(), this)
},
getPropOrState (key) {
return _.getFirstDefined(this.props[key], this.state[key])
},
getStateOrProp (key) {
return _.getFirstDefined(this.state[key], this.props[key])
},
sortData (data, sorting, showFilters, filtering, defaultFilterMethod, allVisibleColumns) {
let filteredData = data
if (showFilters && filtering.length) {
filteredData = filtering.reduce(
(filteredSoFar, nextFilter) => {
return filteredSoFar.filter(
(row) => {
const column = allVisibleColumns.find(x => x.id === nextFilter.id) || {}
const filterMethod = column.filterMethod || defaultFilterMethod
return filterMethod(nextFilter, row, column)
})
}
, filteredData
)
}
if (!sorting.length) {
return filteredData
}
const sorted = _.orderBy(filteredData, sorting.map(sort => {
return row => {
if (row[sort.id] === null || row[sort.id] === undefined) {
return -Infinity
}
return typeof row[sort.id] === 'string' ? row[sort.id].toLowerCase() : row[sort.id]
}
}), sorting.map(d => !d.desc))
return sorted.map(row => {
if (!row[this.props.subRowsKey]) {
return row
}
return {
...row,
[this.props.subRowsKey]: this.sortData(row[this.props.subRowsKey], sorting)
}
})
},
getMinRows () {
return _.getFirstDefined(this.props.minRows, this.getStateOrProp('pageSize'))
},
// User actions
onPageChange (page) {
const {onPageChange, collapseOnPageChange} = this.props
if (onPageChange) {
return onPageChange(page)
}
const newState = {page}
if (collapseOnPageChange) {
newState.expandedRows = {}
}
this.setStateWithData(
newState
, () => {
this.fireOnChange()
})
},
onPageSizeChange (newPageSize) {
const {onPageSizeChange} = this.props
const {pageSize, page} = this.getResolvedState()
// Normalize the page to display
const currentRow = pageSize * page
const newPage = Math.floor(currentRow / newPageSize)
if (onPageSizeChange) {
return onPageSizeChange(newPageSize, newPage)
}
this.setStateWithData({
pageSize: newPageSize,
page: newPage
}, () => {
this.fireOnChange()
})
},
sortColumn (column, additive) {
const {sorting} = this.getResolvedState()
const {onSortingChange} = this.props
if (onSortingChange) {
return onSortingChange(column, additive)
}
let newSorting = _.clone(sorting || []).map(d => {
d.desc = _.isSortingDesc(d)
return d
})
if (!_.isArray(column)) {
// Single-Sort
const existingIndex = newSorting.findIndex(d => d.id === column.id)
if (existingIndex > -1) {
const existing = newSorting[existingIndex]
if (existing.desc) {
if (additive) {
newSorting.splice(existingIndex, 1)
} else {
existing.desc = false
newSorting = [existing]
}
} else {
existing.desc = true
if (!additive) {
newSorting = [existing]
}
}
} else {
if (additive) {
newSorting.push({
id: column.id,
desc: false
})
} else {
newSorting = [{
id: column.id,
desc: false
}]
}
}
} else {
// Multi-Sort
const existingIndex = newSorting.findIndex(d => d.id === column[0].id)
// Existing Sorted Column
if (existingIndex > -1) {
const existing = newSorting[existingIndex]
if (existing.desc) {
if (additive) {
newSorting.splice(existingIndex, column.length)
} else {
column.forEach((d, i) => {
newSorting[existingIndex + i].desc = false
})
}
} else {
column.forEach((d, i) => {
newSorting[existingIndex + i].desc = true
})
}
if (!additive) {
newSorting = newSorting.slice(existingIndex, column.length)
}
} else {
// New Sort Column
if (additive) {
newSorting = newSorting.concat(column.map(d => ({
id: d.id,
desc: false
})))
} else {
newSorting = column.map(d => ({
id: d.id,
desc: false
}))
}
}
}
this.setStateWithData({
page: ((!sorting.length && newSorting.length) || !additive) ? 0 : this.state.page,
sorting: newSorting
}, () => {
this.fireOnChange()
})
},
filterColumn (column, event) {
const {filtering} = this.getResolvedState()
const {onFilteringChange} = this.props
if (onFilteringChange) {
return onFilteringChange(column, event)
}
// Remove old filter first if it exists
const newFiltering = (filtering || []).filter(x => x.id !== column.id)
if (event.target.value !== '') {
newFiltering.push({
id: column.id,
value: event.target.value
})
}
this.setStateWithData({
page: 0,
filtering: newFiltering
}, () => {
this.fireOnChange()
})
}
}
-126
View File
@@ -1,126 +0,0 @@
import React from 'react'
import classnames from 'classnames'
//
// import _ from './utils'
const defaultButton = (props) => (
<button type='button' {...props} className='-btn'>{props.children}</button>
)
export default React.createClass({
getInitialState () {
return {
page: this.props.page
}
},
componentWillReceiveProps (nextProps) {
this.setState({page: nextProps.page})
},
getSafePage (page) {
return Math.min(Math.max(page, 0), this.props.pages - 1)
},
changePage (page) {
page = this.getSafePage(page)
this.setState({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
pages,
// Props
page,
showPageSizeOptions,
pageSizeOptions,
pageSize,
showPageJump,
canPrevious,
canNext,
onPageSizeChange,
className,
PreviousComponent = defaultButton,
NextComponent = defaultButton
} = this.props
return (
<div
className={classnames(className, '-pagination')}
style={this.props.paginationStyle}
>
<div className='-previous'>
<PreviousComponent
onClick={(e) => {
if (!canPrevious) return
this.changePage(page - 1)
}}
disabled={!canPrevious}
>
{this.props.previousText}
</PreviousComponent>
</div>
<div className='-center'>
<span className='-pageInfo'>
{this.props.pageText} {showPageJump ? (
<div className='-pageJump'>
<input
type={this.state.page === '' ? 'text' : 'number'}
onChange={e => {
const val = e.target.value
const page = val - 1
if (val === '') {
return this.setState({page: val})
}
this.setState({page: this.getSafePage(page)})
}}
value={this.state.page === '' ? '' : this.state.page + 1}
onBlur={this.applyPage}
onKeyPress={e => {
if (e.which === 13 || e.keyCode === 13) {
this.applyPage()
}
}}
/>
</div>
) : (
<span className='-currentPage'>{page + 1}</span>
)} {this.props.ofText} <span className='-totalPages'>{pages}</span>
</span>
{showPageSizeOptions && (
<span className='select-wrap -pageSizeOptions'>
<select
onChange={(e) => onPageSizeChange(Number(e.target.value))}
value={pageSize}
>
{pageSizeOptions.map((option, i) => {
return (
<option
key={i}
value={option}>
{option} {this.props.rowsText}
</option>
)
})}
</select>
</span>
)}
</div>
<div className='-next'>
<NextComponent
onClick={(e) => {
if (!canNext) return
this.changePage(page + 1)
}}
disabled={!canNext}
>
{this.props.nextText}
</NextComponent>
</div>
</div>
)
}
})
+38 -145
View File
@@ -1,50 +1,37 @@
import React from 'react'
import classnames from 'classnames'
//
export default {
get,
set,
takeRight,
last,
orderBy,
range,
remove,
clone,
getFirstDefined,
sum,
makeTemplateComponent,
groupBy,
isArray,
splitProps,
compactObject,
isSortingDesc,
normalizeComponent
remove,
getFirstDefined
}
function get (obj, path, def) {
if (!path) {
return obj
}
const pathObj = makePathArray(path)
let val
try {
val = pathObj.reduce((current, pathPart) => current[pathPart], obj)
} catch (e) {}
return typeof val !== 'undefined' ? val : def
}
function set (obj = {}, path, value) {
const keys = makePathArray(path)
let keyPart
let cursor = obj
while ((keyPart = keys.shift()) && keys.length) {
if (!cursor[keyPart]) {
cursor[keyPart] = {}
function remove (a, b) {
return a.filter(function (o, i) {
var r = b(o)
if (r) {
a.splice(i, 1)
return true
}
cursor = cursor[keyPart]
return false
})
}
function get (a, b) {
if (isArray(b)) {
b = b.join('.')
}
cursor[keyPart] = value
return obj
return b
.replace('[', '.').replace(']', '')
.split('.')
.reduce(
function (obj, property) {
return obj[property]
}, a
)
}
function takeRight (arr, n) {
@@ -78,34 +65,25 @@ function orderBy (arr, funcs, dirs) {
return desc ? 1 : -1
}
}
return dirs[0]
? a.__index - b.__index
: b.__index - b.__index
})
}
function remove (a, b) {
return a.filter(function (o, i) {
var r = b(o)
if (r) {
a.splice(i, 1)
return true
}
return false
return 0
})
}
function clone (a) {
try {
return JSON.parse(JSON.stringify(a, (key, value) => {
if (typeof value === 'function') {
return value.toString()
}
return value
}))
} catch (e) {
return a
}
return JSON.parse(JSON.stringify(a, function (key, value) {
if (typeof value === 'function') {
return value.toString()
}
return value
}))
}
// ########################################################################
// Helpers
// ########################################################################
function isArray (a) {
return Array.isArray(a)
}
function getFirstDefined (...args) {
@@ -115,88 +93,3 @@ function getFirstDefined (...args) {
}
}
}
function sum (arr) {
return arr.reduce((a, b) => {
return a + b
}, 0)
}
function makeTemplateComponent (compClass) {
return ({children, className, ...rest}) => (
<div
className={classnames(compClass, className)}
{...rest}
>
{children}
</div>
)
}
function groupBy (xs, key) {
return xs.reduce((rv, x, i) => {
const resKey = typeof key === 'function' ? key(x, i) : x[key]
rv[resKey] = isArray(rv[resKey]) ? rv[resKey] : []
rv[resKey].push(x)
return rv
}, {})
}
function isArray (a) {
return Array.isArray(a)
}
// ########################################################################
// Non-exported Helpers
// ########################################################################
function makePathArray (obj) {
return flattenDeep(obj)
.join('.')
.replace('[', '.')
.replace(']', '')
.split('.')
}
function flattenDeep (arr, newArr = []) {
if (!isArray(arr)) {
newArr.push(arr)
} else {
for (var i = 0; i < arr.length; i++) {
flattenDeep(arr[i], newArr)
}
}
return newArr
}
function splitProps ({className, style, ...rest}) {
return {
className,
style,
rest
}
}
function compactObject (obj) {
const newObj = {}
for (var key in obj) {
if (obj.hasOwnProperty(key) && obj[key] !== undefined && typeof obj[key] !== 'undefined') {
newObj[key] = obj[key]
}
}
return newObj
}
function isSortingDesc (d) {
return !!(d.sort === 'desc' || d.desc === true || d.asc === false)
}
function normalizeComponent (Comp, params = {}, fallback = Comp) {
return typeof Comp === 'function' ? (
Object.getPrototypeOf(Comp).isReactComponent ? (
<Comp
{...params}
/>
) : Comp(params)
) : fallback
}
-170
View File
@@ -1,170 +0,0 @@
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
export default () => {
const data = _.map(_.range(5553), d => {
const statusChance = Math.random()
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
progress: Math.floor(Math.random() * 100),
status: statusChance > 0.66 ? 'relationship'
: statusChance > 0.33 ? 'complicated'
: 'single'
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Profile Progress',
accessor: 'progress',
render: row => (
<div
style={{
width: '100%',
height: '100%',
backgroundColor: '#dadada',
borderRadius: '2px'
}}
>
<div
style={{
width: `${row.value}%`,
height: '100%',
backgroundColor: row.value > 66 ? '#85cc00'
: row.value > 33 ? '#ffbf00'
: '#ff2e00',
borderRadius: '2px',
transition: 'all .2s ease-out'
}}
/>
</div>
)
}, {
header: 'Status',
accessor: 'status',
render: row => (
<span>
<span style={{
color: row.value === 'relationship' ? '#ff2e00'
: row.value === 'complicated' ? '#ffbf00'
: '#57d500',
transition: 'all .3s ease'
}}>
&#x25cf;
</span> {
row.value === 'relationship' ? 'In a relationship'
: row.value === 'complicated' ? `It's complicated`
: 'Single'
}
</span>
)
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
<CodeHighlight>{() => getCode()}</CodeHighlight>
</div>
)
}
function getCode () {
return `
import ReactTable from 'react-table'
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Profile Progress',
accessor: 'progress',
render: row => (
<div
style={{
width: '100%',
height: '100%',
backgroundColor: '#dadada',
borderRadius: '2px'
}}
>
<div
style={{
width: \`$\{row.value}%\`,
height: '100%',
backgroundColor: row.value > 66 ? '#85cc00'
: row.value > 33 ? '#ffbf00'
: '#ff2e00',
borderRadius: '2px',
transition: 'all .2s ease-out'
}}
/>
</div>
)
}, {
header: 'Status',
accessor: 'status',
render: row => (
<span>
<span style={{
color: row.value === 'relationship' ? '#ff2e00'
: row.value === 'complicated' ? '#ffbf00'
: '#57d500',
transition: 'all .3s ease'
}}>
&#x25cf;
</span> {
row.value === 'relationship' ? 'In a relationship'
: row.value === 'complicated' ? \`It's complicated\`
: 'Single'
}
</span>
)
}]
}]
return (
<ReactTable
data={data}
columns={columns}
defaultPageSize={10}
/>
)
`
}
-106
View File
@@ -1,106 +0,0 @@
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
export default () => {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30)
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
}]
}]
return (
<div>
<strong>Hey!</strong> Open your console! :)
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
getTdProps={(state, rowInfo, column, instance) => {
return {
onMouseEnter: e => console.log('Cell - onMouseEnter', {
state,
rowInfo,
column,
instance,
event: e
})
}
}}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
<CodeHighlight>{() => getCode()}</CodeHighlight>
</div>
)
}
function getCode () {
return `
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
}]
}]
return (
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
getTdProps={(state, rowInfo, column, instance) => {
return {
onMouseEnter: e => console.log('Cell - onMouseEnter', {
state,
rowInfo,
column,
instance,
event: e
})
}
}}
/>
)
`
}
-106
View File
@@ -1,106 +0,0 @@
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
export default () => {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30)
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName',
render: row => {
return <span>{row.aggregated ? '...' : row.value}</span>
}
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age',
aggregate: vals => _.round(_.mean(vals)),
render: row => {
return <span>{row.aggregated ? `${row.value} (avg)` : row.value}</span>
}
}]
}, {
expander: true
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
SubComponent={() => <span>Hello</span>}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
<CodeHighlight>{() => getCode()}</CodeHighlight>
</div>
)
}
function getCode () {
return `
import ReactTable from 'react-table'
// Create some column definitions
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName',
render: row => {
return <span>{row.aggregated ? '...' : row.value}</span>
}
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age',
aggregate: vals => _.round(_.mean(vals)),
render: row => {
return <span>{row.aggregated ? \`$\{row.value} (avg)\` : row.value}</span>
}
}]
}, {
expander: true
}]
return (
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
SubComponent={() => <span>Hello</span>}
/>
)
`
}
-91
View File
@@ -1,91 +0,0 @@
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
export default () => {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30)
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName',
maxWidth: 200
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName,
width: 300
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age',
minWidth: 400
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
<CodeHighlight>{() => getCode()}</CodeHighlight>
</div>
)
}
function getCode () {
return `
import ReactTable from 'react-table'
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName',
maxWidth: 200
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName,
width: 300
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age',
minWidth: 400
}]
}]
return (
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
/>
)
`
}
-91
View File
@@ -1,91 +0,0 @@
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
export default () => {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30)
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
defaultSorting={[{
id: 'age',
desc: true
}]}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
<CodeHighlight>{() => getCode()}</CodeHighlight>
</div>
)
}
function getCode () {
return `
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
}]
}]
return (
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
defaultSorting={[{
id: 'age',
desc: true
}]}
/>
)
`
}
-206
View File
@@ -1,206 +0,0 @@
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
class Filtering extends React.Component {
constructor(props) {
super(props)
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({words: 1, numLen: 0}),
lastName: namor.generate({words: 1, numLen: 0}),
age: Math.floor(Math.random() * 30)
}
})
this.state = {
tableOptions: {
loading: false,
showPagination: true,
showPageSizeOptions: true,
showPageJump: true,
collapseOnSortingChange: true,
collapseOnPageChange: true,
collapseOnDataChange: true,
freezeWhenExpanded: false,
showFilters: true
},
data: data
}
this.setTableOption = this.setTableOption.bind(this);
}
render() {
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName',
filterMethod: (filter, row) => (row[filter.id].startsWith(filter.value) && row[filter.id].endsWith(filter.value))
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName,
filterMethod: (filter, row) => (row[filter.id].includes(filter.value))
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
}]
}]
return (
<div>
<div style={{float: "left"}}>
<h1>Table Options</h1>
<table>
<tbody>
{
Object.keys(this.state.tableOptions).map(optionKey => {
const optionValue = this.state.tableOptions[optionKey];
return (
<tr key={optionKey}>
<td>{optionKey}</td>
<td style={{paddingLeft: 10, paddingTop: 5}}>
<input type="checkbox"
name={optionKey}
checked={optionValue}
onChange={this.setTableOption}
/>
</td>
</tr>
)
})
}
</tbody>
</table>
</div>
<div className='table-wrap' style={{paddingLeft: 240}}>
<ReactTable
className='-striped -highlight'
data={this.state.data}
columns={columns}
defaultPageSize={10}
defaultFilterMethod={(filter, row) => ((row[filter.id] + "").startsWith(filter.value))}
{...this.state.tableOptions}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>You can put any component you want here, even another React Table!</em>
<br />
<br />
<ReactTable
data={this.state.data}
columns={columns}
defaultPageSize={3}
showPagination={false}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>It even has access to the row data: </em>
<CodeHighlight>{() => JSON.stringify(row, null, 2)}</CodeHighlight>
</div>
)
}}
/>
</div>
)
}}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
<div>
<h1>Custom Filters In This Example</h1>
<p>The default filter for all columns of a table if it is not specified in the configuration is set to be an exact match. Example: age == "23".</p>
<p>This example overrides the default filter behavior by setting the <strong>defaultFilterMethod</strong> table option to match on values that start with the filter text. Example: age.startsWith("2")</p>
<p>Each column can also be customized with the column <strong>filterMethod</strong> option:</p>
<p>In this example the firstName column filters on the value starting with and ending with the filter value.</p>
<p>In this example the lastName column filters on the value including the filter value anywhere in its text.</p>
</div>
<CodeHighlight>{() => this.getCode()}</CodeHighlight>
</div>
)
}
setTableOption(event) {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
tableOptions: {
...this.state.tableOptions,
[name]: value
}
})
}
getCode() {
return `
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName',
filterMethod: (filter, row) => (row[filter.id].startsWith(filter.value) && row[filter.id].endsWith(filter.value))
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName,
filterMethod: (filter, row) => (row[filter.id].includes(filter.value))
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
}]
}]
export default (
<ReactTable
data={data}
columns={columns}
defaultPageSize={10}
defaultFilterMethod={(filter, row) => ((row[filter.id] + \"\").startsWith(filter.value))}
{...otherOptions}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>You can put any component you want here, even another React Table!</em>
<br />
<br />
<ReactTable
data={data}
columns={columns}
defaultPageSize={3}
showPagination={false}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>It even has access to the row data: </em>
<CodeHighlight>{() => JSON.stringify(row, null, 2)}</CodeHighlight>
</div>
)
}}
/>
</div>
)
}}
/>
)
`
}
}
export default () => <Filtering/>
-114
View File
@@ -1,114 +0,0 @@
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
export default () => {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30)
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName',
footer: (
<span><strong>Popular:</strong> {
_.first(
_.reduce(
_.map(
_.groupBy(
data, d => d.firstName
)
),
(a, b) => a.length > b.length ? a : b
)
).firstName}
</span>
)
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName,
footer: (
<span><strong>Longest:</strong> {
_.reduce(
_.map(
_.groupBy(
data, d => d.lastName
),
(d, key) => key
),
(a, b) => a.length > b.length ? a : b
)}
</span>
)
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age',
footer: <span><strong>Average:</strong> {_.round(_.mean(_.map(data, d => d.age)))}</span>
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
<CodeHighlight>{() => getCode()}</CodeHighlight>
</div>
)
}
function getCode () {
return `
import ReactTable from 'react-table'
// Create some column definitions
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
}]
}]
// Display your table!
return (
<ReactTable
data={data}
columns={columns}
defaultPageSize={10}
/>
)
`
}
-173
View File
@@ -1,173 +0,0 @@
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import JSONTree from 'react-json-tree'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
const JSONtheme = {
scheme: 'monokai',
author: 'wimer hazenberg (http://www.monokai.nl)',
base00: '#272822',
base01: '#383830',
base02: '#49483e',
base03: '#75715e',
base04: '#a59f85',
base05: '#f8f8f2',
base06: '#f5f4f1',
base07: '#f9f8f5',
base08: '#f92672',
base09: '#fd971f',
base0A: '#f4bf75',
base0B: '#a6e22e',
base0C: '#a1efe4',
base0D: '#66d9ef',
base0E: '#ae81ff',
base0F: '#cc6633'
}
export default () => {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30)
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName',
footer: 'Footer'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName,
footer: 'Footer'
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age',
footer: 'Footer'
}]
}]
return (
<div>
<strong>Functional rendering</strong> simply means that you have all of the building blocks to render your own React Table however you'd like.
<br />
<br />
<br />
<br />
<strong>Decorating the standard table output</strong>
<br />
<br />
<div className='table-wrap'>
<ReactTable
data={data}
columns={columns}
>
{(state, makeTable, instance) => {
return (
<div style={{
background: '#ffcf00',
borderRadius: '5px',
overflow: 'hidden',
padding: '5px'
}}>
<pre><code>state.allVisibleColumns === {JSON.stringify(state.allVisibleColumns, null, 4)}</code></pre>
{makeTable()}
</div>
)
}}
</ReactTable>
</div>
<CodeHighlight>{() => `
import ReactTable from 'react-table'
return (
<ReactTable
data={data}
columns={columns}
>
{(state, Table, instance) => {
return (
<div style={{
background: '#ffcf00',
borderRadius: '5px',
overflow: 'hidden',
padding: '5px'
}}>
<pre><code>state.allVisibleColumns === {JSON.stringify(state.allVisibleColumns, null, 4)}</code></pre>
<Table />
</div>
)
}}
</ReactTable>
)
`}</CodeHighlight>
<br />
<br />
<strong>Need more control? This is the entire table state and component instance at your disposal!</strong>
<br />
<br />
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
>
{(state, StandardTable, instance) => {
return (
<div>
<JSONTree
data={Object.assign({}, state, {children: 'function () {...}'})}
theme={JSONtheme}
invertTheme
/>
</div>
)
}}
</ReactTable>
</div>
<br />
<CodeHighlight>{() => `
import ReactTable from 'react-table'
return (
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
>
{(state, StandardTable, instance) => {
return (
<div>
<JSONTree
data={Object.assign({}, state, {children: 'function () {...}'})}
theme={JSONtheme}
invertTheme
/>
</div>
)
}}
</ReactTable>
)
`}</CodeHighlight>
</div>
)
}
-92
View File
@@ -1,92 +0,0 @@
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
export default () => {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30)
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={[]}
noDataText='Oh Noes!'
// noDataText={() => 'Oh Noes!'} // Supports functions
// noDataText={() => <span>Oh Noes!</span>} // Supports JSX / React Components
columns={columns}
defaultPageSize={10}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
<CodeHighlight>{() => getCode()}</CodeHighlight>
</div>
)
}
function getCode () {
return `
import ReactTable from 'react-table'
// Create some column definitions
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
}]
}]
// Display your table!
return (
<ReactTable
data={[]}
noDataText='Oh Noes!'
// noDataText={() => 'Oh Noes!'} // Supports functions
// noDataText={() => <span>Oh Noes!</span>} // Supports JSX / React Components
columns={columns}
defaultPageSize={10}
/>
)
`
}
-148
View File
@@ -1,148 +0,0 @@
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>
}
}, {
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 />
<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>
)
}}
/>
)
`
}
-102
View File
@@ -1,102 +0,0 @@
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>
}
}, {
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']}
/>
</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}
className='-striped -highlight'
defaultPageSize={10}
pivotBy={['firstName', 'lastName']}
/>
)
`
}
-152
View File
@@ -1,152 +0,0 @@
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
export default () => {
const data = _.map(_.range(1000), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30),
visits: Math.floor(Math.random() * 100)
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age',
aggregate: vals => _.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)
}]
}]
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)
}]
}]
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 />
<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>
)
}}
/>
)
`
}
-176
View File
@@ -1,176 +0,0 @@
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 => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30)
}
})
// 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) => {
return new Promise((resolve, reject) => {
// On the server, you'll likely use SQL or noSQL or some other query language to do this.
// For this mock, we'll just use lodash
let filteredData = rawData
if (filtering.length) {
filteredData = filtering.reduce(
(filteredSoFar, nextFilter) => {
return filteredSoFar.filter(
(row) => {
return (row[nextFilter.id] + '').includes(nextFilter.value)
})
}
, filteredData)
}
const sortedData = _.orderBy(filteredData, sorting.map(sort => {
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'))
// Be sure to send back the rows to be displayed and any other pertinent information, like how many pages there are total.
const res = {
rows: sortedData.slice(pageSize * page, (pageSize * page) + pageSize),
pages: Math.ceil(filteredData.length / pageSize)
}
// Here we'll simulate a server response with 500ms of delay.
setTimeout(() => resolve(res), 500)
})
}
const ServerSide = React.createClass({
getInitialState () {
// To handle our data server-side, we need a few things in the state to help us out:
return {
data: [],
pages: null,
loading: true
}
},
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)
.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,
pages: res.pages,
loading: false
})
})
},
render () {
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
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
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
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
<CodeHighlight>{() => getCode()}</CodeHighlight>
</div>
)
}
})
export default () => (
<ServerSide />
)
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
/>
}
})
`
}
-86
View File
@@ -1,86 +0,0 @@
import React from 'react'
import _ from 'lodash'
import namor from 'namor'
import CodeHighlight from './components/codeHighlight'
import ReactTable from '../src/index'
export default () => {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30)
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
}]
}]
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
data={data}
columns={columns}
defaultPageSize={10}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
<CodeHighlight>{() => getCode()}</CodeHighlight>
</div>
)
}
function getCode () {
return `
import ReactTable from 'react-table'
// Create some column definitions
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
}]
}]
// Display your table!
return (
<ReactTable
data={data}
columns={columns}
defaultPageSize={10}
/>
)
`
}
-194
View File
@@ -1,194 +0,0 @@
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) {
super(props)
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({words: 1, numLen: 0}),
lastName: namor.generate({words: 1, numLen: 0}),
age: Math.floor(Math.random() * 30)
}
})
this.state = {
tableOptions: {
loading: false,
showPagination: true,
showPageSizeOptions: true,
showPageJump: true,
collapseOnSortingChange: true,
collapseOnPageChange: true,
collapseOnDataChange: true,
freezeWhenExpanded: false,
showFilters: false
},
data: data
}
this.setTableOption = this.setTableOption.bind(this);
}
render() {
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
}]
}, {
header: 'Info',
columns: [{
header: 'Age',
accessor: 'age'
}]
}]
return (
<div>
<div style={{float: "left"}}>
<h1>Table Options</h1>
<table>
<tbody>
{
Object.keys(this.state.tableOptions).map(optionKey => {
const optionValue = this.state.tableOptions[optionKey];
return (
<tr key={optionKey}>
<td>{optionKey}</td>
<td style={{paddingLeft: 10, paddingTop: 5}}>
<input type="checkbox"
name={optionKey}
checked={optionValue}
onChange={this.setTableOption}
/>
</td>
</tr>
)
})
}
</tbody>
</table>
</div>
<div className='table-wrap' style={{paddingLeft: 240}}>
<ReactTable
className='-striped -highlight'
data={this.state.data}
columns={columns}
defaultPageSize={10}
{...this.state.tableOptions}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>You can put any component you want here, even another React Table!</em>
<br />
<br />
<ReactTable
data={this.state.data}
columns={columns}
defaultPageSize={3}
showPagination={false}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>It even has access to the row data: </em>
<CodeHighlight>{() => JSON.stringify(row, null, 2)}</CodeHighlight>
</div>
)
}}
/>
</div>
)
}}
/>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
</div>
<CodeHighlight>{() => this.getCode()}</CodeHighlight>
</div>
)
}
setTableOption(event) {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
tableOptions: {
...this.state.tableOptions,
[name]: value
}
})
}
getCode() {
return `
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
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/>
-21
View File
@@ -1,21 +0,0 @@
import React from 'react'
import '../utils/prism'
export default React.createClass({
render () {
const { language, children } = this.props
return (
<pre>
<code className={'language-' + (language || 'jsx')}>
{children()}
</code>
</pre>
)
},
componentDidMount () {
window.Prism.highlightAll()
},
componentDidUpdate () {
window.Prism.highlightAll()
}
})
-138
View File
@@ -1,138 +0,0 @@
/* http://prismjs.com/download.html?themes=prism&languages=markup+css+clike+javascript */
/**
* prism.js default theme for JavaScript, CSS and HTML
* Based on dabblet (http://dabblet.com)
* @author Lea Verou
*/
code[class*="language-"],
pre[class*="language-"] {
color: black;
background: none;
text-shadow: 0 1px white;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection {
text-shadow: none;
background: #b3d4fc;
}
pre[class*="language-"]::selection, pre[class*="language-"] ::selection,
code[class*="language-"]::selection, code[class*="language-"] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
}
:not(pre) > code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}
/* Inline code */
:not(pre) > code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #999;
}
.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #690;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #a67f59;
background: hsla(0, 0%, 100%, .5);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}
.token.function {
color: #DD4A68;
}
.token.regex,
.token.important,
.token.variable {
color: #e90;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
File diff suppressed because one or more lines are too long
-5886
View File
File diff suppressed because it is too large Load Diff