Pagination Features

- Page Jumping
- Page Size Changing
- Updated Examples
This commit is contained in:
Tanner Linsley 2016-11-02 12:09:52 -06:00
parent e181f8e3d1
commit 57ac1f142d
14 changed files with 618 additions and 218 deletions

2
.gitignore vendored
View File

@ -3,3 +3,5 @@ lib/
react-table.js
react-table.css
*.log
dist/

View File

@ -83,11 +83,14 @@ These are the default props for the main react component `<ReactTable />`
{
// General
loading: false, // Whether to show the loading overlay or not
pageSize: 20,
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
showPageSizeOptions: true, // Enables the user to change the page size
pageSizeOptions: [5, 10, 20, 25, 50, 100], // The available page size options
// Callbacks
onChange: () => null,
onChange: (state, instance) => null, // Anytime the internal state of the table changes, this will fire
// Text
previousText: 'Previous',

View File

@ -10,7 +10,8 @@
},
"scripts": {
"watch": "jumpsuit watch",
"build": "jumpsuit build"
"build": "jumpsuit build",
"deploy": "jumpsuit build && zab deploy"
},
"devDependencies": {
"nib": "^1.1.0",
@ -21,6 +22,7 @@
"jumpsuit": "^0.7.5",
"lodash": "^4.16.4",
"namor": "^0.3.0",
"react-syntax-highlighter": "^3.0.0",
"react-table": "^2.0.0"
}
}

View File

@ -1,5 +1,15 @@
import { Render } from 'jumpsuit'
// import App from 'screens/async'
import App from 'screens/index'
import { Render, Router, Route, IndexRoute } from 'jumpsuit'
//
import Layout from 'components/layout'
import Simple from 'screens/simple'
import ServerSide from 'screens/serverSide'
Render(null, <App />)
Render(null, (
<Router>
<Route path='/' component={Layout}>
<IndexRoute component={Simple} />
<Route path='simple' component={Simple} />
<Route path='server-side' component={ServerSide} />
</Route>
</Router>
))

View File

@ -11,7 +11,7 @@ global-reset()
// vendor styles
// -----------------------------------------------------------------------------
@import '../node_modules/react-table/react-table.css'
@import '../../src/index'
// -----------------------------------------------------------------------------
// variables
@ -34,7 +34,6 @@ body
background: white
font-family: $fnt-open-sans
font-weight: 300
padding-bottom: 50px
h1
font-size: 2.5em
@ -50,6 +49,7 @@ strong
.logo
width: 400px
max-width: 100%
.container
display: flex
@ -63,11 +63,34 @@ strong
font-size: 20px
padding: 10px
.table-wrap
width: 700px
.viewport
width:100%
.table-wrap
width: 90%
margin: auto
padding: 10px
border-radius: 5px
box-shadow: 0 0 20px 0 alpha(black, .2)
.menu
display:block
margin: 0 10px 20px
ul
display:block
li
display:inline-block
a
display:block
padding: 10px
border-radius: 5px
box-shadow: 0 0 20px 0 alpha(black, .2)
margin: 5px
background: alpha(black, .7)
color: white
border-radius: 3px
transition: all .2s ease-out
&.active
&:hover
background: alpha(black, .9)
.ReactTable
thead
@ -77,3 +100,13 @@ strong
box-shadow:inset 0 3px 0 0 alpha(black, .6)
&.-sort-desc
box-shadow:inset 0 -3px 0 0 alpha(black, .6)
pre
display:block
font-family: monospace
font-size: 15px
line-height: 20px
border-radius: 5px
margin: 20px auto
max-width: 90%
padding: 0 20px !important

View File

@ -2,6 +2,7 @@
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>React-Table Demo</title>
<link rel="stylesheet" href="/app.css" charset="utf-8">
</head>

View File

