mirror of
https://github.com/gosticks/react-table.git
synced 2026-08-19 08:20:30 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
29eda4dc71 | ||
|
|
e5689bc9d4 | ||
|
|
dd433f7d9c | ||
|
|
0daffaf08d | ||
|
|
ecd660ef10 | ||
|
|
be951a3252 | ||
|
|
f195b3243d | ||
|
|
19a0187720 | ||
|
|
d8e5188d94 | ||
|
|
8c79bf95df | ||
|
|
6053c48781 | ||
|
|
8f1c8774f2 | ||
|
|
d5795fb5ac | ||
|
|
8abbefa680 | ||
|
|
4db644941a | ||
|
|
6905ccae72 | ||
|
|
e832bf52b0 | ||
|
|
3432fefce2 | ||
|
|
2abcc86954 | ||
|
|
610972d99e | ||
|
|
c99796342b | ||
|
|
1b4d8bd45f | ||
|
|
e922a43741 | ||
|
|
75317c2251 | ||
|
|
e531ef1f64 | ||
|
|
598d33410a | ||
|
|
57ac1f142d | ||
|
|
e181f8e3d1 | ||
|
|
5e19459eba | ||
|
|
cad0ac49cb | ||
|
|
b5d17cdbce | ||
|
|
a5d9e15b5d | ||
|
|
c9cf436576 | ||
|
|
ece0ddc8a4 | ||
|
|
dbc90c2e63 | ||
|
|
2b0e1eb8a7 | ||
|
|
3d0f38f2c5 | ||
|
|
516b88468e | ||
|
|
07cd241ced |
@@ -3,3 +3,6 @@ lib/
|
||||
react-table.js
|
||||
react-table.css
|
||||
*.log
|
||||
example/dist/
|
||||
|
||||
storybook-static
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
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 ServerSide from '../stories/ServerSide.js'
|
||||
import SubComponents from '../stories/SubComponents.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('Client-side Data', Simple)
|
||||
.add('Server-side Data', ServerSide)
|
||||
.add('Sub Components', SubComponents)
|
||||
}, module)
|
||||
@@ -0,0 +1,6 @@
|
||||
@import url("https://fonts.googleapis.com/css?family=Open+Sans:300,600");
|
||||
body {
|
||||
background: #fff;
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
font-weight: 300;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
body{
|
||||
padding: 20px;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/* 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;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
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
|
||||
}
|
||||
@@ -1,21 +1,24 @@
|
||||

|
||||
<div align="center">
|
||||
<a href="https://github.com/tannerlinsley/react-table"><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
|
||||
A fast, lightweight, opinionated table and datagrid built on React
|
||||
</div>
|
||||
|
||||
[](https://travis-ci.org/tannerlinsley/react-table)
|
||||
[](https://react-table-slack.herokuapp.com/)
|
||||
# React Table
|
||||
`react-table` is a **lightweight, fast and extendable datagrid** built for React
|
||||
|
||||
[](https://travis-ci.org/tannerlinsley/react-table) [](https://npmjs.com/packag/react-table) [](https://react-table-slack.herokuapp.com/) [](https://github.com/tannerlinsley/react-table) [](https://twitter.com/tannerlinsley)
|
||||
|
||||
## Features
|
||||
|
||||
- Lightweight at 3kb (and just 2kb more for styles)
|
||||
- No composition needed
|
||||
- Uses customizable JSX and callbacks for everything
|
||||
- Client-side pagination and sorting
|
||||
- Server-side data
|
||||
- Lightweight at 4kb (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
|
||||
- <a href="https://medium.com/@tannerlinsley/why-i-wrote-react-table-and-the-problems-it-has-solved-for-nozzle-others-445c4e93d4a8#.axza4ixba" target="\_blank">"Why I wrote React Table and the problems it has solved for Nozzle.io</a> by Tanner Linsley
|
||||
|
||||
## [Demo](http://react-table.zabapps.com)
|
||||
## <a href="http://react-table.zabapps.com/?selectedKind=2.%20Demos&selectedStory=Client-side%20Data&full=0&down=1&left=1&panelRight=0&downPanel=kadirahq%2Fstorybook-addon-actions%2Factions-panel" target="\_blank">Demo</a>
|
||||
|
||||
## Table of Contents
|
||||
- [Installation](#nstallation)
|
||||
@@ -25,6 +28,7 @@ A fast, lightweight, opinionated table and datagrid built on React
|
||||
- [Columns](#columns)
|
||||
- [Styles](#styles)
|
||||
- [Header Groups](#header-groups)
|
||||
- [Sub Tables & Components](#sub-tables--components)
|
||||
- [Server-side Data](#server-side-data)
|
||||
- [Multi-sort](#multi-sort)
|
||||
- [Component Overrides](#component-overrides)
|
||||
@@ -53,27 +57,28 @@ const data = [{
|
||||
|
||||
const columns = [{
|
||||
header: 'Name',
|
||||
accessor: 'name',
|
||||
accessor: 'name' // String-based value accessors !
|
||||
}, {
|
||||
header: 'Age',
|
||||
accessor: 'age'
|
||||
accessor: 'age',
|
||||
render: props => <span className='number'>props.value</span> // Custom cell components!
|
||||
}, {
|
||||
header: 'Friend Name',
|
||||
accessor: d => d.friend.name
|
||||
accessor: d => d.friend.name // Custom value accessors!
|
||||
}, {
|
||||
header: 'Friend Age',
|
||||
header: props => <span>Friend Age</span>, // Custom header components!
|
||||
accessor: 'friend.age'
|
||||
}]
|
||||
|
||||
<ReactTable
|
||||
data=[data]
|
||||
data={data}
|
||||
columns={columns}
|
||||
/>
|
||||
```
|
||||
|
||||
<a name="data"></a>
|
||||
## Data
|
||||
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.
|
||||
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 as you change any props. [Server-side data](#server-side-data) is also supported!
|
||||
|
||||
|
||||
<a name="default-props"></a>
|
||||
@@ -82,12 +87,25 @@ These are the default props for the main react component `<ReactTable />`
|
||||
```javascript
|
||||
{
|
||||
// General
|
||||
pageSize: 20,
|
||||
loading: false, // Whether to show the loading overlay or not
|
||||
pageSize: 20, // The default page size (this can be changed by the user if `showPageSizeOptions` is enabled)
|
||||
minRows: 0, // Ensure this many rows are always rendered, regardless of rows on page
|
||||
showPagination: true, // Shows or hides the pagination component
|
||||
showPageJump: true, // Shows or hides the pagination number input
|
||||
showPageSizeOptions: true, // Enables the user to change the page size
|
||||
pageSizeOptions: [5, 10, 20, 25, 50, 100], // The available page size options
|
||||
expanderColumnWidth: 30, // default columnWidth for the expander column
|
||||
|
||||
// Callbacks
|
||||
onChange: (state, instance) => null, // Anytime the internal state of the table changes, this will fire
|
||||
onTrClick: (row, event) => null, // Handler for row click events
|
||||
|
||||
// Text
|
||||
previousText: 'Previous',
|
||||
nextText: 'Next'
|
||||
nextText: 'Next',
|
||||
pageText: 'Page',
|
||||
ofText: 'of',
|
||||
rowsText: 'rows',
|
||||
|
||||
// Classes
|
||||
className: '-striped -highlight', // The most top level className for the component
|
||||
@@ -134,7 +152,7 @@ Or just define them on the component per-instance
|
||||
|
||||
<a name="columns"></a>
|
||||
## Columns
|
||||
Every React-Table instance requires a `columns` prop, which is an array of objects containing the following properties
|
||||
`<ReactTable/>` requires a `columns` prop, which is an array of objects with the following properties
|
||||
|
||||
```javascript
|
||||
[{
|
||||
@@ -142,15 +160,13 @@ Every React-Table instance requires a `columns` prop, which is an array of objec
|
||||
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,
|
||||
sort: 'asc' or 'desc',
|
||||
show: true,
|
||||
minWidth: Number // Allows the column to flex above this minimum amount
|
||||
sort: 'asc' or 'desc', // used to determine the column sorting on init
|
||||
show: true, // can be used to hide a column
|
||||
minWidth: 100 // A minimum width for this column. If there is room, columns will flex to fill
|
||||
|
||||
// Cell Options
|
||||
className: '', // Set the classname of the `td` element of the column
|
||||
style: {}, // Set the style of the `td` element of the column
|
||||
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
|
||||
@@ -162,8 +178,6 @@ Every React-Table instance requires a `columns` prop, which is an array of objec
|
||||
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
|
||||
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
|
||||
@@ -194,49 +208,65 @@ const columns = [{
|
||||
}]
|
||||
```
|
||||
|
||||
<a name="server-side-data"></a>
|
||||
## Server-side Data
|
||||
If you want to handle pagination, and sorting on the server, `react-table` makes it easy on you. Instead of passing the `data` prop an array, you provide a function instead.
|
||||
|
||||
This function will be called on mount, pagination events, and sorting events. It also provides you all of the parameters to help you query and format your data.
|
||||
|
||||
## Sub Tables & Components
|
||||
By adding a `subComponent` props, you can easily add an expansion level to all root-level rows:
|
||||
```javascript
|
||||
<ReactTable
|
||||
data={(params, callback) => {
|
||||
|
||||
// params will give you all the info you need to query and sort your data
|
||||
params == {
|
||||
page: 0, // The page index the user is requesting
|
||||
pageSize: 20, // The current pageSize
|
||||
pages: -1, // The amount of existing pages (-1 means there is no page data yet)
|
||||
sorting: [ // An array of column sort models (yes, you can multi-sort!)
|
||||
{
|
||||
id: 'columnID', // The columnID (usually the accessor string, but can be overridden for server-side or required if the column accessor is a function)
|
||||
ascending: true or false
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// Query your data however you'd like, then structure your response like so:
|
||||
const result = {
|
||||
rows: [...], // Your data for the current page/sorting model
|
||||
pages: 10 // optionally provide how many pages exist (this is only needed if you choose to display page numbers, and only the first time you make the call or if the page count changes)
|
||||
}
|
||||
|
||||
// You can return a promise that resolve the result
|
||||
return Axios.post('/myDataEnpoint', params) // resolves to `result`
|
||||
|
||||
// or use the manual callback whenever you please
|
||||
setTimeout(() => {
|
||||
callback(result)
|
||||
}, 5000)
|
||||
|
||||
// That's it!
|
||||
|
||||
data={data}
|
||||
columns={columns}
|
||||
pageSize={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, 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. 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
|
||||
|
||||
```javascript
|
||||
<ReactTable
|
||||
...
|
||||
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
|
||||
})
|
||||
.then((res) => {
|
||||
// Update react-table
|
||||
this.setState({
|
||||
data: res.data.rows,
|
||||
pages: res.data.pages,
|
||||
loading: false
|
||||
})
|
||||
})
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
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!
|
||||
@@ -277,7 +307,7 @@ If you would like to help develop a suggested feature follow these steps:
|
||||
|
||||
- Fork this repo
|
||||
- `npm install`
|
||||
- `npm watch`
|
||||
- `npm run watch`
|
||||
- Implement your changes to files in the `src/` directory
|
||||
- Submit PR for review
|
||||
|
||||
@@ -287,6 +317,12 @@ If you would like to preview your changes, you can link and utilize the example
|
||||
- `cd example`
|
||||
- `npm install`
|
||||
- `npm link react-table`
|
||||
- `npm watch`
|
||||
- `npm run watch`
|
||||
- Make changes to the example in `src/screens/index.js` if needed
|
||||
- View changes at `localhost:8000`
|
||||
|
||||
## Used By
|
||||
|
||||
<a href='https://nozzle.io'>
|
||||
<img src='https://nozzle.io/img/logo-blue.png' alt='Nozzle Logo' style='width:300px;'/>
|
||||
</a>
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
# Jumpsuit Getting Started
|
||||
Vendored
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 35 KiB |
Vendored
-171
File diff suppressed because one or more lines are too long
Vendored
-59142
File diff suppressed because one or more lines are too long
Vendored
-13
@@ -1,13 +0,0 @@
|
||||
<!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>
|
||||
@@ -1,28 +0,0 @@
|
||||
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)
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
import { Render } from 'jumpsuit'
|
||||
import App from 'screens/index'
|
||||
|
||||
Render(null, <App />)
|
||||
@@ -1,79 +0,0 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// 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.
|
Before Width: | Height: | Size: 35 KiB |
@@ -1,13 +0,0 @@
|
||||
<!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>
|
||||
@@ -1,82 +0,0 @@
|
||||
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>
|
||||
)
|
||||
}
|
||||
})
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"name": "react-table",
|
||||
"root": "dist"
|
||||
}
|
||||
+17
-5
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-table",
|
||||
"version": "2.2.7",
|
||||
"version": "4.0.0",
|
||||
"description": "A fast, lightweight, opinionated table and datagrid built on React",
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/tannerlinsley/react-table#readme",
|
||||
@@ -16,6 +16,7 @@
|
||||
],
|
||||
"main": "lib/index.js",
|
||||
"files": [
|
||||
"src/",
|
||||
"lib/",
|
||||
"react-table.js",
|
||||
"react-table.css",
|
||||
@@ -24,19 +25,24 @@
|
||||
"scripts": {
|
||||
"build:node": "babel src --out-dir lib --source-maps inline",
|
||||
"build:css": "rm -rf react-table.css && stylus src/index.styl --use ./node_modules/nib/lib/nib.js --compress -o react-table.css",
|
||||
"watch": "onchange 'src/**' -i -- npm-run-all build:*",
|
||||
"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",
|
||||
"test": "standard",
|
||||
"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",
|
||||
"postpublish": "git push --tags"
|
||||
"storybook": "start-storybook -p 8000 -c .storybook",
|
||||
"deploy": "build-storybook && zab deploy"
|
||||
},
|
||||
"dependencies": {
|
||||
"classnames": "^2.2.5"
|
||||
"classnames": "^2.2.5",
|
||||
"inline-style-prefixer": "^2.0.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^15.3.1"
|
||||
"react": "^15.x.x"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@kadira/storybook": "^2.35.1",
|
||||
"babel-cli": "6.14.0",
|
||||
"babel-eslint": "6.1.2",
|
||||
"babel-preset-es2015": "6.14.0",
|
||||
@@ -44,9 +50,15 @@
|
||||
"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",
|
||||
"react": "^15.4.2",
|
||||
"react-dom": "^15.4.2",
|
||||
"standard": "^8.0.0",
|
||||
"stylus": "^0.54.5",
|
||||
"uglifyify": "3.0.3"
|
||||
|
||||
+414
-393
@@ -1,21 +1,33 @@
|
||||
import React from 'react'
|
||||
import classnames from 'classnames'
|
||||
import prefixAll from 'inline-style-prefixer/static'
|
||||
//
|
||||
const _ = {
|
||||
get,
|
||||
takeRight,
|
||||
last,
|
||||
orderBy,
|
||||
range,
|
||||
clone,
|
||||
remove
|
||||
}
|
||||
import _ from './utils'
|
||||
|
||||
const defaultButton = (props) => (
|
||||
<button {...props} className='-btn'>{props.children}</button>
|
||||
import Pagination from './pagination'
|
||||
|
||||
const makeTemplateComponent = (compClass) => ({children, className, ...rest}) => (
|
||||
<div
|
||||
className={classnames(compClass, className)}
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
|
||||
export const ReactTableDefaults = {
|
||||
// General
|
||||
data: [],
|
||||
loading: false,
|
||||
pageSize: 20,
|
||||
showPagination: true,
|
||||
showPageSizeOptions: true,
|
||||
pageSizeOptions: [5, 10, 20, 25, 50, 100],
|
||||
showPageJump: true,
|
||||
expanderColumnWidth: 30,
|
||||
// Callbacks
|
||||
onChange: () => null,
|
||||
onTrClick: () => null,
|
||||
// Classes
|
||||
className: '-striped -highlight',
|
||||
tableClassName: '',
|
||||
@@ -37,37 +49,63 @@ export const ReactTableDefaults = {
|
||||
thStyle: {},
|
||||
tdStyle: {},
|
||||
paginationStyle: {},
|
||||
//
|
||||
pageSize: 20,
|
||||
minRows: 0,
|
||||
// Global Column Defaults
|
||||
column: {
|
||||
sortable: true,
|
||||
show: true,
|
||||
className: '',
|
||||
style: {},
|
||||
innerClassName: '',
|
||||
innerStyle: {},
|
||||
headerClassName: '',
|
||||
headerStyle: {},
|
||||
headerInnerClassName: '',
|
||||
headerInnerStyle: {}
|
||||
headerInnerStyle: {},
|
||||
minWidth: 100
|
||||
},
|
||||
// Text
|
||||
previousText: 'Previous',
|
||||
nextText: 'Next',
|
||||
loadingText: 'Loading...',
|
||||
pageText: 'Page',
|
||||
ofText: 'of',
|
||||
rowsText: 'rows',
|
||||
// Components
|
||||
tableComponent: (props) => <table {...props}>{props.children}</table>,
|
||||
theadComponent: (props) => <thead {...props}>{props.children}</thead>,
|
||||
tbodyComponent: (props) => <tbody {...props}>{props.children}</tbody>,
|
||||
trComponent: (props) => <tr {...props}>{props.children}</tr>,
|
||||
thComponent: (props) => <th {...props}>{props.children}</th>,
|
||||
tdComponent: (props) => <td {...props}>{props.children}</td>,
|
||||
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'),
|
||||
expanderComponent: ({isOpen, toggle, ...rest}) => {
|
||||
return (
|
||||
<div
|
||||
className={classnames('rt-expander', isOpen && '-open')}
|
||||
{...rest}
|
||||
/>
|
||||
)
|
||||
},
|
||||
paginationComponent: Pagination,
|
||||
previousComponent: null,
|
||||
nextComponent: null,
|
||||
// Unlisted
|
||||
data: []
|
||||
loadingComponent: props => (
|
||||
<div className={classnames('-loading', {'-active': props.loading})}>
|
||||
<div className='-loading-inner'>
|
||||
{props.loadingText}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default React.createClass({
|
||||
@@ -76,91 +114,33 @@ export default React.createClass({
|
||||
},
|
||||
getInitialState () {
|
||||
return {
|
||||
sorting: false
|
||||
}
|
||||
},
|
||||
componentWillMount () {
|
||||
this.update(this.props)
|
||||
},
|
||||
componentWillReceiveProps (nextProps) {
|
||||
this.update(nextProps)
|
||||
},
|
||||
update (props) {
|
||||
const resetState = {
|
||||
loading: false,
|
||||
page: 0,
|
||||
pages: -1
|
||||
// columns: {} for column hiding in the future
|
||||
}
|
||||
this.setState(resetState)
|
||||
const newState = Object.assign({}, this.state, resetState)
|
||||
this.isAsync = typeof props.data === 'function'
|
||||
this.buildColumns(props, newState)
|
||||
this.buildData(props, newState)
|
||||
},
|
||||
buildColumns (props) {
|
||||
this.hasHeaderGroups = false
|
||||
props.columns.forEach(column => {
|
||||
if (column.columns) {
|
||||
this.hasHeaderGroups = true
|
||||
}
|
||||
})
|
||||
|
||||
this.headerGroups = []
|
||||
this.decoratedColumns = []
|
||||
let currentSpan = []
|
||||
|
||||
const addHeader = (columns, column = {}) => {
|
||||
this.headerGroups.push(Object.assign({}, column, {
|
||||
columns: columns
|
||||
}))
|
||||
currentSpan = []
|
||||
}
|
||||
const makeDecoratedColumn = (column) => {
|
||||
const dcol = Object.assign({}, this.props.column, column)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
return dcol
|
||||
}
|
||||
|
||||
props.columns.forEach((column, i) => {
|
||||
if (column.columns) {
|
||||
column.columns.forEach(nestedColumn => {
|
||||
this.decoratedColumns.push(makeDecoratedColumn(nestedColumn))
|
||||
})
|
||||
if (this.hasHeaderGroups) {
|
||||
if (currentSpan.length > 0) {
|
||||
addHeader(currentSpan)
|
||||
}
|
||||
addHeader(_.takeRight(this.decoratedColumns, column.columns.length), column)
|
||||
}
|
||||
} else {
|
||||
this.decoratedColumns.push(makeDecoratedColumn(column))
|
||||
currentSpan.push(_.last(this.decoratedColumns))
|
||||
}
|
||||
})
|
||||
|
||||
if (this.hasHeaderGroups && currentSpan.length > 0) {
|
||||
addHeader(currentSpan)
|
||||
sorting: false,
|
||||
visibleSubComponents: {}
|
||||
}
|
||||
},
|
||||
getInitSorting () {
|
||||
const initSorting = this.decoratedColumns.filter(d => {
|
||||
componentDidMount () {
|
||||
this.fireOnChange()
|
||||
},
|
||||
fireOnChange () {
|
||||
this.props.onChange({
|
||||
page: this.getPropOrState('page'),
|
||||
pageSize: this.getStateOrProp('pageSize'),
|
||||
pages: this.getPagesLength(),
|
||||
sorting: this.getSorting()
|
||||
}, this)
|
||||
},
|
||||
getPropOrState (key) {
|
||||
return _.getFirstDefined(this.props[key], this.state[key])
|
||||
},
|
||||
getStateOrProp (key) {
|
||||
return _.getFirstDefined(this.state[key], this.props[key])
|
||||
},
|
||||
getInitSorting (columns) {
|
||||
if (!columns) {
|
||||
return []
|
||||
}
|
||||
const initSorting = columns.filter(d => {
|
||||
return typeof d.sort !== 'undefined'
|
||||
}).map(d => {
|
||||
return {
|
||||
@@ -170,152 +150,224 @@ export default React.createClass({
|
||||
})
|
||||
|
||||
return initSorting.length ? initSorting : [{
|
||||
id: this.decoratedColumns[0].id,
|
||||
id: columns[0].id,
|
||||
asc: true
|
||||
}]
|
||||
},
|
||||
buildData (props, state) {
|
||||
const sorting = state.sorting === false ? this.getInitSorting() : state.sorting
|
||||
|
||||
const setData = (data) => {
|
||||
this.setState({
|
||||
sorting,
|
||||
data,
|
||||
page: state.page,
|
||||
loading: false
|
||||
})
|
||||
}
|
||||
|
||||
if (this.isAsync) {
|
||||
this.setState({
|
||||
loading: true
|
||||
})
|
||||
|
||||
const cb = (res) => {
|
||||
if (!res) {
|
||||
return Promise.reject('Uh Oh! Nothing was returned in ReactTable\'s data callback!')
|
||||
}
|
||||
if (res.pages) {
|
||||
this.setState({
|
||||
pages: res.pages
|
||||
})
|
||||
}
|
||||
// Only access the data. Sorting is done server side.
|
||||
const accessedData = this.accessData(res.rows)
|
||||
setData(accessedData)
|
||||
}
|
||||
|
||||
// Fetch data with current state
|
||||
const dataRes = props.data({
|
||||
sorting,
|
||||
page: state.page || 0,
|
||||
pageSize: props.pageSize,
|
||||
pages: state.pages
|
||||
}, cb)
|
||||
|
||||
if (dataRes && dataRes.then) {
|
||||
dataRes.then(cb)
|
||||
}
|
||||
} else {
|
||||
// Return locally accessed, sorted data
|
||||
const accessedData = this.accessData(props.data)
|
||||
const sortedData = this.sortData(accessedData, sorting)
|
||||
setData(sortedData)
|
||||
}
|
||||
},
|
||||
accessData (data) {
|
||||
return data.map((d, i) => {
|
||||
const row = {
|
||||
__original: d,
|
||||
__index: i
|
||||
}
|
||||
this.decoratedColumns.forEach(column => {
|
||||
row[column.id] = column.accessor(d)
|
||||
})
|
||||
return row
|
||||
})
|
||||
},
|
||||
sortData (data, sorting) {
|
||||
const resolvedSorting = sorting.length ? sorting : this.getInitSorting()
|
||||
return _.orderBy(data, resolvedSorting.map(sort => {
|
||||
return _.orderBy(data, sorting.map(sort => {
|
||||
return row => {
|
||||
if (row[sort.id] === null || row[sort.id] === undefined) {
|
||||
return -Infinity
|
||||
}
|
||||
return typeof row[sort.id] === 'string' ? row[sort.id].toLowerCase() : row[sort.id]
|
||||
}
|
||||
}), resolvedSorting.map(d => d.asc ? 'asc' : 'desc'))
|
||||
}), sorting.map(d => d.asc ? 'asc' : 'desc'))
|
||||
},
|
||||
setPage (page) {
|
||||
if (this.isAsync) {
|
||||
return this.buildData(this.props, Object.assign({}, this.state, {page}))
|
||||
makeDecoratedColumn (column) {
|
||||
const dcol = Object.assign({}, this.props.column, column)
|
||||
|
||||
if (typeof dcol.accessor === 'string') {
|
||||
dcol.id = dcol.id || dcol.accessor
|
||||
const accessorString = dcol.accessor
|
||||
dcol.accessor = row => _.get(row, accessorString)
|
||||
return dcol
|
||||
}
|
||||
this.setState({
|
||||
page
|
||||
})
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
return dcol
|
||||
},
|
||||
getSorting (columns) {
|
||||
return this.props.sorting || (this.state.sorting && this.state.sorting.length ? this.state.sorting : this.getInitSorting(columns))
|
||||
},
|
||||
getPagesLength () {
|
||||
return this.props.manual ? this.props.pages
|
||||
: Math.ceil(this.props.data.length / this.getStateOrProp('pageSize'))
|
||||
},
|
||||
getMinRows () {
|
||||
return _.getFirstDefined(this.props.minRows, this.getStateOrProp('pageSize'))
|
||||
},
|
||||
|
||||
render () {
|
||||
const data = this.state.data ? this.state.data : []
|
||||
const {visibleSubComponents} = this.state
|
||||
const {
|
||||
className,
|
||||
style,
|
||||
tableClassName,
|
||||
tableStyle,
|
||||
theadGroupClassName,
|
||||
theadStyle,
|
||||
trClassName,
|
||||
trStyle,
|
||||
thClassname,
|
||||
thStyle,
|
||||
data,
|
||||
theadClassName,
|
||||
tbodyClassName,
|
||||
tbodyStyle,
|
||||
onTrClick,
|
||||
trClassCallback,
|
||||
trStyleCallback,
|
||||
tdStyle,
|
||||
showPagination,
|
||||
showPageSizeOptions,
|
||||
pageSizeOptions,
|
||||
showPageJump,
|
||||
previousText,
|
||||
nextText,
|
||||
pageText,
|
||||
ofText,
|
||||
rowsText,
|
||||
paginationClassName,
|
||||
expanderColumnWidth
|
||||
} = this.props
|
||||
|
||||
const pagesLength = this.isAsync ? this.state.pages : Math.ceil(data.length / this.props.pageSize)
|
||||
const startRow = this.props.pageSize * this.state.page
|
||||
const endRow = startRow + this.props.pageSize
|
||||
const pageRows = this.isAsync ? data.slice(0, this.props.pageSize) : data.slice(startRow, endRow)
|
||||
const padRows = pagesLength > 1 ? _.range(this.props.pageSize - pageRows.length)
|
||||
: this.props.minRows ? _.range(Math.max(this.props.minRows - pageRows.length, 0))
|
||||
// Build Columns
|
||||
const decoratedColumns = []
|
||||
const headerGroups = []
|
||||
let currentSpan = []
|
||||
|
||||
// Determine Header Groups
|
||||
let hasHeaderGroups = false
|
||||
this.props.columns
|
||||
.forEach(column => {
|
||||
if (column.columns) {
|
||||
hasHeaderGroups = true
|
||||
}
|
||||
})
|
||||
|
||||
// A convenience function to add a header and reset the currentSpan
|
||||
const addHeader = (columns, column = {}) => {
|
||||
headerGroups.push(Object.assign({}, column, {
|
||||
columns: columns
|
||||
}))
|
||||
currentSpan = []
|
||||
}
|
||||
|
||||
// Build the columns and headers
|
||||
const visibleColumns = this.props.columns.filter(d => _.getFirstDefined(d.show, true))
|
||||
visibleColumns.forEach((column, i) => {
|
||||
if (column.columns) {
|
||||
const nestedColumns = column.columns.filter(d => _.getFirstDefined(d.show, true))
|
||||
nestedColumns.forEach(nestedColumn => {
|
||||
decoratedColumns.push(this.makeDecoratedColumn(nestedColumn))
|
||||
})
|
||||
if (hasHeaderGroups) {
|
||||
if (currentSpan.length > 0) {
|
||||
addHeader(currentSpan)
|
||||
}
|
||||
addHeader(_.takeRight(decoratedColumns, nestedColumns.length), column)
|
||||
}
|
||||
} else {
|
||||
decoratedColumns.push(this.makeDecoratedColumn(column))
|
||||
currentSpan.push(_.last(decoratedColumns))
|
||||
}
|
||||
})
|
||||
|
||||
const columnPercentage = 100 / decoratedColumns.length
|
||||
|
||||
if (hasHeaderGroups && currentSpan.length > 0) {
|
||||
addHeader(currentSpan)
|
||||
}
|
||||
|
||||
const sorting = this.getSorting(decoratedColumns)
|
||||
const accessedData = this.props.data.map((d, i) => {
|
||||
const row = {
|
||||
__original: d,
|
||||
__index: i
|
||||
}
|
||||
decoratedColumns.forEach(column => {
|
||||
row[column.id] = column.accessor(d)
|
||||
})
|
||||
return row
|
||||
})
|
||||
const resolvedData = this.props.manual ? accessedData : this.sortData(accessedData, sorting)
|
||||
|
||||
// Normalize state
|
||||
const currentPage = this.getPropOrState('page')
|
||||
const pageSize = this.getStateOrProp('pageSize')
|
||||
const pagesLength = this.getPagesLength()
|
||||
|
||||
// Pagination
|
||||
const startRow = pageSize * currentPage
|
||||
const endRow = startRow + pageSize
|
||||
const pageRows = this.props.manual ? resolvedData : resolvedData.slice(startRow, endRow)
|
||||
const minRows = this.getMinRows()
|
||||
const padRows = pagesLength > 1 ? _.range(pageSize - pageRows.length)
|
||||
: minRows ? _.range(Math.max(minRows - pageRows.length, 0))
|
||||
: []
|
||||
|
||||
const canPrevious = this.state.page > 0
|
||||
const canNext = this.state.page + 1 < pagesLength
|
||||
const canPrevious = currentPage > 0
|
||||
const canNext = currentPage + 1 < pagesLength
|
||||
|
||||
const TableComponent = this.props.tableComponent
|
||||
const TheadComponent = this.props.theadComponent
|
||||
const TbodyComponent = this.props.tbodyComponent
|
||||
const TrGroupComponent = this.props.trGroupComponent
|
||||
const TrComponent = this.props.trComponent
|
||||
const ThComponent = this.props.thComponent
|
||||
const TdComponent = this.props.tdComponent
|
||||
const ExpanderComponent = this.props.expanderComponent
|
||||
const PaginationComponent = this.props.paginationComponent
|
||||
const PreviousComponent = this.props.previousComponent
|
||||
const NextComponent = this.props.nextComponent
|
||||
const LoadingComponent = this.props.loadingComponent
|
||||
const SubComponent = this.props.subComponent
|
||||
|
||||
const PreviousComponent = this.props.previousComponent || defaultButton
|
||||
const NextComponent = this.props.nextComponent || defaultButton
|
||||
const rowWidth = (SubComponent ? expanderColumnWidth : 0) + _.sum(decoratedColumns.map(d => d.minWidth))
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classnames(this.props.className, 'ReactTable')}
|
||||
style={this.props.style}
|
||||
className={classnames(className, 'ReactTable')}
|
||||
style={style}
|
||||
>
|
||||
<TableComponent
|
||||
className={classnames(this.props.tableClassName)}
|
||||
style={this.props.tableStyle}
|
||||
className={classnames(tableClassName)}
|
||||
style={tableStyle}
|
||||
>
|
||||
{this.hasHeaderGroups && (
|
||||
{hasHeaderGroups && (
|
||||
<TheadComponent
|
||||
className={classnames(this.props.theadGroupClassName, '-headerGroups')}
|
||||
style={this.props.theadStyle}
|
||||
className={classnames(theadGroupClassName, '-headerGroups')}
|
||||
style={Object.assign({}, theadStyle, {
|
||||
minWidth: `${rowWidth}px`
|
||||
})}
|
||||
>
|
||||
<TrComponent
|
||||
className={this.props.trClassName}
|
||||
style={this.props.trStyle}
|
||||
className={trClassName}
|
||||
style={trStyle}
|
||||
>
|
||||
{this.headerGroups.map((column, i) => {
|
||||
{SubComponent && (
|
||||
<ThComponent
|
||||
className={classnames(thClassname, 'rt-expander-header')}
|
||||
style={prefixAll({
|
||||
flex: `0 0 auto`,
|
||||
width: `${expanderColumnWidth}px`
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
{headerGroups.map((column, i) => {
|
||||
return (
|
||||
<ThComponent
|
||||
key={i}
|
||||
colSpan={column.columns.length}
|
||||
className={classnames(this.props.thClassname, column.headerClassName)}
|
||||
style={Object.assign({}, this.props.thStyle, column.headerStyle)}
|
||||
className={classnames(thClassname, column.headerClassName)}
|
||||
style={Object.assign({}, thStyle, column.headerStyle, prefixAll({
|
||||
flex: `${column.columns.length * columnPercentage} 0 auto`,
|
||||
width: `${_.sum(column.columns.map(d => d.minWidth))}px`
|
||||
}))}
|
||||
>
|
||||
<div
|
||||
className={classnames(column.headerInnerClassName, '-th-inner')}
|
||||
style={Object.assign({}, this.props.thInnerStyle, column.headerInnerStyle)}
|
||||
>
|
||||
{typeof column.header === 'function' ? (
|
||||
<column.header
|
||||
data={this.props.data}
|
||||
column={column}
|
||||
/>
|
||||
) : column.header}
|
||||
</div>
|
||||
{typeof column.header === 'function' ? (
|
||||
<column.header
|
||||
data={resolvedData}
|
||||
column={column}
|
||||
/>
|
||||
) : column.header}
|
||||
</ThComponent>
|
||||
)
|
||||
})}
|
||||
@@ -323,21 +375,32 @@ export default React.createClass({
|
||||
</TheadComponent>
|
||||
)}
|
||||
<TheadComponent
|
||||
className={classnames(this.props.theadClassName)}
|
||||
style={this.props.theadStyle}
|
||||
className={classnames(theadClassName, '-header')}
|
||||
style={Object.assign({}, theadStyle, {
|
||||
minWidth: `${rowWidth}px`
|
||||
})}
|
||||
>
|
||||
<TrComponent
|
||||
className={this.props.trClassName}
|
||||
style={this.props.trStyle}
|
||||
className={trClassName}
|
||||
style={trStyle}
|
||||
>
|
||||
{this.decoratedColumns.map((column, i) => {
|
||||
const sort = this.state.sorting.find(d => d.id === column.id)
|
||||
{SubComponent && (
|
||||
<ThComponent
|
||||
className={classnames(thClassname, 'rt-expander-header')}
|
||||
style={prefixAll({
|
||||
flex: `0 0 auto`,
|
||||
width: `${expanderColumnWidth}px`
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
{decoratedColumns.map((column, i) => {
|
||||
const sort = sorting.find(d => d.id === column.id)
|
||||
const show = typeof column.show === 'function' ? column.show() : column.show
|
||||
return (
|
||||
<ThComponent
|
||||
key={i}
|
||||
className={classnames(
|
||||
this.props.thClassname,
|
||||
thClassname,
|
||||
column.headerClassName,
|
||||
sort ? (sort.asc ? '-sort-asc' : '-sort-desc') : '',
|
||||
{
|
||||
@@ -345,32 +408,30 @@ export default React.createClass({
|
||||
'-hidden': !show
|
||||
}
|
||||
)}
|
||||
style={Object.assign({}, this.props.thStyle, column.headerStyle)}
|
||||
onClick={(e) => {
|
||||
style={Object.assign({}, thStyle, column.headerStyle, prefixAll({
|
||||
flex: `${columnPercentage} 0 auto`,
|
||||
width: `${column.minWidth}px`
|
||||
}))}
|
||||
toggleSort={(e) => {
|
||||
column.sortable && this.sortColumn(column, e.shiftKey)
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className={classnames(column.headerInnerClassName, '-th-inner')}
|
||||
style={Object.assign({}, column.headerInnerStyle, {
|
||||
minWidth: column.minWidth + 'px'
|
||||
})}
|
||||
>
|
||||
{typeof column.header === 'function' ? (
|
||||
<column.header
|
||||
data={this.props.data}
|
||||
column={column}
|
||||
/>
|
||||
) : column.header}
|
||||
</div>
|
||||
{typeof column.header === 'function' ? (
|
||||
<column.header
|
||||
data={resolvedData}
|
||||
column={column}
|
||||
/>
|
||||
) : column.header}
|
||||
</ThComponent>
|
||||
)
|
||||
})}
|
||||
</TrComponent>
|
||||
</TheadComponent>
|
||||
<TbodyComponent
|
||||
className={classnames(this.props.tbodyClassName)}
|
||||
style={this.props.tbodyStyle}
|
||||
className={classnames(tbodyClassName)}
|
||||
style={Object.assign({}, tbodyStyle, {
|
||||
minWidth: `${rowWidth}px`
|
||||
})}
|
||||
>
|
||||
{pageRows.map((row, i) => {
|
||||
const rowInfo = {
|
||||
@@ -380,61 +441,90 @@ export default React.createClass({
|
||||
viewIndex: i
|
||||
}
|
||||
return (
|
||||
<TrComponent
|
||||
key={i}
|
||||
className={classnames(this.props.trClassName, this.props.trClassCallback(rowInfo))}
|
||||
style={Object.assign({}, this.props.trStyle, this.props.trStyleCallback(rowInfo))}
|
||||
>
|
||||
{this.decoratedColumns.map((column, i2) => {
|
||||
const Cell = column.render
|
||||
const show = typeof column.show === 'function' ? column.show() : column.show
|
||||
return (
|
||||
<TdComponent
|
||||
key={i2}
|
||||
className={classnames(column.className, {hidden: !show})}
|
||||
style={Object.assign({}, this.props.tdStyle, column.style)}
|
||||
<TrGroupComponent key={i}>
|
||||
<TrComponent
|
||||
onClick={event => onTrClick(rowInfo.row, event)}
|
||||
className={classnames(trClassName, trClassCallback(rowInfo))}
|
||||
style={Object.assign({}, trStyle, trStyleCallback(rowInfo))}
|
||||
>
|
||||
{SubComponent && (
|
||||
<ThComponent
|
||||
className={classnames(thClassname, 'rt-expander-wrap')}
|
||||
style={prefixAll({
|
||||
flex: `0 0 auto`,
|
||||
width: `${expanderColumnWidth}px`
|
||||
})}
|
||||
onClick={() => {
|
||||
this.setState({
|
||||
visibleSubComponents: {
|
||||
...visibleSubComponents,
|
||||
[i]: !visibleSubComponents[i]
|
||||
}
|
||||
})
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className={classnames(column.innerClassName, '-td-inner')}
|
||||
style={Object.assign({}, column.innerStyle, {
|
||||
minWidth: column.minWidth + 'px'
|
||||
})}
|
||||
<ExpanderComponent
|
||||
isOpen={visibleSubComponents[i]}
|
||||
/>
|
||||
</ThComponent>
|
||||
)}
|
||||
{decoratedColumns.map((column, i2) => {
|
||||
const Cell = column.render
|
||||
const show = typeof column.show === 'function' ? column.show() : column.show
|
||||
return (
|
||||
<TdComponent
|
||||
key={i2}
|
||||
className={classnames(column.className, {hidden: !show})}
|
||||
style={Object.assign({}, tdStyle, column.style, prefixAll({
|
||||
flex: `${columnPercentage} 0 auto`,
|
||||
width: `${column.minWidth}px`
|
||||
}))}
|
||||
>
|
||||
{typeof Cell === 'function' ? (
|
||||
<Cell
|
||||
{...rowInfo}
|
||||
value={rowInfo.rowValues[column.id]}
|
||||
/>
|
||||
) : typeof Cell !== 'undefined' ? Cell
|
||||
) : typeof Cell !== 'undefined' ? Cell
|
||||
: rowInfo.rowValues[column.id]}
|
||||
</div>
|
||||
</TdComponent>
|
||||
)
|
||||
})}
|
||||
</TrComponent>
|
||||
</TdComponent>
|
||||
)
|
||||
})}
|
||||
</TrComponent>
|
||||
{SubComponent && visibleSubComponents[i] ? (
|
||||
SubComponent(rowInfo)
|
||||
) : null}
|
||||
</TrGroupComponent>
|
||||
)
|
||||
})}
|
||||
{padRows.map((row, i) => {
|
||||
return (
|
||||
<TrComponent
|
||||
key={i}
|
||||
className={classnames(this.props.trClassName, '-padRow')}
|
||||
style={this.props.trStyle}
|
||||
className={classnames(trClassName, '-padRow')}
|
||||
style={trStyle}
|
||||
>
|
||||
{this.decoratedColumns.map((column, i2) => {
|
||||
{SubComponent && (
|
||||
<ThComponent
|
||||
className={classnames(thClassname, 'rt-expander-header')}
|
||||
style={prefixAll({
|
||||
flex: `0 0 auto`,
|
||||
width: `${expanderColumnWidth}px`
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
{decoratedColumns.map((column, i2) => {
|
||||
const show = typeof column.show === 'function' ? column.show() : column.show
|
||||
return (
|
||||
<TdComponent
|
||||
key={i2}
|
||||
className={classnames(column.className, {hidden: !show})}
|
||||
style={Object.assign({}, this.props.tdStyle, column.style)}
|
||||
style={Object.assign({}, tdStyle, column.style, {
|
||||
flex: `${columnPercentage} 0 auto`,
|
||||
width: `${column.minWidth}px`
|
||||
})}
|
||||
>
|
||||
<div
|
||||
className={classnames(column.innerClassName, '-td-inner')}
|
||||
style={Object.assign({}, column.innerStyle, {
|
||||
minWidth: column.minWidth + 'px'
|
||||
})}
|
||||
> </div>
|
||||
|
||||
</TdComponent>
|
||||
)
|
||||
})}
|
||||
@@ -443,42 +533,57 @@ export default React.createClass({
|
||||
})}
|
||||
</TbodyComponent>
|
||||
</TableComponent>
|
||||
{pagesLength > 1 && (
|
||||
<div
|
||||
className={classnames(this.props.paginationClassName, '-pagination')}
|
||||
style={this.props.paginationStyle}
|
||||
>
|
||||
<div className='-left'>
|
||||
<PreviousComponent
|
||||
onClick={canPrevious && ((e) => this.previousPage(e))}
|
||||
disabled={!canPrevious}
|
||||
>
|
||||
{this.props.previousText}
|
||||
</PreviousComponent>
|
||||
</div>
|
||||
<div className='-center'>
|
||||
Page {this.state.page + 1} of {pagesLength}
|
||||
</div>
|
||||
<div className='-right'>
|
||||
<NextComponent
|
||||
onClick={canNext && ((e) => this.nextPage(e))}
|
||||
disabled={!canNext}
|
||||
>
|
||||
{this.props.nextText}
|
||||
</NextComponent>
|
||||
</div>
|
||||
</div>
|
||||
{showPagination && (
|
||||
<PaginationComponent
|
||||
currentPage={currentPage}
|
||||
pagesLength={pagesLength}
|
||||
pageSize={pageSize}
|
||||
showPageSizeOptions={showPageSizeOptions}
|
||||
pageSizeOptions={pageSizeOptions}
|
||||
showPageJump={showPageJump}
|
||||
canPrevious={canPrevious}
|
||||
canNext={canNext}
|
||||
previousText={previousText}
|
||||
nextText={nextText}
|
||||
pageText={pageText}
|
||||
ofText={ofText}
|
||||
rowsText={rowsText}
|
||||
previousComponent={PreviousComponent}
|
||||
nextComponent={NextComponent}
|
||||
//
|
||||
onChange={this.setPage}
|
||||
onPageSizeChange={this.setPageSize}
|
||||
//
|
||||
className={paginationClassName}
|
||||
/>
|
||||
)}
|
||||
<div className={classnames('-loading', {'-active': this.state.loading})}>
|
||||
<div className='-loading-inner'>
|
||||
{this.props.loadingText}
|
||||
</div>
|
||||
</div>
|
||||
<LoadingComponent {...this.props} />
|
||||
</div>
|
||||
)
|
||||
},
|
||||
// User actions
|
||||
setPage (page) {
|
||||
this.setState({
|
||||
visibleSubComponents: {},
|
||||
page
|
||||
}, () => {
|
||||
this.fireOnChange()
|
||||
})
|
||||
},
|
||||
setPageSize (pageSize) {
|
||||
const currentPageSize = this.getStateOrProp('pageSize')
|
||||
const currentPage = this.getPropOrState('page')
|
||||
const currentRow = currentPageSize * currentPage
|
||||
const page = Math.floor(currentRow / pageSize)
|
||||
this.setState({
|
||||
pageSize,
|
||||
page
|
||||
}, () => {
|
||||
this.fireOnChange()
|
||||
})
|
||||
},
|
||||
sortColumn (column, additive) {
|
||||
const existingSorting = this.state.sorting || []
|
||||
const existingSorting = this.getSorting()
|
||||
let sorting = _.clone(this.state.sorting || [])
|
||||
const existingIndex = sorting.findIndex(d => d.id === column.id)
|
||||
if (existingIndex > -1) {
|
||||
@@ -510,95 +615,11 @@ export default React.createClass({
|
||||
}
|
||||
}
|
||||
const page = (existingIndex === 0 || (!existingSorting.length && sorting.length) || !additive) ? 0 : this.state.page
|
||||
this.buildData(this.props, Object.assign({}, this.state, {page, sorting}))
|
||||
},
|
||||
nextPage (e) {
|
||||
e.preventDefault()
|
||||
this.setPage(this.state.page + 1)
|
||||
},
|
||||
previousPage (e) {
|
||||
e.preventDefault()
|
||||
this.setPage(this.state.page - 1)
|
||||
this.setState({
|
||||
page,
|
||||
sorting
|
||||
}, () => {
|
||||
this.fireOnChange()
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// ########################################################################
|
||||
// Utils
|
||||
// ########################################################################
|
||||
|
||||
function remove (a, b) {
|
||||
return a.filter(function (o, i) {
|
||||
var r = b(o)
|
||||
if (r) {
|
||||
a.splice(i, 1)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
function get (a, b) {
|
||||
if (isArray(b)) {
|
||||
b = b.join('.')
|
||||
}
|
||||
return b
|
||||
.replace('[', '.').replace(']', '')
|
||||
.split('.')
|
||||
.reduce(
|
||||
function (obj, property) {
|
||||
return obj[property]
|
||||
}, a
|
||||
)
|
||||
}
|
||||
|
||||
function takeRight (arr, n) {
|
||||
const start = n > arr.length ? 0 : arr.length - n
|
||||
return arr.slice(start)
|
||||
}
|
||||
|
||||
function last (arr) {
|
||||
return arr[arr.length - 1]
|
||||
}
|
||||
|
||||
function range (n) {
|
||||
const arr = []
|
||||
for (let i = 0; i < n; i++) {
|
||||
arr.push(n)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
function orderBy (arr, funcs, dirs) {
|
||||
return arr.sort((a, b) => {
|
||||
for (let i = 0; i < funcs.length; i++) {
|
||||
const comp = funcs[i]
|
||||
const ca = comp(a)
|
||||
const cb = comp(b)
|
||||
const desc = dirs[i] === false || dirs[i] === 'desc'
|
||||
if (ca > cb) {
|
||||
return desc ? -1 : 1
|
||||
}
|
||||
if (ca < cb) {
|
||||
return desc ? 1 : -1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
})
|
||||
}
|
||||
|
||||
function clone (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)
|
||||
}
|
||||
|
||||
+125
-97
@@ -2,90 +2,37 @@
|
||||
|
||||
$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
|
||||
table
|
||||
border: 1px solid alpha(black, .1)
|
||||
*
|
||||
box-sizing: border-box
|
||||
.rt-table
|
||||
display: flex
|
||||
flex-direction: column
|
||||
align-items: stretch
|
||||
width: 100%
|
||||
border-collapse: collapse
|
||||
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
|
||||
overflow: auto
|
||||
|
||||
.rt-thead
|
||||
display: flex
|
||||
flex-direction: column
|
||||
&.-headerGroups
|
||||
background: alpha(black, .03)
|
||||
border-bottom: 1px solid alpha(black, .05)
|
||||
|
||||
th
|
||||
td
|
||||
background: alpha(black, .03)
|
||||
&.-header
|
||||
box-shadow: 0 2px 15px 0px alpha(black, .15)
|
||||
|
||||
tr
|
||||
.rt-tr
|
||||
text-align:center
|
||||
|
||||
th
|
||||
td
|
||||
width: 1%
|
||||
background: white
|
||||
font-weight:500
|
||||
color: $darkColor
|
||||
.rt-th
|
||||
.rt-td
|
||||
color: black
|
||||
border-right: 1px solid alpha(black, .05)
|
||||
transition box-shadow .3s $easeOutBack
|
||||
box-shadow:inset 0 0 0 0 transparent
|
||||
@@ -95,40 +42,81 @@ $easeOutBack = cubic-bezier(0.175, 0.885, 0.320, 1.275)
|
||||
box-shadow:inset 0 -3px 0 0 alpha(black, .6)
|
||||
&.-cursor-pointer
|
||||
cursor: pointer
|
||||
|
||||
tbody
|
||||
z-index:0
|
||||
tr
|
||||
&:last-child
|
||||
border-right: 0
|
||||
.rt-tbody
|
||||
display: flex
|
||||
flex-direction: column
|
||||
// z-index:0
|
||||
.rt-tr-group
|
||||
border-bottom: solid 1px alpha(black, .05)
|
||||
&:last-child
|
||||
border-bottom: 0
|
||||
|
||||
&:first-child td
|
||||
box-shadow: inset 0 20px 20px -20px alpha(black, .2)
|
||||
td
|
||||
.rt-td
|
||||
border-right:1px solid alpha(black, .02)
|
||||
&:last-child
|
||||
border-right:0
|
||||
.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
|
||||
|
||||
&.striped
|
||||
tbody tr:nth-child(even)
|
||||
&.-hidden
|
||||
width: 0 !important
|
||||
min-width: 0 !important
|
||||
padding: 0 !important
|
||||
border:0 !important
|
||||
opacity: 0 !important
|
||||
|
||||
.rt-expander-wrap
|
||||
display:flex
|
||||
align-items: center
|
||||
justify-content: center
|
||||
cursor: pointer
|
||||
|
||||
.rt-expander
|
||||
width: 0
|
||||
height: 0
|
||||
border-left: ($expandSize * .72) solid transparent
|
||||
border-right: ($expandSize * .72) solid transparent
|
||||
border-top: $expandSize solid alpha(black, .8)
|
||||
transition: all .3s $easeOutBack
|
||||
transform: rotate(-90deg)
|
||||
&.-open
|
||||
transform: rotate(0deg)
|
||||
|
||||
&.-striped
|
||||
.rt-tr-group:nth-child(even)
|
||||
background: alpha(black, .03)
|
||||
&.highlight
|
||||
tbody tr:hover
|
||||
&.-highlight
|
||||
.rt-tr-group:hover
|
||||
background: alpha(black, .05)
|
||||
|
||||
.-pagination
|
||||
width:100%
|
||||
z-index: 1
|
||||
display:flex
|
||||
margin-top:5px
|
||||
justify-content: space-between
|
||||
align-items: center
|
||||
align-items: stretch
|
||||
flex-wrap: wrap
|
||||
padding: 3px
|
||||
box-shadow: 0 0px 15px 0px alpha(black, .1)
|
||||
|
||||
.-btn
|
||||
appearance:none
|
||||
display:block
|
||||
width:100%
|
||||
height: 100%
|
||||
border: 0
|
||||
border-radius: 3px
|
||||
padding: 6px
|
||||
@@ -147,21 +135,34 @@ $easeOutBack = cubic-bezier(0.175, 0.885, 0.320, 1.275)
|
||||
background: alpha(black, .3)
|
||||
color: white
|
||||
|
||||
.-left
|
||||
.-center
|
||||
.-right
|
||||
.-previous
|
||||
.-next
|
||||
flex: 1
|
||||
// min-width:150px
|
||||
margin-bottom:5px
|
||||
|
||||
.-left
|
||||
.-right
|
||||
text-align: center
|
||||
|
||||
|
||||
.-center
|
||||
flex: 1.5
|
||||
text-align:center
|
||||
padding: 0 5px
|
||||
margin-bottom:0
|
||||
display: flex
|
||||
flex-direction: row
|
||||
flex-wrap: wrap
|
||||
align-items: center
|
||||
justify-content: space-around
|
||||
|
||||
.-pageInfo
|
||||
display: inline-block
|
||||
margin: 3px 10px
|
||||
white-space: nowrap
|
||||
|
||||
.-pageJump
|
||||
display:inline-block
|
||||
input
|
||||
width: 70px
|
||||
text-align:center
|
||||
|
||||
.-pageSizeOptions
|
||||
margin: 3px 10px
|
||||
|
||||
|
||||
.-loading
|
||||
@@ -194,3 +195,30 @@ $easeOutBack = cubic-bezier(0.175, 0.885, 0.320, 1.275)
|
||||
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
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
import React from 'react'
|
||||
import classnames from 'classnames'
|
||||
//
|
||||
// import _ from './utils'
|
||||
|
||||
const defaultButton = (props) => (
|
||||
<button {...props} className='-btn'>{props.children}</button>
|
||||
)
|
||||
|
||||
export default React.createClass({
|
||||
getInitialState () {
|
||||
return {
|
||||
page: this.props.currentPage
|
||||
}
|
||||
},
|
||||
componentWillReceiveProps (nextProps) {
|
||||
this.setState({page: nextProps.currentPage})
|
||||
},
|
||||
getSafePage (page) {
|
||||
return Math.min(Math.max(page, 0), this.props.pagesLength - 1)
|
||||
},
|
||||
changePage (page) {
|
||||
page = this.getSafePage(page)
|
||||
this.setState({page})
|
||||
this.props.onChange(page)
|
||||
},
|
||||
applyPage (e) {
|
||||
e && e.preventDefault()
|
||||
const page = this.state.page
|
||||
this.changePage(page === '' ? this.props.currentPage : page)
|
||||
},
|
||||
render () {
|
||||
const {
|
||||
currentPage,
|
||||
pagesLength,
|
||||
showPageSizeOptions,
|
||||
pageSizeOptions,
|
||||
pageSize,
|
||||
showPageJump,
|
||||
canPrevious,
|
||||
canNext,
|
||||
onPageSizeChange,
|
||||
className
|
||||
} = this.props
|
||||
|
||||
const PreviousComponent = this.props.previousComponent || defaultButton
|
||||
const NextComponent = this.props.nextComponent || defaultButton
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classnames(className, '-pagination')}
|
||||
style={this.props.paginationStyle}
|
||||
>
|
||||
<div className='-previous'>
|
||||
<PreviousComponent
|
||||
onClick={(e) => {
|
||||
if (!canPrevious) return
|
||||
this.changePage(currentPage - 1)
|
||||
}}
|
||||
disabled={!canPrevious}
|
||||
>
|
||||
{this.props.previousText}
|
||||
</PreviousComponent>
|
||||
</div>
|
||||
<div className='-center'>
|
||||
<span className='-pageInfo'>
|
||||
{this.props.pageText} {showPageJump ? (
|
||||
<form className='-pageJump'
|
||||
onSubmit={this.applyPage}
|
||||
>
|
||||
<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}
|
||||
/>
|
||||
</form>
|
||||
) : (
|
||||
<span className='-currentPage'>{currentPage + 1}</span>
|
||||
)} {this.props.ofText} <span className='-totalPages'>{pagesLength}</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(currentPage + 1)
|
||||
}}
|
||||
disabled={!canNext}
|
||||
>
|
||||
{this.props.nextText}
|
||||
</NextComponent>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
})
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
export default {
|
||||
get,
|
||||
takeRight,
|
||||
last,
|
||||
orderBy,
|
||||
range,
|
||||
clone,
|
||||
remove,
|
||||
getFirstDefined,
|
||||
sum
|
||||
}
|
||||
|
||||
function remove (a, b) {
|
||||
return a.filter(function (o, i) {
|
||||
var r = b(o)
|
||||
if (r) {
|
||||
a.splice(i, 1)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
function get (a, b) {
|
||||
if (isArray(b)) {
|
||||
b = b.join('.')
|
||||
}
|
||||
return b
|
||||
.replace('[', '.').replace(']', '')
|
||||
.split('.')
|
||||
.reduce(
|
||||
function (obj, property) {
|
||||
return obj[property]
|
||||
}, a
|
||||
)
|
||||
}
|
||||
|
||||
function takeRight (arr, n) {
|
||||
const start = n > arr.length ? 0 : arr.length - n
|
||||
return arr.slice(start)
|
||||
}
|
||||
|
||||
function last (arr) {
|
||||
return arr[arr.length - 1]
|
||||
}
|
||||
|
||||
function range (n) {
|
||||
const arr = []
|
||||
for (let i = 0; i < n; i++) {
|
||||
arr.push(n)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
function orderBy (arr, funcs, dirs) {
|
||||
return arr.sort((a, b) => {
|
||||
for (let i = 0; i < funcs.length; i++) {
|
||||
const comp = funcs[i]
|
||||
const ca = comp(a)
|
||||
const cb = comp(b)
|
||||
const desc = dirs[i] === false || dirs[i] === 'desc'
|
||||
if (ca > cb) {
|
||||
return desc ? -1 : 1
|
||||
}
|
||||
if (ca < cb) {
|
||||
return desc ? 1 : -1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
})
|
||||
}
|
||||
|
||||
function clone (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) {
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
if (typeof args[i] !== 'undefined') {
|
||||
return args[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function sum (arr) {
|
||||
return arr.reduce((a, b) => {
|
||||
return a + b
|
||||
}, 0)
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
import React from 'react'
|
||||
import _ from 'lodash'
|
||||
import namor from 'namor'
|
||||
|
||||
import CodeHighlight from './components/codeHighlight'
|
||||
import ReactTable from '../lib/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) => {
|
||||
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)
|
||||
})
|
||||
}
|
||||
|
||||
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)
|
||||
.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>
|
||||
<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={10}
|
||||
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.creatClass({
|
||||
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
|
||||
})
|
||||
.then((res) => {
|
||||
// Now update your state!
|
||||
this.setState({
|
||||
data: res.rows,
|
||||
pages: res.pages,
|
||||
loading: false
|
||||
})
|
||||
})
|
||||
},
|
||||
render () {
|
||||
const columns = [{
|
||||
header: 'Name',
|
||||
columns: [{
|
||||
header: 'First Name',
|
||||
accessor: 'firstName'
|
||||
}, {
|
||||
header: 'Last Name',
|
||||
id: 'lastName',
|
||||
accessor: d => d.lastName
|
||||
}]
|
||||
}, {
|
||||
header: 'Info',
|
||||
columns: [{
|
||||
header: 'Age',
|
||||
accessor: 'age'
|
||||
}]
|
||||
}]
|
||||
|
||||
return (
|
||||
<ReactTable
|
||||
columns={columns}
|
||||
manual // This forces table not to paginate or sort automatically, so we can handle things server-side
|
||||
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
|
||||
/>
|
||||
)
|
||||
}
|
||||
})
|
||||
`
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
import React from 'react'
|
||||
import _ from 'lodash'
|
||||
import namor from 'namor'
|
||||
|
||||
import CodeHighlight from './components/codeHighlight'
|
||||
import ReactTable from '../lib/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
|
||||
data={data}
|
||||
columns={columns}
|
||||
pageSize={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}
|
||||
pageSize={10}
|
||||
/>
|
||||
)
|
||||
`
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
import React from 'react'
|
||||
import _ from 'lodash'
|
||||
import namor from 'namor'
|
||||
|
||||
import CodeHighlight from './components/codeHighlight'
|
||||
import ReactTable from '../lib/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
|
||||
data={data}
|
||||
columns={columns}
|
||||
pageSize={10}
|
||||
subComponent={(row) => {
|
||||
return (
|
||||
<div style={{padding: '20px'}}>
|
||||
<em>You can put any component you want here, even another React Table!. It has access to the row data: </em>
|
||||
<CodeHighlight>{() => JSON.stringify(row, null, 2)}</CodeHighlight>
|
||||
<ReactTable
|
||||
data={data}
|
||||
columns={columns}
|
||||
pageSize={10}
|
||||
subComponent={(row) => {
|
||||
return (
|
||||
<div style={{padding: '20px'}}>
|
||||
<em>You can put any component you want here, even another React Table! 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'
|
||||
}]
|
||||
}]
|
||||
|
||||
export default (
|
||||
<ReactTable
|
||||
data={data}
|
||||
columns={columns}
|
||||
pageSize={10}
|
||||
subComponent={(row) => {
|
||||
return (
|
||||
<code><pre>{JSON.stringify(row, null, 2)}</pre></code>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
)
|
||||
`
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import React from 'react'
|
||||
import banner from '../../media/Banner.png'
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<a href='https://github.com/tannerlinsley/react-table' target='_blank'>
|
||||
<img src={banner} className='logo' />
|
||||
</a>
|
||||
<br />
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
@@ -0,0 +1,21 @@
|
||||
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()
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,138 @@
|
||||
/* 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
Reference in New Issue
Block a user