@ -0,0 +1,11 @@
import { Component } from 'jumpsuit'
import SyntaxHighlighter from 'react-syntax-highlighter'
import atomOneDark from '../../node_modules/react-syntax-highlighter/dist/styles/atom-one-dark'
export default Component({
render () {
return (
<SyntaxHighlighter language='javascript' style={atomOneDark}>{this.props.children}</SyntaxHighlighter>
)
}
})

View File

@ -1,43 +1,13 @@
import { Component } from 'jumpsuit'
import _ from 'lodash'
import namor from 'namor'
import ReactTable from 'react-table'
import { Component, Link } from 'jumpsuit'
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>
react-table
</span>
<img src='/Banner.png' className='logo' />
</h1>
@ -66,15 +36,22 @@ export default Component({
<br />
<br />
</div>
<div className='table-wrap'>
<ReactTable
data={data}
columns={columns}
/>
<div className='menu'>
<ul>
<li>
<Link to='/simple' activeClassName='active'>
Simple
</Link>
</li>
<li>
<Link to='/server-side' activeClassName='active'>
Server-Side
</Link>
</li>
</ul>
</div>
<div style={{textAlign: 'center'}}>
<br />
<em>Tip: Hold shift when sorting to multi-sort!</em>
<div className='viewport'>
{this.props.children}
</div>
</div>
)

View File

@ -1,96 +0,0 @@
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>
<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>
)
}
})

View File

@ -0,0 +1,170 @@
import { Component } from 'jumpsuit'
import _ from 'lodash'
import namor from 'namor'
import CodeHighlight from 'components/codeHighlight'
import ReactTable from '../../../lib/index.js'
// Let's mock some data to play around with
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)
})
}
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>
<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>
)
}
})
function getCode () {
return `
import ReactTable from 'react-table'
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
/>
)
}
})
`
}

View File

@ -0,0 +1,103 @@
import { Component } from 'jumpsuit'
import _ from 'lodash'
import namor from 'namor'
import CodeHighlight from 'components/codeHighlight'
import ReactTable from '../../../lib/index.js'
export default Component({
render () {
const data = _.map(_.range(5553), d => {
return {
firstName: namor.generate({ words: 1, numLen: 0 }),
lastName: namor.generate({ words: 1, numLen: 0 }),
age: Math.floor(Math.random() * 30)
}
})
const columns = [{
header: 'Name',
columns: [{
header: 'First Name',
accessor: 'firstName'
}, {
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'
// To help us mock some data
import namor from 'namor'
import _ from 'lodash'
export default () => {
// Mock some data
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)
}
})
// 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}
/>
)
})
`
}

View File

@ -3,16 +3,17 @@ import classnames from 'classnames'
//
import _ from './utils'
const defaultButton = (props) => (
<button {...props} className='-btn'>{props.children}</button>
)
import Pagination from './pagination'
export const ReactTableDefaults = {
// State
// General
data: [],
loading: false,
pageSize: 20,
minRows: 0,
showPagination: true,
showPageSizeOptions: true,
pageSizeOptions: [5, 10, 20, 25, 50, 100],
showPageJump: true,
// Callbacks
onChange: () => null,
// Classes
@ -58,10 +59,24 @@ export const ReactTableDefaults = {
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>,
thComponent: (props) => {
const {toggleSort, ...rest} = props
return (
<th {...rest} onClick={e => {
toggleSort && toggleSort(e)
}}>{props.children}</th>
)
},
tdComponent: (props) => <td {...props}>{props.children}</td>,
previousComponent: null,
nextComponent: null
nextComponent: null,
loadingComponent: props => (
<div className={classnames('-loading', {'-active': props.loading})}>
<div className='-loading-inner'>
{props.loadingText}
</div>
</div>
)
}
export default React.createClass({
@ -71,7 +86,6 @@ export default React.createClass({
getInitialState () {
return {
page: 0,
pages: -1,
sorting: false
}
},
@ -80,12 +94,18 @@ export default React.createClass({
},
fireOnChange () {
this.props.onChange({
page: _.getFirstDefined(this.props.page, this.state.page),
pageSize: this.props.pageSize,
pages: this.props.pages,
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 []
@ -138,6 +158,13 @@ export default React.createClass({
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.props.pageSize)
},
render () {
// Build Columns
const decoratedColumns = []
@ -198,17 +225,22 @@ export default React.createClass({
})
const data = 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 pagesLength = this.props.manual ? this.props.pages : Math.ceil(data.length / this.props.pageSize)
const startRow = this.props.pageSize * this.state.page
const endRow = startRow + this.props.pageSize
const startRow = pageSize * currentPage
const endRow = startRow + pageSize
const pageRows = this.props.manual ? data : 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))
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
@ -216,9 +248,9 @@ export default React.createClass({
const TrComponent = this.props.trComponent
const ThComponent = this.props.thComponent
const TdComponent = this.props.tdComponent
const PreviousComponent = this.props.previousComponent || defaultButton
const NextComponent = this.props.nextComponent || defaultButton
const PreviousComponent = this.props.previousComponent
const NextComponent = this.props.nextComponent
const LoadingComponent = this.props.loadingComponent
return (
<div
@ -287,7 +319,7 @@ export default React.createClass({
}
)}
style={Object.assign({}, this.props.thStyle, column.headerStyle)}
onClick={(e) => {
toggleSort={(e) => {
column.sortable && this.sortColumn(column, e.shiftKey)
}}
>
@ -384,37 +416,26 @@ 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>
{this.props.showPagination && pagesLength > 1 && (
<Pagination
currentPage={currentPage}
pagesLength={pagesLength}
pageSize={pageSize}
showPageSizeOptions={this.props.showPageSizeOptions}
pageSizeOptions={this.props.pageSizeOptions}
showPageJump={this.props.showPageJump}
canPrevious={canPrevious}
canNext={canNext}
previousText={this.props.previousText}
nextText={this.props.nextText}
previousComponent={PreviousComponent}
nextComponent={NextComponent}
//
onChange={this.setPage}
onPageSizeChange={this.setPageSize}
/>
)}
<div className={classnames('-loading', {'-active': this.props.loading})}>
<div className='-loading-inner'>
{this.props.loadingText}
</div>
</div>
<LoadingComponent {...this.props} />
</div>
)
},
@ -426,13 +447,17 @@ export default React.createClass({
this.fireOnChange()
})
},
nextPage (e) {
e.preventDefault()
this.setPage(this.state.page + 1)
},
previousPage (e) {
e.preventDefault()
this.setPage(this.state.page - 1)
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.getSorting()

View File

@ -120,10 +120,10 @@ $easeOutBack = cubic-bezier(0.175, 0.885, 0.320, 1.275)
.-pagination
width:100%
display:flex
margin-top:5px
justify-content: space-between
align-items: center
flex-wrap: wrap
padding-top:3px
.-btn
appearance:none
@ -147,21 +147,33 @@ $easeOutBack = cubic-bezier(0.175, 0.885, 0.320, 1.275)
background: alpha(black, .3)
color: white
.-left
.-previous
.-center
.-right
flex: 1
// min-width:150px
margin-bottom:5px
.-next
margin:3px 0
.-left
.-right
.-previous
.-next
flex: 1
text-align: center
.-center
flex: 1.5
text-align:center
padding: 0 5px
.-pageInfo
display: inline-block
margin: 0 10px 3px
white-space: nowrap
.-pageJump
display:inline-block
input
width: 70px
text-align:center
.-pageSizeOptions
margin-left:12px
.-loading
@ -194,3 +206,29 @@ $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)
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

121
src/pagination.js Normal file
View File

@ -0,0 +1,121 @@
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
} = this.props
const PreviousComponent = this.props.PreviousComponent || defaultButton
const NextComponent = this.props.NextComponent || defaultButton
return (
<div
className={classnames(this.props.paginationClassName, '-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'>
Page {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>
)} of <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} rows
</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>
)
}
})