Compare commits

..

4 Commits

Author SHA1 Message Date
Chun-MingChen
f49c41cab1 Example to demonstate how to customize sticky table 2018-11-03 18:36:51 +08:00
Chun-MingChen
6ff2ba35b4 Disable double strips when table was displayed in bordered 2018-11-03 18:36:51 +08:00
Chun-MingChen
53bdd2e3a0 Implement feature of sticky header 2018-11-03 18:36:51 +08:00
Chun-MingChen
26e2cb4077 Fix typo 2018-11-03 17:47:34 +08:00
95 changed files with 1634 additions and 4234 deletions

View File

@@ -1,52 +1,43 @@
# react-bootstrap-table2
[![Build Status](https://travis-ci.org/react-bootstrap-table/react-bootstrap-table2.svg?branch=master)](https://travis-ci.org/react-bootstrap-table/react-bootstrap-table2)
Rebuilt of [react-bootstrap-table](https://github.com/AllenFang/react-bootstrap-table)
Rebuilt [react-bootstrap-table](https://github.com/AllenFang/react-bootstrap-table)
> Note that `react-bootstrap-table2`'s npm module name is [**`react-bootstrap-table-next`**](https://www.npmjs.com/package/react-bootstrap-table-next) due to the name being already taken.
> `react-bootstrap-table2`'s npm module name is [**`react-bootstrap-table-next`**](https://www.npmjs.com/package/react-bootstrap-table-next) due to some guys already used it
`react-bootstrap-table2` separates some functionalities from its core modules to other modules as listed in the following:
`react-bootstrap-table2` separate some functionalities from core modules to other modules like following:
- [`react-bootstrap-table-next`](https://www.npmjs.com/package/react-bootstrap-table-next)
- [`react-bootstrap-table2-filter`](https://www.npmjs.com/package/react-bootstrap-table2-filter)
- [`react-bootstrap-table2-editor`](https://www.npmjs.com/package/react-bootstrap-table2-editor)
- [`react-bootstrap-table2-paginator`](https://www.npmjs.com/package/react-bootstrap-table2-paginator)
- [`react-bootstrap-table2-overlay`](https://www.npmjs.com/package/react-bootstrap-table2-overlay)
- [`react-bootstrap-table2-toolkit`](https://www.npmjs.com/package/react-bootstrap-table2-toolkit)
* [`react-bootstrap-table-next`](https://www.npmjs.com/package/react-bootstrap-table-next)
* [`react-bootstrap-table2-filter`](https://www.npmjs.com/package/react-bootstrap-table2-filter)
* [`react-bootstrap-table2-editor`](https://www.npmjs.com/package/react-bootstrap-table2-editor)
* [`react-bootstrap-table2-paginator`](https://www.npmjs.com/package/react-bootstrap-table2-paginator)
* [`react-bootstrap-table2-overlay`](https://www.npmjs.com/package/react-bootstrap-table2-overlay)
* [`react-bootstrap-table2-toolkit`](https://www.npmjs.com/package/react-bootstrap-table2-toolkit)
Not only does this reduce the bundle size of your apps but also helps us have a cleaner design to avoid handling too much logic in the kernel module(SRP).
This can help your application with less bundled size and also help us have clean design to avoid handling to much logic in kernel module(SRP).
## Migration
If you are coming from the legacy [`react-bootstrap-table`](https://github.com/AllenFang/react-bootstrap-table/), please check out the [migration guide](./docs/migration.md).
If you are the user from legacy [`react-bootstrap-table`](https://github.com/AllenFang/react-bootstrap-table/), please have a look on [this](./docs/migration.md).
## Usage
See [getting started](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/getting-started.html).
## Online Demo
See `react-bootstrap-table2` [storybook](https://react-bootstrap-table.github.io/react-bootstrap-table2/storybook/index.html).
## Roadmap
See [release plans](https://react-bootstrap-table.github.io/react-bootstrap-table2/blog/2018/01/24/release-plan.html).
## Development
Please check [development guide](./docs/development.md).
Please check the [development guide](./docs/development.md).
## Running storybook example on your local machine
## How should I run storybook example in my local?
```sh
# Clone the repo
$ git clone https://github.com/react-bootstrap-table/react-bootstrap-table2.git
# change dir to the cloned repo
$ cd react-bootstrap-table2
# Install all dependencies with yarn
$ yarn install
# Start the stroybook server, then go to localhost:6006
$ yarn storybook
$ Go to localhost:6006
```
**Storybook examples: [`packages/react-bootstrap-table2-example/examples`](https://github.com/react-bootstrap-table/react-bootstrap-table2/tree/master/packages/react-bootstrap-table2-example/examples)**

View File

@@ -27,7 +27,6 @@
* [rowStyle](#rowStyle)
* [rowClasses](#rowClasses)
* [rowEvents](#rowEvents)
* [hiddenRows](#hiddenRows)
* [defaultSorted](#defaultSorted)
* [defaultSortDirection](#defaultSortDirection)
* [pagination](#pagination)
@@ -182,14 +181,6 @@ const rowEvents = {
<BootstrapTable data={ data } columns={ columns } rowEvents={ rowEvents } />
```
### <a name='hiddenRows'>hiddenRows - [Array]</a>
Hide rows, this props accept an array of row keys:
```js
const hiddenRows = [1, 4];
<BootstrapTable data={ data } columns={ columns } hiddenRows={ hiddenRows } />
```
### <a name='defaultSorted'>defaultSorted - [Array]</a>
`defaultSorted` accept an object array which allow you to define the default sort columns when first render.

View File

@@ -113,6 +113,8 @@ Please see [available pagination configurations](https://react-bootstrap-table.g
Remember to install [`react-bootstrap-table2-paginator`](https://www.npmjs.com/package/react-bootstrap-table2-paginator) firstly.
No big changes for pagination, but still can't custom the pagination list, button and sizePerPage dropdown.
## Table Search
he usage of search functionality is a little bit different from legacy search. The mainly different thing is developer have to render the search input field, we do believe it will be very flexible for all the developers who want to custom the search position or search field itself.

View File

@@ -15,7 +15,6 @@
* [showExpandColumn](#showExpandColumn)
* [onlyOneExpanding](#onlyOneExpanding)
* [expandByColumnOnly](#expandByColumnOnly)
* [expandColumnPosition](#expandColumnPosition)
* [expandColumnRenderer](#expandColumnRenderer)
* [expandHeaderColumnRenderer](#expandHeaderColumnRenderer)
@@ -93,16 +92,13 @@ const expandRow = {
```
### <a name='expandColumnRenderer'>expandRow.expandColumnRenderer - [Function]</a>
Provide a callback function which allow you to custom the expand indicator. This callback only have one argument which is an object and contain these properties:
* `expanded`: If current row is expanded or not
* `rowKey`: Current row key
* `expandable`: If currnet row is expandable or not
Provide a callback function which allow you to custom the expand indicator. This callback only have one argument which is an object and contain one property `expanded` which indicate if current row is expanded
```js
const expandRow = {
renderer: (row) => ...
expandColumnRenderer: ({ expanded, rowKey, expandable }) => (
expandColumnRenderer: ({ expanded }) => (
// ....
)
};
@@ -154,14 +150,3 @@ const expandRow = {
expandByColumnOnly: true
};
```
### <a name='expandColumnPosition'>expandRow.expandColumnPosition - [String]</a>
Default is `left`. You can give this as `right` for rendering expand column in the right side.
```js
const expandRow = {
renderer: (row) => ...,
showExpandColumn: true,
expandColumnPosition: 'right'
};
```

View File

@@ -211,44 +211,18 @@ const selectRow = {
};
```
> If you want to reject current select action, just return `false`:
```js
const selectRow = {
mode: 'checkbox',
onSelect: (row, isSelect, rowIndex, e) => {
if (SOME_CONDITION) {
return false;
}
}
};
```
### <a name='onSelectAll'>selectRow.onSelectAll - [Function]</a>
This callback function will be called when select/unselect all and it only work when you configure [`selectRow.mode`](#mode) as `checkbox`.
```js
const selectRow = {
mode: 'checkbox',
onSelectAll: (isSelect, rows, e) => {
onSelectAll: (isSelect, results, e) => {
// ...
}
};
```
> If you want to control the final selection result, just return a row key array:
```js
const selectRow = {
mode: 'checkbox',
onSelectAll: (isSelect, rows, e) => {
if (isSelect && SOME_CONDITION) {
return [1, 3, 4]; // finally, key 1, 3, 4 will being selected
}
}
};
```
### <a name='hideSelectColumn'>selectRow.hideSelectColumn - [Bool]</a>
Default is `false`, if you don't want to have a selection column, give this prop as `true`

View File

@@ -1,6 +1,6 @@
{
"name": "react-bootstrap-table2-editor",
"version": "1.2.2",
"version": "1.2.1",
"description": "it's the editor addon for react-bootstrap-table2",
"main": "./lib/index.js",
"scripts": {

View File

@@ -4,7 +4,7 @@ import PropTypes from 'prop-types';
const EditorIndicator = ({ invalidMessage }) =>
(
<div className="alert alert-danger in" role="alert">
<div className="alert alert-danger fade in">
<strong>{ invalidMessage }</strong>
</div>
);

View File

@@ -103,7 +103,7 @@ const columns = [{
}, {
dataField: 'quality',
text: 'Product Quality',
editorRenderer: (editorProps, value, row, column, rowIndex, columnIndex) => (
editorRenderer: (editorProps, value, row, rowIndex, columnIndex) => (
<QualityRanger { ...editorProps } value={ value } />
)
}];

View File

@@ -1,57 +0,0 @@
/* eslint no-console: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator(8);
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name',
filter: textFilter()
}, {
dataField: 'price',
text: 'Product Price',
filter: textFilter({
onFilter: filterVal => console.log(`Filter Value: ${filterVal}`)
})
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name',
filter: textFilter()
}, {
dataField: 'price',
text: 'Product Price',
filter: textFilter({
onFilter: filterVal => console.log(\`Filter Value: $\{filterVal}\`)
})
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
`;
export default () => (
<div>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
filter={ filterFactory() }
/>
<Code>{ sourceCode }</Code>
</div>
);

View File

@@ -1,70 +0,0 @@
/* eslint max-len: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { selectFilter } from 'react-bootstrap-table2-filter';
import Code from 'components/common/code-block';
import { productsQualityGenerator } from 'utils/common';
const products = productsQualityGenerator(6);
const selectOptions = [
{ value: 0, label: 'good' },
{ value: 1, label: 'Bad' },
{ value: 2, label: 'unknown' }
];
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'quality',
text: 'Product Quailty',
formatter: cell => selectOptions.find(opt => opt.value === cell).label,
filter: selectFilter({
options: selectOptions
})
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { selectFilter } from 'react-bootstrap-table2-filter';
const selectOptions = [
{ value: 0, label: 'good' },
{ value: 1, label: 'Bad' },
{ value: 2, label: 'unknown' }
];
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'quality',
text: 'Product Quailty',
formatter: cell => selectOptions.find(opt => opt.value === cell).label,
filter: selectFilter({
options: selectOptions
})
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
`;
export default () => (
<div>
<h3><code>selectFilter.options</code> accept an Array and we keep that order when rendering the options</h3>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
filter={ filterFactory() }
/>
<Code>{ sourceCode }</Code>
</div>
);

View File

@@ -2,9 +2,9 @@ import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block';
import { productsGenerator, withOnSale } from 'utils/common';
import { productsGenerator } from 'utils/common';
const products = withOnSale(productsGenerator());
const products = productsGenerator();
function priceFormatter(cell, row) {
if (row.onSale) {

View File

@@ -1,106 +0,0 @@
/* eslint react/prefer-stateless-function: 0 */
/* eslint react/prop-types: 0 */
/* eslint jsx-a11y/href-no-hash: 0 */
/* eslint no-unused-vars: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import paginationFactory from 'react-bootstrap-table2-paginator';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator(87);
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import paginationFactory from 'react-bootstrap-table2-paginator';
// ...
const pageButtonRenderer = ({
page,
active,
disable,
title,
onPageChange
}) => {
const handleClick = (e) => {
e.preventDefault();
onPageChange(page);
};
const activeStyle = {};
if (active) {
activeStyle.backgroundColor = 'black';
activeStyle.color = 'white';
} else {
activeStyle.backgroundColor = 'gray';
activeStyle.color = 'black';
}
if (typeof page === 'string') {
activeStyle.backgroundColor = 'white';
activeStyle.color = 'black';
}
return (
<li className="page-item">
<a href="#" onClick={ handleClick } style={ activeStyle }>{ page }</a>
</li>
);
};
const options = {
pageButtonRenderer
};
<BootstrapTable keyField="id" data={ products } columns={ columns } pagination={ paginationFactory(options) } />
`;
const pageButtonRenderer = ({
page,
active,
disable,
title,
onPageChange
}) => {
const handleClick = (e) => {
e.preventDefault();
onPageChange(page);
};
const activeStyle = {};
if (active) {
activeStyle.backgroundColor = 'black';
activeStyle.color = 'white';
} else {
activeStyle.backgroundColor = 'gray';
activeStyle.color = 'black';
}
if (typeof page === 'string') {
activeStyle.backgroundColor = 'white';
activeStyle.color = 'black';
}
return (
<li className="page-item">
<a href="#" onClick={ handleClick } style={ activeStyle }>{ page }</a>
</li>
);
};
const options = {
pageButtonRenderer
};
export default () => (
<div>
<BootstrapTable keyField="id" data={ products } columns={ columns } pagination={ paginationFactory(options) } />
<Code>{ sourceCode }</Code>
</div>
);

View File

@@ -1,78 +0,0 @@
/* eslint react/prefer-stateless-function: 0 */
/* eslint react/prop-types: 0 */
/* eslint jsx-a11y/href-no-hash: 0 */
/* eslint jsx-a11y/no-noninteractive-element-interactions: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import paginationFactory from 'react-bootstrap-table2-paginator';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator(87);
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import paginationFactory from 'react-bootstrap-table2-paginator';
// ...
const pageListRenderer = ({
pages,
onPageChange
}) => {
const pageWithoutIndication = pages.filter(p => typeof p.page !== 'string');
return (
<div>
{
pageWithoutIndication.map(p => (
<button className="btn btn-success" onClick={ () => onPageChange(p.page) }>{ p.page }</button>
))
}
</div>
);
};
const options = {
pageListRenderer
};
<BootstrapTable keyField="id" data={ products } columns={ columns } pagination={ paginationFactory(options) } />
`;
const pageListRenderer = ({
pages,
onPageChange
}) => {
const pageWithoutIndication = pages.filter(p => typeof p.page !== 'string');
return (
<div>
{
pageWithoutIndication.map(p => (
<button className="btn btn-success" onClick={ () => onPageChange(p.page) }>{ p.page }</button>
))
}
</div>
);
};
const options = {
pageListRenderer
};
export default () => (
<div>
<BootstrapTable keyField="id" data={ products } columns={ columns } pagination={ paginationFactory(options) } />
<Code>{ sourceCode }</Code>
</div>
);

View File

@@ -1,96 +0,0 @@
/* eslint react/prop-types: 0 */
/* eslint jsx-a11y/href-no-hash: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import paginationFactory from 'react-bootstrap-table2-paginator';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator(87);
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import paginationFactory from 'react-bootstrap-table2-paginator';
// ...
const sizePerPageOptionRenderer = ({
text,
page,
onSizePerPageChange
}) => (
<li
key={ text }
role="presentation"
className="dropdown-item"
>
<a
href="#"
tabIndex="-1"
role="menuitem"
data-page={ page }
onMouseDown={ (e) => {
e.preventDefault();
onSizePerPageChange(page);
} }
style={ { color: 'red' } }
>
{ text }
</a>
</li>
);
const options = {
sizePerPageOptionRenderer
};
<BootstrapTable keyField="id" data={ products } columns={ columns } pagination={ paginationFactory(options) } />
`;
const sizePerPageOptionRenderer = ({
text,
page,
onSizePerPageChange
}) => (
<li
key={ text }
role="presentation"
className="dropdown-item"
>
<a
href="#"
tabIndex="-1"
role="menuitem"
data-page={ page }
onMouseDown={ (e) => {
e.preventDefault();
onSizePerPageChange(page);
} }
style={ { color: 'red' } }
>
{ text }
</a>
</li>
);
const options = {
sizePerPageOptionRenderer
};
export default () => (
<div>
<BootstrapTable keyField="id" data={ products } columns={ columns } pagination={ paginationFactory(options) } />
<Code>{ sourceCode }</Code>
</div>
);

View File

@@ -1,89 +0,0 @@
/* eslint react/prop-types: 0 */
/* eslint jsx-a11y/href-no-hash: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import paginationFactory from 'react-bootstrap-table2-paginator';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator(87);
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import paginationFactory from 'react-bootstrap-table2-paginator';
// ...
const sizePerPageRenderer = ({
options,
currSizePerPage,
onSizePerPageChange
}) => (
<div className="btn-group" role="group">
{
options.map((option) => {
const isSelect = currSizePerPage === \`$\{option.page}\`;
return (
<button
key={ option.text }
type="button"
onClick={ () => onSizePerPageChange(option.page) }
className={ \`btn $\{isSelect ? 'btn-secondary' : 'btn-warning'}\` }
>
{ option.text }
</button>
);
})
}
</div>
);
const options = {
sizePerPageRenderer
};
<BootstrapTable keyField="id" data={ products } columns={ columns } pagination={ paginationFactory(options) } />s
`;
const sizePerPageRenderer = ({
options,
currSizePerPage,
onSizePerPageChange
}) => (
<div className="btn-group" role="group">
{
options.map(option => (
<button
key={ option.text }
type="button"
onClick={ () => onSizePerPageChange(option.page) }
className={ `btn ${currSizePerPage === `${option.page}` ? 'btn-secondary' : 'btn-warning'}` }
>
{ option.text }
</button>
))
}
</div>
);
const options = {
sizePerPageRenderer
};
export default () => (
<div>
<BootstrapTable keyField="id" data={ products } columns={ columns } pagination={ paginationFactory(options) } />
<Code>{ sourceCode }</Code>
</div>
);

View File

@@ -1,166 +0,0 @@
/* eslint react/prefer-stateless-function: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import paginationFactory, { PaginationProvider } from 'react-bootstrap-table2-paginator';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator(87);
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import paginationFactory from 'react-bootstrap-table2-paginator';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const options = {
custom: true,
totalSize: products.length
};
class FullyCustomPagination extends React.Component {
handleNextPage = ({
page,
onPageChange
}) => () => {
onPageChange(page + 1);
}
handlePrevPage = ({
page,
onPageChange
}) => () => {
onPageChange(page - 1);
}
handleSizePerPage = ({
page,
onSizePerPageChange
}, newSizePerPage) => {
onSizePerPageChange(newSizePerPage, page);
}
render() {
return (
<div>
<PaginationProvider
pagination={ paginationFactory(options) }
>
{
({
paginationProps,
paginationTableProps
}) => (
<div>
<div>
<p>Current Page: { paginationProps.page }</p>
<p>Current SizePerPage: { paginationProps.sizePerPage }</p>
</div>
<div className="btn-group" role="group">
<button className="btn btn-primary" onClick={ this.handleNextPage(paginationProps) }>Next Page</button>
<button className="btn btn-success" onClick={ this.handlePrevPage(paginationProps) }>Prev Page</button>
<button className="btn btn-danger" onClick={ () => this.handleSizePerPage(paginationProps, 10) }>Size Per Page: 10</button>
<button className="btn btn-warning" onClick={ () => this.handleSizePerPage(paginationProps, 25) }>Size Per Page: 25</button>
</div>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
{ ...paginationTableProps }
/>
</div>
)
}
</PaginationProvider>
<Code>{ sourceCode }</Code>
</div>
);
}
}
`;
const options = {
custom: true,
totalSize: products.length
};
export default class FullyCustomPagination extends React.Component {
handleNextPage = ({
page,
onPageChange
}) => () => {
onPageChange(page + 1);
}
handlePrevPage = ({
page,
onPageChange
}) => () => {
onPageChange(page - 1);
}
handleSizePerPage = ({
page,
onSizePerPageChange
}, newSizePerPage) => {
onSizePerPageChange(newSizePerPage, page);
}
render() {
return (
<div>
<PaginationProvider
pagination={ paginationFactory(options) }
>
{
({
paginationProps,
paginationTableProps
}) => (
<div>
<div>
<p>Current Page: { paginationProps.page }</p>
<p>Current SizePerPage: { paginationProps.sizePerPage }</p>
</div>
<div className="btn-group" role="group">
<button className="btn btn-primary" onClick={ this.handleNextPage(paginationProps) }>Next Page</button>
<button className="btn btn-success" onClick={ this.handlePrevPage(paginationProps) }>Prev Page</button>
<button className="btn btn-danger" onClick={ () => this.handleSizePerPage(paginationProps, 10) }>Size Per Page: 10</button>
<button className="btn btn-warning" onClick={ () => this.handleSizePerPage(paginationProps, 25) }>Size Per Page: 25</button>
</div>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
{ ...paginationTableProps }
/>
</div>
)
}
</PaginationProvider>
<Code>{ sourceCode }</Code>
</div>
);
}
}

View File

@@ -1,190 +0,0 @@
/* eslint react/no-multi-comp: 0 */
import React from 'react';
import PropTypes from 'prop-types';
import BootstrapTable from 'react-bootstrap-table-next';
import paginationFactory, { PaginationProvider, PaginationListStandalone } from 'react-bootstrap-table2-paginator';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator(87);
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import paginationFactory, { PaginationProvider, PaginationListStandalone } from 'react-bootstrap-table2-paginator';
// ...
const RemotePagination = ({ data, page, sizePerPage, onTableChange, totalSize }) => (
<div>
<PaginationProvider
pagination={
paginationFactory({
custom: true,
page,
sizePerPage,
totalSize
})
}
>
{
({
paginationProps,
paginationTableProps
}) => (
<div>
<div>
<p>Current Page: { paginationProps.page }</p>
<p>Current SizePerPage: { paginationProps.sizePerPage }</p>
</div>
<div>
<PaginationListStandalone
{ ...paginationProps }
/>
</div>
<BootstrapTable
remote
keyField="id"
data={ data }
columns={ columns }
onTableChange={ onTableChange }
{ ...paginationTableProps }
/>
</div>
)
}
</PaginationProvider>
</div>
);
class Container extends React.Component {
constructor(props) {
super(props);
this.state = {
page: 1,
data: products.slice(0, 10),
sizePerPage: 10
};
}
handleTableChange = (type, { page, sizePerPage }) => {
const currentIndex = (page - 1) * sizePerPage;
setTimeout(() => {
this.setState(() => ({
page,
data: products.slice(currentIndex, currentIndex + sizePerPage),
sizePerPage
}));
}, 2000);
}
render() {
const { data, sizePerPage, page } = this.state;
return (
<RemotePagination
data={ data }
page={ page }
sizePerPage={ sizePerPage }
totalSize={ products.length }
onTableChange={ this.handleTableChange }
/>
);
}
}
`;
const RemotePagination = ({ data, page, sizePerPage, onTableChange, totalSize }) => (
<div>
<PaginationProvider
pagination={
paginationFactory({
custom: true,
page,
sizePerPage,
totalSize
})
}
>
{
({
paginationProps,
paginationTableProps
}) => (
<div>
<div>
<p>Current Page: { paginationProps.page }</p>
<p>Current SizePerPage: { paginationProps.sizePerPage }</p>
</div>
<div>
<PaginationListStandalone
{ ...paginationProps }
/>
</div>
<BootstrapTable
remote
keyField="id"
data={ data }
columns={ columns }
onTableChange={ onTableChange }
{ ...paginationTableProps }
/>
</div>
)
}
</PaginationProvider>
<Code>{ sourceCode }</Code>
</div>
);
RemotePagination.propTypes = {
data: PropTypes.array.isRequired,
page: PropTypes.number.isRequired,
totalSize: PropTypes.number.isRequired,
sizePerPage: PropTypes.number.isRequired,
onTableChange: PropTypes.func.isRequired
};
class Container extends React.Component {
constructor(props) {
super(props);
this.state = {
page: 1,
data: products.slice(0, 10),
sizePerPage: 10
};
}
handleTableChange = (type, { page, sizePerPage }) => {
const currentIndex = (page - 1) * sizePerPage;
setTimeout(() => {
this.setState(() => ({
page,
data: products.slice(currentIndex, currentIndex + sizePerPage),
sizePerPage
}));
}, 2000);
}
render() {
const { data, sizePerPage, page } = this.state;
return (
<RemotePagination
data={ data }
page={ page }
sizePerPage={ sizePerPage }
totalSize={ products.length }
onTableChange={ this.handleTableChange }
/>
);
}
}
export default Container;

View File

@@ -1,102 +0,0 @@
/* eslint react/prefer-stateless-function: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import paginationFactory, { PaginationProvider, PaginationListStandalone } from 'react-bootstrap-table2-paginator';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator(87);
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import paginationFactory, { PaginationProvider, PaginationListStandalone } from 'react-bootstrap-table2-paginator';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const options = {
custom: true,
totalSize: products.length
};
<PaginationProvider
pagination={ paginationFactory(options) }
>
{
({
paginationProps,
paginationTableProps
}) => (
<div>
<PaginationListStandalone
{ ...paginationProps }
/>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
{ ...paginationTableProps }
/>
</div>
)
}
</PaginationProvider>
`;
const options = {
custom: true,
totalSize: products.length
};
// const pagination = paginationFactory(options);
export default class StandalonePaginationList extends React.Component {
render() {
return (
<div>
<PaginationProvider
pagination={ paginationFactory(options) }
>
{
({
paginationProps,
paginationTableProps
}) => (
<div>
<PaginationListStandalone
{ ...paginationProps }
/>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
{ ...paginationTableProps }
/>
</div>
)
}
</PaginationProvider>
<Code>{ sourceCode }</Code>
</div>
);
}
}

View File

@@ -1,102 +0,0 @@
/* eslint react/prefer-stateless-function: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import paginationFactory, { PaginationProvider, SizePerPageDropdownStandalone } from 'react-bootstrap-table2-paginator';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator(87);
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import paginationFactory, { PaginationProvider, SizePerPageDropdownStandalone } from 'react-bootstrap-table2-paginator';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const options = {
custom: true,
totalSize: products.length
};
<PaginationProvider
pagination={ paginationFactory(options) }
>
{
({
paginationProps,
paginationTableProps
}) => (
<div>
<SizePerPageDropdownStandalone
{ ...paginationProps }
/>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
{ ...paginationTableProps }
/>
</div>
)
}
</PaginationProvider>
`;
const options = {
custom: true,
totalSize: products.length
};
// const pagination = paginationFactory(options);
export default class StandaloneSizePerPage extends React.Component {
render() {
return (
<div>
<PaginationProvider
pagination={ paginationFactory(options) }
>
{
({
paginationProps,
paginationTableProps
}) => (
<div>
<SizePerPageDropdownStandalone
{ ...paginationProps }
/>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
{ ...paginationTableProps }
/>
</div>
)
}
</PaginationProvider>
<Code>{ sourceCode }</Code>
</div>
);
}
}

View File

@@ -1,5 +1,4 @@
/* eslint react/prop-types: 0 */
/* eslint no-unused-vars: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
@@ -34,7 +33,7 @@ const expandRow = {
}
return <b>+</b>;
},
expandColumnRenderer: ({ expanded, rowKey, expandable }) => {
expandColumnRenderer: ({ expanded }) => {
if (expanded) {
return (
<b>-</b>

View File

@@ -51,8 +51,7 @@ const expandRow = {
<p>expandRow.renderer callback will pass the origin row object to you</p>
</div>
),
showExpandColumn: true,
expandByColumnOnly: true
showExpandColumn: true
};
<BootstrapTable

View File

@@ -1,76 +0,0 @@
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block';
import { productsExpandRowsGenerator } from 'utils/common';
const products = productsExpandRowsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const expandRow = {
renderer: row => (
<div>
<p>{ `This Expand row is belong to rowKey ${row.id}` }</p>
<p>You can render anything here, also you can add additional data on every row object</p>
<p>expandRow.renderer callback will pass the origin row object to you</p>
</div>
),
showExpandColumn: true,
expandColumnPosition: 'right'
};
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const expandRow = {
renderer: row => (
<div>
<p>{ \`This Expand row is belong to rowKey $\{row.id}\` }</p>
<p>You can render anything here, also you can add additional data on every row object</p>
<p>expandRow.renderer callback will pass the origin row object to you</p>
</div>
),
showExpandColumn: true,
expandColumnPosition: 'right'
};
<BootstrapTable
keyField='id'
data={ products }
columns={ columns }
expandRow={ expandRow }
/>
`;
export default () => (
<div>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
expandRow={ expandRow }
/>
<Code>{ sourceCode }</Code>
</div>
);

View File

@@ -25,7 +25,6 @@ const expandRow = {
<p>expandRow.renderer callback will pass the origin row object to you</p>
</div>
),
showExpandColumn: true,
nonExpandable: [1, 3]
};
@@ -51,7 +50,6 @@ const expandRow = {
<p>expandRow.renderer callback will pass the origin row object to you</p>
</div>
),
showExpandColumn: true,
nonExpandable: [1, 3]
};

View File

@@ -1,88 +0,0 @@
/* eslint no-alert: 0 */
/* eslint consistent-return: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
class AdvSelectionManagment extends React.Component {
handleOnSelect = (row, isSelect) => {
if (isSelect && row.id < 3) {
alert('Oops, You can not select Product ID which less than 3');
return false; // return false to deny current select action
}
return true; // return true or dont return to approve current select action
}
handleOnSelectAll = (isSelect, rows) => {
if (isSelect) {
return rows.filter(r => r.id >= 3).map(r => r.id);
}
}
render() {
const selectRow = {
mode: 'checkbox',
clickToSelect: true,
onSelect: this.handleOnSelect,
onSelectAll: this.handleOnSelectAll
};
return (
<div>
<h3>You can not select Product ID less than 3</h3>
<BootstrapTable keyField="id" data={ products } columns={ columns } selectRow={ selectRow } />
<Code>{ sourceCode }</Code>
</div>
);
}
}
`;
export default class AdvSelectionManagment extends React.Component {
handleOnSelect = (row, isSelect) => {
if (isSelect && row.id < 3) {
alert('Oops, You can not select Product ID which less than 3');
return false; // return false to deny current select action
}
return true; // return true or dont return to approve current select action
}
handleOnSelectAll = (isSelect, rows) => {
if (isSelect) {
return rows.filter(r => r.id >= 3).map(r => r.id);
}
}
render() {
const selectRow = {
mode: 'checkbox',
clickToSelect: true,
onSelect: this.handleOnSelect,
onSelectAll: this.handleOnSelectAll
};
return (
<div>
<h3>You can not select Product ID less than 3</h3>
<BootstrapTable keyField="id" data={ products } columns={ columns } selectRow={ selectRow } />
<Code>{ sourceCode }</Code>
</div>
);
}
}

View File

@@ -1,12 +1,10 @@
/* eslint no-unused-vars: 0 */
/* eslint no-console: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const products = productsGenerator(87);
const columns = [{
dataField: 'id',
@@ -19,14 +17,16 @@ const columns = [{
text: 'Product Price'
}];
const rowEvents = {
onClick: (e, row, rowIndex) => {
console.log(`clicked on row with index: ${rowIndex}`);
},
onMouseEnter: (e, row, rowIndex) => {
console.log(`enter on row with index: ${rowIndex}`);
const style = `\
// Customizing your own sticky table style by simply overwriting .table-sticky
.react-bootstrap-table {
.sticky.table-sticky {
tbody {
max-height: 200px;
}
}
};
}
`;
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
@@ -42,16 +42,14 @@ const columns = [{
text: 'Product Price'
}];
const hiddenRowKeys = [1, 3];
<BootstrapTable keyField="id" data={ products } columns={ columns } hiddenRows={ hiddenRowKeys } />
<BootstrapTable sticky classes="sticky" keyField="id" data={ products } columns={ columns } />
`;
const hiddenRowKeys = [1, 3];
export default () => (
<div>
<BootstrapTable keyField="id" data={ products } columns={ columns } hiddenRows={ hiddenRowKeys } />
<BootstrapTable sticky classes="sticky" keyField="id" data={ products } columns={ columns } />
<Code>{ style }</Code>
<Code>{ sourceCode }</Code>
</div>
);

View File

@@ -0,0 +1,43 @@
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator(87);
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
<BootstrapTable sticky keyField="id" data={ products } columns={ columns } />
`;
export default () => (
<div>
<BootstrapTable sticky keyField="id" data={ products } columns={ columns } />
<Code>{ sourceCode }</Code>
</div>
);

View File

@@ -1,6 +1,6 @@
{
"name": "react-bootstrap-table2-example",
"version": "1.0.14",
"version": "1.0.8",
"description": "",
"main": "index.js",
"private": true,

View File

@@ -1,5 +1,4 @@
/* eslint no-mixed-operators: 0 */
/* eslint no-param-reassign: 0 */
/**
* products generator for stories
@@ -23,12 +22,6 @@ export const productsGenerator = (quantity = 5, callback) => {
);
};
export const withOnSale = rows => rows.map((row) => {
if (row.id > 2) row.onSale = false;
else row.onSale = true;
return row;
});
export const productsQualityGenerator = (quantity = 5) =>
Array.from({ length: quantity }, (value, index) => ({
id: index,

View File

@@ -55,7 +55,6 @@ import CustomFilterValue from 'examples/column-filter/custom-filter-value';
import SelectFilter from 'examples/column-filter/select-filter';
import SelectFilterWithDefaultValue from 'examples/column-filter/select-filter-default-value';
import SelectFilterComparator from 'examples/column-filter/select-filter-like-comparator';
import SelectFilterWithPreservedOptionsOrder from 'examples/column-filter/select-filter-preserve-option-order';
import CustomSelectFilter from 'examples/column-filter/custom-select-filter';
import MultiSelectFilter from 'examples/column-filter/multi-select-filter';
import MultiSelectFilterDefaultValue from 'examples/column-filter/multi-select-filter-default-value';
@@ -74,13 +73,11 @@ import ProgrammaticallyMultiSelectFilter from 'examples/column-filter/programmat
import CustomFilter from 'examples/column-filter/custom-filter';
import AdvanceCustomFilter from 'examples/column-filter/advance-custom-filter';
import ClearAllFilters from 'examples/column-filter/clear-all-filters';
import FilterHooks from 'examples/column-filter/filter-hooks';
// work on rows
import RowStyleTable from 'examples/rows/row-style';
import RowClassTable from 'examples/rows/row-class';
import RowEventTable from 'examples/rows/row-event';
import RowHiddenTable from 'examples/rows/row-hidden';
// table sort
import EnableSortTable from 'examples/sort/enable-sort-table';
@@ -121,7 +118,6 @@ import MultipleSelectionTable from 'examples/row-selection/multiple-selection';
import ClickToSelectTable from 'examples/row-selection/click-to-select';
import DefaultSelectTable from 'examples/row-selection/default-select';
import SelectionManagement from 'examples/row-selection/selection-management';
import AdvanceSelectionManagement from 'examples/row-selection/selection-advance-management';
import ClickToSelectWithCellEditTable from 'examples/row-selection/click-to-select-with-cell-edit';
import SelectionWithExpansionTable from 'examples/row-selection/selection-with-expansion';
import SelectionNoDataTable from 'examples/row-selection/selection-no-data';
@@ -142,21 +138,12 @@ import ExpandColumn from 'examples/row-expand/expand-column';
import OnlyExpandByColumn from 'examples/row-expand/expand-by-column-only.js';
import ExpandOnlyOne from 'examples/row-expand/expand-only-one';
import CustomExpandColumn from 'examples/row-expand/custom-expand-column';
import ExpandColumnPosition from 'examples/row-expand/expand-column-position';
import ExpandHooks from 'examples/row-expand/expand-hooks';
// pagination
import PaginationTable from 'examples/pagination';
import PaginationHooksTable from 'examples/pagination/pagination-hooks';
import CustomPaginationTable from 'examples/pagination/custom-pagination';
import CustomPageButtonTable from 'examples/pagination/custom-page-button';
import CustomSizePerPageOptionTable from 'examples/pagination/custom-size-per-page-option';
import CustomSizePerPageTable from 'examples/pagination/custom-size-per-page';
import CustomPageListTable from 'examples/pagination/custom-page-list';
import StandalonePaginationList from 'examples/pagination/standalone-pagination-list';
import StandaloneSizePerPage from 'examples/pagination/standalone-size-per-page';
import FullyCustomPaginationTable from 'examples/pagination/fully-custom-pagination';
import RemoteStandalonePaginationTable from 'examples/pagination/remote-standalone-pagination';
// search
import SearchTable from 'examples/search';
@@ -181,6 +168,10 @@ import CustomCSV from 'examples/csv/custom-csv';
import EmptyTableOverlay from 'examples/loading-overlay/empty-table-overlay';
import TableOverlay from 'examples/loading-overlay/table-overlay';
// sticky header table
import StickyHeaderTable from 'examples/sticky-header/default';
import StickyHeaderCustomStyleTable from 'examples/sticky-header/customized-style.js';
// remote
import RemoteSort from 'examples/remote/remote-sort';
import RemoteFilter from 'examples/remote/remote-filter';
@@ -275,15 +266,12 @@ storiesOf('Column Filter', module)
.add('Programmatically Multi Select Filter', () => <ProgrammaticallyMultiSelectFilter />)
.add('Custom Filter', () => <CustomFilter />)
.add('Advance Custom Filter', () => <AdvanceCustomFilter />)
.add('Preserved Option Order on Select Filter', () => <SelectFilterWithPreservedOptionsOrder />)
.add('Clear All Filters', () => <ClearAllFilters />)
.add('Filter Hooks', () => <FilterHooks />);
.add('Clear All Filters', () => <ClearAllFilters />);
storiesOf('Work on Rows', module)
.addDecorator(bootstrapStyle())
.add('Customize Row Style', () => <RowStyleTable />)
.add('Customize Row Class', () => <RowClassTable />)
.add('Hide Rows', () => <RowHiddenTable />)
.add('Row Event', () => <RowEventTable />);
storiesOf('Sort Table', module)
@@ -328,7 +316,6 @@ storiesOf('Row Selection', module)
.add('Click to Select', () => <ClickToSelectTable />)
.add('Default Select', () => <DefaultSelectTable />)
.add('Selection Management', () => <SelectionManagement />)
.add('Advance Selection Management', () => <AdvanceSelectionManagement />)
.add('Click to Select and Edit Cell', () => <ClickToSelectWithCellEditTable />)
.add('Row Select and Expand', () => <SelectionWithExpansionTable />)
.add('Selection without Data', () => <SelectionNoDataTable />)
@@ -350,22 +337,13 @@ storiesOf('Row Expand', module)
.add('Only Expand by Indicator', () => <OnlyExpandByColumn />)
.add('Expand Only One Row at The Same Time', () => <ExpandOnlyOne />)
.add('Custom Expand Indicator', () => <CustomExpandColumn />)
.add('Expand Column Position', () => <ExpandColumnPosition />)
.add('Expand Hooks', () => <ExpandHooks />);
storiesOf('Pagination', module)
.addDecorator(bootstrapStyle())
.add('Basic Pagination Table', () => <PaginationTable />)
.add('Pagination Hooks', () => <PaginationHooksTable />)
.add('Custom Pagination', () => <CustomPaginationTable />)
.add('Custom Page Button', () => <CustomPageButtonTable />)
.add('Custom Page List', () => <CustomPageListTable />)
.add('Custom SizePerPage Option', () => <CustomSizePerPageOptionTable />)
.add('Custom SizePerPage', () => <CustomSizePerPageTable />)
.add('Standalone Pagination List', () => <StandalonePaginationList />)
.add('Standalone SizePerPage Dropdown', () => <StandaloneSizePerPage />)
.add('Fully Custom Pagination', () => <FullyCustomPaginationTable />)
.add('Remote Fully Custom Pagination', () => <RemoteStandalonePaginationTable />);
.add('Custom Pagination', () => <CustomPaginationTable />);
storiesOf('Table Search', module)
.addDecorator(bootstrapStyle())
@@ -388,6 +366,11 @@ storiesOf('Export CSV', module)
.add('Export Custom Data', () => <ExportCustomData />)
.add('Custom CSV', () => <CustomCSV />);
storiesOf('Sticky header', module)
.addDecorator(bootstrapStyle())
.add('Default sticky header', () => <StickyHeaderTable />)
.add('Custom style for sticky header', () => <StickyHeaderCustomStyleTable />);
storiesOf('EmptyTableOverlay', module)
.addDecorator(bootstrapStyle())
.add('Empty Table Overlay', () => <EmptyTableOverlay />)

View File

@@ -0,0 +1,7 @@
.react-bootstrap-table {
.sticky.table-sticky {
tbody {
max-height: 200px;
}
}
}

View File

@@ -12,3 +12,4 @@
@import "sort/index";
@import "search/index";
@import "loading-overlay/index";
@import "sticky/index";

View File

@@ -115,27 +115,6 @@ const qualityFilter = selectFilter({
// omit...
```
> Note, the selectOptions can be an array also:
```js
const selectOptions = [
{ value: 0, label: 'good' },
{ value: 1, label: 'Bad' },
{ value: 2, label: 'unknown' }
];
const columns = [
..., {
dataField: 'quality',
text: 'Product Quailty',
formatter: cell => selectOptions.find(opt => opt.value === cell).label,
filter: selectFilter({
options: selectOptions
})
}];
```
The benifit is `react-bootstrap-table2` will render the select options by the order of array.
## MultiSelect Filter
A quick example:

View File

@@ -1,6 +1,6 @@
{
"name": "react-bootstrap-table2-filter",
"version": "1.1.1",
"version": "1.0.1",
"description": "it's a column filter addon for react-bootstrap-table2",
"main": "./lib/index.js",
"repository": {

View File

@@ -7,17 +7,6 @@ import { LIKE, EQ } from '../comparison';
import { FILTER_TYPE } from '../const';
function optionsEquals(currOpts, prevOpts) {
if (Array.isArray(currOpts)) {
for (let i = 0; i < currOpts.length; i += 1) {
if (
currOpts[i].value !== prevOpts[i].value ||
currOpts[i].label !== prevOpts[i].label
) {
return false;
}
}
return currOpts.length === prevOpts.length;
}
const keys = Object.keys(currOpts);
for (let i = 0; i < keys.length; i += 1) {
if (currOpts[keys[i]] !== prevOpts[keys[i]]) {
@@ -27,21 +16,11 @@ function optionsEquals(currOpts, prevOpts) {
return Object.keys(currOpts).length === Object.keys(prevOpts).length;
}
function getOptionValue(options, key) {
if (Array.isArray(options)) {
const result = options
.filter(({ label }) => label === key)
.map(({ value }) => value);
return result[0];
}
return options[key];
}
class SelectFilter extends Component {
constructor(props) {
super(props);
this.filter = this.filter.bind(this);
const isSelected = getOptionValue(props.options, props.defaultValue) !== undefined;
const isSelected = props.options[props.defaultValue] !== undefined;
this.state = { isSelected };
}
@@ -87,14 +66,9 @@ class SelectFilter extends Component {
<option key="-1" value="">{ placeholder || `Select ${column.text}...` }</option>
));
}
if (Array.isArray(options)) {
options.forEach(({ value, label }) =>
optionTags.push(<option key={ value } value={ value }>{ label }</option>));
} else {
Object.keys(options).forEach(key =>
optionTags.push(<option key={ key } value={ key }>{ options[key] }</option>)
);
}
Object.keys(options).forEach(key =>
optionTags.push(<option key={ key } value={ key }>{ options[key] }</option>)
);
return optionTags;
}
@@ -154,7 +128,7 @@ class SelectFilter extends Component {
SelectFilter.propTypes = {
onFilter: PropTypes.func.isRequired,
column: PropTypes.object.isRequired,
options: PropTypes.oneOfType([PropTypes.object, PropTypes.array]).isRequired,
options: PropTypes.object.isRequired,
comparator: PropTypes.oneOf([LIKE, EQ]),
placeholder: PropTypes.string,
style: PropTypes.object,

View File

@@ -64,10 +64,6 @@ export default (
return;
}
if (filter.props.onFilter) {
filter.props.onFilter(filterVal);
}
this.forceUpdate();
};
}

View File

@@ -44,8 +44,7 @@ describe('FilterContext', () => {
const handleFilterChange = jest.fn();
function shallowContext(
enableRemote = false,
tableColumns = columns
enableRemote = false
) {
mockBase.mockReset();
handleFilterChange.mockReset();
@@ -57,7 +56,7 @@ describe('FilterContext', () => {
return (
<FilterContext.Provider
columns={ tableColumns }
columns={ columns }
data={ data }
>
<FilterContext.Consumer>
@@ -226,32 +225,6 @@ describe('FilterContext', () => {
});
});
describe('if filter.props.onFilter is defined', () => {
const filterVal = '3';
const onFilter = jest.fn();
const customColumns = columns.map((column, i) => {
if (i === 1) {
return {
...column,
filter: textFilter({ onFilter })
};
}
return column;
});
beforeEach(() => {
wrapper = shallow(shallowContext(false, customColumns));
wrapper.render();
instance = wrapper.instance();
});
it('should call filter.props.onFilter correctly', () => {
instance.onFilter(customColumns[1], FILTER_TYPE.TEXT)(filterVal);
expect(onFilter).toHaveBeenCalledTimes(1);
expect(onFilter).toHaveBeenCalledWith(filterVal);
});
});
describe('combination', () => {
beforeEach(() => {
wrapper = shallow(shallowContext());

View File

@@ -37,188 +37,4 @@ import paginationFactory from 'react-bootstrap-table2-paginator';
## Customization
### Basic Customization
`react-bootstrap-table2` give some simple ways to customize something like text, styling etc, following is all the props we support for basic customization:
* [paginationSize](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/pagination-props.html#paginationpaginationsize-number)
* [sizePerPageList](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/pagination-props.html#paginationsizeperpagelist-array)
* [withFirstAndLast](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/pagination-props.html#paginationwithfirstandlast-bool)
* [alwaysShowAllBtns](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/pagination-props.html#paginationalwaysshowallbtns-bool)
* [firstPageText](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/pagination-props.html#paginationfirstpagetext-any)
* [prePageText](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/pagination-props.html#paginationprepagetext-any)
* [nextPageText](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/pagination-props.html#paginationnextpagetext-any)
* [lastPageText](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/pagination-props.html#paginationlastpagetext-any)
* [firstPageTitle](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/pagination-props.html#paginationfirstpagetitle-any)
* [prePageTitle](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/pagination-props.html#paginationprepagetitle-any)
* [nextPageTitle](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/pagination-props.html#paginationnextpagetitle-any)
* [lastPageTitle](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/pagination-props.html#paginationlastpagetitle-any)
* [hideSizePerPage](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/pagination-props.html#paginationhidesizeperpage-bool)
* [hidePageListOnlyOnePage](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/pagination-props.html#paginationhidepagelistonlyonepage-bool)
* [showTotal](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/pagination-props.html#paginationshowtotal-bool)
You can check [this online demo](https://react-bootstrap-table.github.io/react-bootstrap-table2/storybook/index.html?selectedKind=Pagination&selectedStory=Custom%20Pagination&full=0&addons=1&stories=1&panelRight=0&addonPanel=storybook%2Factions%2Factions-panel) for above props usage.
### Advance Customization
Sometime, you may feel above props is not satisfied with your requirement, don't worry, we provide following renderer for each part of pagination:
* [pageListRenderer](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/pagination-props.html#paginationpagelistrenderer-function)
* [pageButtonRenderer](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/pagination-props.html#paginationpagebuttonrenderer-function)
* [sizePerPageRenderer](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/pagination-props.html#paginationsizeperpagerenderer-function)
* [sizePerPageOptionRenderer](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/pagination-props.html#paginationsizeperpageoptionrenderer-function)
* [paginationTotalRenderer](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/pagination-props.html#paginationpaginationtotalrenderer-function)
### Professional
If you want to customize the pagination component completely, you may get interesting on following solution:
* Standalone
* Non-standalone
`react-bootstrap-table2-paginator` have a `PaginationProvider` which is a react context and you will be easier to customize the pagination components under the scope of `PaginationProvider`. Let's introduce it step by step:
#### Import PaginationProvider
```js
import paginationFactory, { PaginationProvider } from 'react-bootstrap-table2-paginator';
```
#### Declare custom and totalSize in pagination option:
```js
const paginationOption = {
custom: true,
totalSize: products.length
};
```
#### Render PaginationProvider
```js
<PaginationProvider
pagination={ paginationFactory(options) }
>
{
({
paginationProps,
paginationTableProps
}) => (
.....
)
}
</PaginationProvider>
```
`PaginationProvider` actually is a wrapper for the concumser of react context, so that now you have to get the props from context provide then render to your compoennt and `BootstrapTable`:
* `paginationProps`: this include everything about pagination, you will use it when you render standalone component or your custom component.
* `paginationTableProps`: you don't need to know about this, but you have to render this as props to `BootstrapTable`.
So far, your customization pagination is supposed to look like it:
```js
<PaginationProvider
pagination={ paginationFactory(options) }
>
{
({
paginationProps,
paginationTableProps
}) => (
<div>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
{ ...paginationTableProps }
/>
</div>
)
}
</PaginationProvider>
```
Now, you have to choose, your built-in standalne components or you customize all of them by yourself:
#### Use Standalone Component
`react-bootstrap-table2-paginator` provider two standalone components:
* Size Per Page Dropdwn Standalone
* Pagination List Standalone
When render each standalone, you just need to pass the `paginationProps` props to standalone component:
```js
import paginationFactory, { PaginationProvider, PaginationListStandalone, SizePerPageDropdownStandalone } from 'react-bootstrap-table2-paginator';
<PaginationProvider
pagination={ paginationFactory(options) }
>
{
({
paginationProps,
paginationTableProps
}) => (
<div>
<SizePerPageDropdownStandalone
{ ...paginationProps }
/>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
{ ...paginationTableProps }
/>
<PaginationListStandalone
{ ...paginationProps }
/>
</div>
)
}
</PaginationProvider>
```
That's it!! The benifit for using standalone is you can much easier to render the standalone component in any posistion. In the future, we will implement more featue like applying `style`, `className` etc on standalone components.
#### Customization Everything
If you choose to custom the pagination component by yourself, the `paginationProps` will be important for you. Becasue you have to know for example how to change page or what's the current page etc. Hence, following is all the props in `paginationProps` object:
```js
page,
sizePerPage,
pageStartIndex,
hidePageListOnlyOnePage,
hideSizePerPage,
alwaysShowAllBtns,
withFirstAndLast,
dataSize,
sizePerPageList,
paginationSize,
showTotal,
pageListRenderer,
pageButtonRenderer,
sizePerPageRenderer,
paginationTotalRenderer,
sizePerPageOptionRenderer,
firstPageText,
prePageText,
nextPageText,
lastPageText,
prePageTitle,
nextPageTitle,
firstPageTitle,
lastPageTitle,
onPageChange,
onSizePerPageChange
```
In most of case, `page`, `sizePerPage`, `onPageChange` and `onSizePerPageChange` are most important things for developer.
* `page`: Current page.
* `sizePerPage`: Current size per page.
* `onPageChange`: Call it when you nede to change page. This function accept one number argument which indicate the new page
* `onSizePerPageChange`: Call it when you nede to change size per page. This function accept two number argument which indicate the new sizePerPage and new page
[Here](https://react-bootstrap-table.github.io/react-bootstrap-table2/storybook/index.html?selectedKind=Pagination&selectedStory=Fully%20Custom%20Pagination&full=0&addons=1&stories=1&panelRight=0&addonPanel=storybook%2Factions%2Factions-panel) is a online example.
See [pagination props](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/pagination-props.html)

View File

@@ -1,26 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import createBaseContext from './src/state-context';
import createDataContext from './src/data-context';
import PaginationListStandalone from './src/pagination-list-standalone';
import SizePerPageDropdownStandalone from './src/size-per-page-dropdown-standalone';
import createContext from './src/context';
export default (options = {}) => ({
createContext: createDataContext,
createContext,
options
});
const { Provider, Consumer } = createBaseContext();
const CustomizableProvider = props => (
<Provider { ...props }>
<Consumer>{ paginationProps => props.children(paginationProps) }</Consumer>
</Provider>
);
CustomizableProvider.propTypes = {
children: PropTypes.func.isRequired
};
export const PaginationProvider = CustomizableProvider;
export { PaginationListStandalone, SizePerPageDropdownStandalone };

View File

@@ -1,6 +1,6 @@
{
"name": "react-bootstrap-table2-paginator",
"version": "2.0.1",
"version": "1.0.3",
"description": "it's the pagination addon for react-bootstrap-table2",
"main": "./lib/index.js",
"repository": {

View File

@@ -0,0 +1,182 @@
/* eslint react/prop-types: 0 */
/* eslint react/require-default-props: 0 */
/* eslint no-lonely-if: 0 */
import React from 'react';
import PropTypes from 'prop-types';
import Const from './const';
import { BootstrapContext } from './bootstrap';
import Pagination from './pagination';
import { getByCurrPage, alignPage } from './page';
export default (
isRemotePagination,
handleRemotePageChange
) => {
const PaginationContext = React.createContext();
class PaginationProvider extends React.Component {
static propTypes = {
data: PropTypes.array.isRequired
}
constructor(props) {
super(props);
this.handleChangePage = this.handleChangePage.bind(this);
this.handleChangeSizePerPage = this.handleChangeSizePerPage.bind(this);
let currPage;
let currSizePerPage;
const { options } = props.pagination;
const sizePerPageList = options.sizePerPageList || Const.SIZE_PER_PAGE_LIST;
// initialize current page
if (typeof options.page !== 'undefined') {
currPage = options.page;
} else if (typeof options.pageStartIndex !== 'undefined') {
currPage = options.pageStartIndex;
} else {
currPage = Const.PAGE_START_INDEX;
}
// initialize current sizePerPage
if (typeof options.sizePerPage !== 'undefined') {
currSizePerPage = options.sizePerPage;
} else if (typeof sizePerPageList[0] === 'object') {
currSizePerPage = sizePerPageList[0].value;
} else {
currSizePerPage = sizePerPageList[0];
}
this.currPage = currPage;
this.currSizePerPage = currSizePerPage;
}
componentWillReceiveProps(nextProps) {
let needNewState = false;
let { currPage } = this;
const { currSizePerPage } = this;
const { onPageChange } = nextProps.pagination.options;
const pageStartIndex = typeof nextProps.pagination.options.pageStartIndex !== 'undefined' ?
nextProps.pagination.options.pageStartIndex : Const.PAGE_START_INDEX;
// user should align the page when the page is not fit to the data size when remote enable
if (!isRemotePagination()) {
const newPage = alignPage(nextProps.data, currPage, currSizePerPage, pageStartIndex);
if (currPage !== newPage) {
currPage = newPage;
needNewState = true;
}
} else {
this.currPage = nextProps.pagination.options.page;
this.currSizePerPage = nextProps.pagination.options.sizePerPage;
}
if (needNewState) {
if (onPageChange) {
onPageChange(currPage, currSizePerPage);
}
this.currPage = currPage;
this.currSizePerPage = currSizePerPage;
}
}
handleChangePage(currPage) {
const { currSizePerPage } = this;
const { pagination: { options } } = this.props;
if (options.onPageChange) {
options.onPageChange(currPage, currSizePerPage);
}
this.currPage = currPage;
if (isRemotePagination()) {
handleRemotePageChange(currPage, currSizePerPage);
return;
}
this.forceUpdate();
}
handleChangeSizePerPage(currSizePerPage, currPage) {
const { pagination: { options } } = this.props;
if (options.onSizePerPageChange) {
options.onSizePerPageChange(currSizePerPage, currPage);
}
this.currPage = currPage;
this.currSizePerPage = currSizePerPage;
if (isRemotePagination()) {
handleRemotePageChange(currPage, currSizePerPage);
return;
}
this.forceUpdate();
}
render() {
let { data } = this.props;
const { pagination: { options }, bootstrap4 } = this.props;
const { currPage, currSizePerPage } = this;
const withFirstAndLast = typeof options.withFirstAndLast === 'undefined' ?
Const.With_FIRST_AND_LAST : options.withFirstAndLast;
const alwaysShowAllBtns = typeof options.alwaysShowAllBtns === 'undefined' ?
Const.SHOW_ALL_PAGE_BTNS : options.alwaysShowAllBtns;
const hideSizePerPage = typeof options.hideSizePerPage === 'undefined' ?
Const.HIDE_SIZE_PER_PAGE : options.hideSizePerPage;
const hidePageListOnlyOnePage = typeof options.hidePageListOnlyOnePage === 'undefined' ?
Const.HIDE_PAGE_LIST_ONLY_ONE_PAGE : options.hidePageListOnlyOnePage;
const pageStartIndex = typeof options.pageStartIndex === 'undefined' ?
Const.PAGE_START_INDEX : options.pageStartIndex;
data = isRemotePagination() ?
data :
getByCurrPage(
data,
currPage,
currSizePerPage,
pageStartIndex
);
return (
<PaginationContext.Provider value={ { data } }>
{ this.props.children }
<BootstrapContext.Provider value={ { bootstrap4 } }>
<Pagination
key="pagination"
dataSize={ options.totalSize || this.props.data.length }
currPage={ currPage }
currSizePerPage={ currSizePerPage }
onPageChange={ this.handleChangePage }
onSizePerPageChange={ this.handleChangeSizePerPage }
sizePerPageList={ options.sizePerPageList || Const.SIZE_PER_PAGE_LIST }
paginationSize={ options.paginationSize || Const.PAGINATION_SIZE }
pageStartIndex={ pageStartIndex }
withFirstAndLast={ withFirstAndLast }
alwaysShowAllBtns={ alwaysShowAllBtns }
hideSizePerPage={ hideSizePerPage }
hidePageListOnlyOnePage={ hidePageListOnlyOnePage }
showTotal={ options.showTotal }
paginationTotalRenderer={ options.paginationTotalRenderer }
firstPageText={ options.firstPageText || Const.FIRST_PAGE_TEXT }
prePageText={ options.prePageText || Const.PRE_PAGE_TEXT }
nextPageText={ options.nextPageText || Const.NEXT_PAGE_TEXT }
lastPageText={ options.lastPageText || Const.LAST_PAGE_TEXT }
prePageTitle={ options.prePageTitle || Const.PRE_PAGE_TITLE }
nextPageTitle={ options.nextPageTitle || Const.NEXT_PAGE_TITLE }
firstPageTitle={ options.firstPageTitle || Const.FIRST_PAGE_TITLE }
lastPageTitle={ options.lastPageTitle || Const.LAST_PAGE_TITLE }
/>
</BootstrapContext.Provider>
</PaginationContext.Provider>
);
}
}
return {
Provider: PaginationProvider,
Consumer: PaginationContext.Consumer
};
};

View File

@@ -1,100 +0,0 @@
/* eslint react/prop-types: 0 */
/* eslint react/require-default-props: 0 */
/* eslint no-lonely-if: 0 */
import React from 'react';
import PropTypes from 'prop-types';
import Const from './const';
import { BootstrapContext } from './bootstrap';
import Pagination from './pagination';
import { getByCurrPage, alignPage } from './page';
import createBaseContext from './state-context';
const { Provider } = createBaseContext();
const PaginationDataContext = React.createContext();
class PaginationDataProvider extends Provider {
static propTypes = {
data: PropTypes.array.isRequired,
remoteEmitter: PropTypes.object.isRequired,
isRemotePagination: PropTypes.func.isRequired
}
componentWillReceiveProps(nextProps) {
super.componentWillReceiveProps(nextProps);
const { currSizePerPage } = this;
const { custom, onPageChange } = nextProps.pagination.options;
const pageStartIndex = typeof nextProps.pagination.options.pageStartIndex !== 'undefined' ?
nextProps.pagination.options.pageStartIndex : Const.PAGE_START_INDEX;
// user should align the page when the page is not fit to the data size when remote enable
if (!this.isRemotePagination() && !custom) {
const newPage = alignPage(
nextProps.data.length, this.currPage, currSizePerPage, pageStartIndex);
if (this.currPage !== newPage) {
if (onPageChange) {
onPageChange(newPage, currSizePerPage);
}
this.currPage = newPage;
}
}
}
isRemotePagination = () => this.props.isRemotePagination();
renderDefaultPagination = () => {
if (!this.props.pagination.options.custom) {
const {
bootstrap4,
page: currPage,
sizePerPage: currSizePerPage,
dataSize,
...rest
} = this.getPaginationProps();
return (
<BootstrapContext.Provider value={ { bootstrap4 } }>
<Pagination
{ ...rest }
key="pagination"
dataSize={ dataSize || this.props.data.length }
currPage={ currPage }
currSizePerPage={ currSizePerPage }
/>
</BootstrapContext.Provider>
);
}
return null;
}
render() {
let { data } = this.props;
const { pagination: { options } } = this.props;
const { currPage, currSizePerPage } = this;
const pageStartIndex = typeof options.pageStartIndex === 'undefined' ?
Const.PAGE_START_INDEX : options.pageStartIndex;
data = this.isRemotePagination() ?
data :
getByCurrPage(
data,
currPage,
currSizePerPage,
pageStartIndex
);
return (
<PaginationDataContext.Provider value={ { data, setRemoteEmitter: this.setRemoteEmitter } }>
{ this.props.children }
{ this.renderDefaultPagination() }
</PaginationDataContext.Provider>
);
}
}
export default () => ({
Provider: PaginationDataProvider,
Consumer: PaginationDataContext.Consumer
});

View File

@@ -20,14 +20,13 @@ class PageButton extends Component {
page,
title,
active,
disabled,
className
disabled
} = this.props;
const classes = cs({
active,
disabled,
'page-item': true
}, className);
});
return (
<li className={ classes } title={ title }>
@@ -42,7 +41,6 @@ PageButton.propTypes = {
page: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
active: PropTypes.bool.isRequired,
disabled: PropTypes.bool.isRequired,
className: PropTypes.string,
title: PropTypes.string
};

View File

@@ -8,10 +8,16 @@ export default ExtendBase =>
return (currPage - 1) < pageStartIndex ? pageStartIndex : currPage - 1;
}
goToNextPage() {
const { currPage } = this.props;
const { lastPage } = this.state;
return (currPage + 1) > lastPage ? lastPage : currPage + 1;
}
initialState() {
const totalPages = this.calculateTotalPage();
const lastPage = this.calculateLastPage(totalPages);
return { totalPages, lastPage };
return { totalPages, lastPage, dropdownOpen: false };
}
calculateTotalPage(sizePerPage = this.props.currSizePerPage, dataSize = this.props.dataSize) {
@@ -41,9 +47,8 @@ export default ExtendBase =>
}
calculatePages(
totalPages,
lastPage
) {
totalPages = this.state.totalPages,
lastPage = this.state.lastPage) {
const {
currPage,
paginationSize,
@@ -89,7 +94,7 @@ export default ExtendBase =>
return pages;
}
calculatePageStatus(pages = [], lastPage) {
calculatePageStatus(pages = [], lastPage = this.state.lastPage) {
const {
currPage,
pageStartIndex,
@@ -135,8 +140,8 @@ export default ExtendBase =>
calculateSizePerPageStatus() {
const { sizePerPageList } = this.props;
return sizePerPageList.map((_sizePerPage) => {
const pageText = typeof _sizePerPage.text !== 'undefined' ? _sizePerPage.text : _sizePerPage;
const pageNumber = typeof _sizePerPage.value !== 'undefined' ? _sizePerPage.value : _sizePerPage;
const pageText = _sizePerPage.text || _sizePerPage;
const pageNumber = _sizePerPage.value || _sizePerPage;
return {
text: `${pageText}`,
page: pageNumber

View File

@@ -18,11 +18,13 @@ const startIndex = (
) => end - (sizePerPage - 1);
export const alignPage = (
dataSize,
data,
page,
sizePerPage,
pageStartIndex
) => {
const dataSize = data.length;
if (page < pageStartIndex || page > (Math.floor(dataSize / sizePerPage) + pageStartIndex)) {
return pageStartIndex;
}

View File

@@ -1,77 +0,0 @@
/* eslint react/prop-types: 0 */
import React, { Component } from 'react';
import pageResolver from './page-resolver';
export default WrappedComponent =>
class PaginationHandler extends pageResolver(Component) {
constructor(props) {
super(props);
this.handleChangePage = this.handleChangePage.bind(this);
this.handleChangeSizePerPage = this.handleChangeSizePerPage.bind(this);
this.state = this.initialState();
}
componentWillReceiveProps(nextProps) {
const { dataSize, currSizePerPage } = nextProps;
if (currSizePerPage !== this.props.currSizePerPage || dataSize !== this.props.dataSize) {
const totalPages = this.calculateTotalPage(currSizePerPage, dataSize);
const lastPage = this.calculateLastPage(totalPages);
this.setState({ totalPages, lastPage });
}
}
handleChangeSizePerPage(sizePerPage) {
const { currSizePerPage, onSizePerPageChange } = this.props;
const selectedSize = typeof sizePerPage === 'string' ? parseInt(sizePerPage, 10) : sizePerPage;
let { currPage } = this.props;
if (selectedSize !== currSizePerPage) {
const newTotalPages = this.calculateTotalPage(selectedSize);
const newLastPage = this.calculateLastPage(newTotalPages);
if (currPage > newLastPage) currPage = newLastPage;
onSizePerPageChange(selectedSize, currPage);
}
}
handleChangePage(newPage) {
let page;
const {
currPage,
pageStartIndex,
prePageText,
nextPageText,
lastPageText,
firstPageText,
onPageChange
} = this.props;
const { lastPage } = this.state;
if (newPage === prePageText) {
page = this.backToPrevPage();
} else if (newPage === nextPageText) {
page = (currPage + 1) > lastPage ? lastPage : currPage + 1;
} else if (newPage === lastPageText) {
page = lastPage;
} else if (newPage === firstPageText) {
page = pageStartIndex;
} else {
page = parseInt(newPage, 10);
}
if (page !== currPage) {
onPageChange(page);
}
}
render() {
return (
<WrappedComponent
{ ...this.props }
lastPage={ this.state.lastPage }
totalPages={ this.state.totalPages }
onPageChange={ this.handleChangePage }
onSizePerPageChange={ this.handleChangeSizePerPage }
/>
);
}
};

View File

@@ -1,24 +0,0 @@
/* eslint react/prop-types: 0 */
import React, { Component } from 'react';
import pageResolver from './page-resolver';
import PaginationList from './pagination-list';
const paginationListAdapter = WrappedComponent =>
class PaginationListAdapter extends pageResolver(Component) {
render() {
const { lastPage, totalPages, pageButtonRenderer, onPageChange } = this.props;
const pages = this.calculatePageStatus(this.calculatePages(totalPages, lastPage), lastPage);
return (
<WrappedComponent
pageButtonRenderer={ pageButtonRenderer }
onPageChange={ onPageChange }
pages={ pages }
/>
);
}
};
export const PaginationListWithAdapter = paginationListAdapter(PaginationList);
export default paginationListAdapter;

View File

@@ -1,12 +0,0 @@
import React from 'react';
import PaginationList from './pagination-list';
import standaloneAdapter from './standalone-adapter';
import PaginationHandler from './pagination-handler';
import paginationListAdapter from './pagination-list-adapter';
const PaginationListStandalone = props => (
<PaginationList { ...props } />
);
export default
standaloneAdapter(PaginationHandler(paginationListAdapter(PaginationListStandalone)));

View File

@@ -6,21 +6,13 @@ import PageButton from './page-button';
const PaginatonList = props => (
<ul className="pagination react-bootstrap-table-page-btns-ul">
{
props.pages.map((pageProps) => {
if (props.pageButtonRenderer) {
return props.pageButtonRenderer({
...pageProps,
onPageChange: props.onPageChange
});
}
return (
<PageButton
key={ pageProps.page }
{ ...pageProps }
onPageChange={ props.onPageChange }
/>
);
})
props.pages.map(pageProps => (
<PageButton
key={ pageProps.page }
{ ...pageProps }
onPageChange={ props.onPageChange }
/>
))
}
</ul>
);
@@ -32,12 +24,7 @@ PaginatonList.propTypes = {
disable: PropTypes.bool,
title: PropTypes.string
})).isRequired,
onPageChange: PropTypes.func.isRequired,
pageButtonRenderer: PropTypes.func
};
PaginatonList.defaultProps = {
pageButtonRenderer: null
onPageChange: PropTypes.func.isRequired
};
export default PaginatonList;

View File

@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
const PaginationTotal = props => (
<span className="react-bootstrap-table-pagination-total">
&nbsp;Showing rows { props.from } to&nbsp;{ props.to } of&nbsp;{ props.dataSize }
&nbsp;Showing rows { props.from } to&nbsp;{ props.to + 1 } of&nbsp;{ props.dataSize }
</span>
);

View File

@@ -4,13 +4,89 @@ import cs from 'classnames';
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import pageResolver from './page-resolver';
import paginationHandler from './pagination-handler';
import { SizePerPageDropdownAdapter } from './size-per-page-dropdown-adapter';
import { PaginationListWithAdapter } from './pagination-list-adapter';
import SizePerPageDropDown from './size-per-page-dropdown';
import PaginationList from './pagination-list';
import PaginationTotal from './pagination-total';
import Const from './const';
class Pagination extends pageResolver(Component) {
constructor(props) {
super(props);
this.closeDropDown = this.closeDropDown.bind(this);
this.toggleDropDown = this.toggleDropDown.bind(this);
this.handleChangePage = this.handleChangePage.bind(this);
this.handleChangeSizePerPage = this.handleChangeSizePerPage.bind(this);
this.state = this.initialState();
}
componentWillReceiveProps(nextProps) {
const { dataSize, currSizePerPage } = nextProps;
if (currSizePerPage !== this.props.currSizePerPage || dataSize !== this.props.dataSize) {
const totalPages = this.calculateTotalPage(currSizePerPage, dataSize);
const lastPage = this.calculateLastPage(totalPages);
this.setState({ totalPages, lastPage });
}
}
toggleDropDown() {
const dropdownOpen = !this.state.dropdownOpen;
this.setState(() => {
return { dropdownOpen };
});
}
closeDropDown() {
this.setState(() => {
return { dropdownOpen: false };
});
}
handleChangeSizePerPage(sizePerPage) {
const { currSizePerPage, onSizePerPageChange } = this.props;
const selectedSize = typeof sizePerPage === 'string' ? parseInt(sizePerPage, 10) : sizePerPage;
let { currPage } = this.props;
if (selectedSize !== currSizePerPage) {
const newTotalPages = this.calculateTotalPage(selectedSize);
const newLastPage = this.calculateLastPage(newTotalPages);
if (currPage > newLastPage) currPage = newLastPage;
onSizePerPageChange(selectedSize, currPage);
}
this.closeDropDown();
}
handleChangePage(newPage) {
let page;
const {
currPage,
pageStartIndex,
prePageText,
nextPageText,
lastPageText,
firstPageText,
onPageChange
// keepSizePerPageState
} = this.props;
const { lastPage } = this.state;
if (newPage === prePageText) {
page = this.backToPrevPage();
} else if (newPage === nextPageText) {
page = (currPage + 1) > lastPage ? lastPage : currPage + 1;
} else if (newPage === lastPageText) {
page = lastPage;
} else if (newPage === firstPageText) {
page = pageStartIndex;
} else {
page = parseInt(newPage, 10);
}
// if (keepSizePerPageState) { this.closeDropDown(); }
if (page !== currPage) {
onPageChange(page);
}
}
defaultTotal = (from, to, size) => (
<PaginationTotal
from={ from }
@@ -28,26 +104,17 @@ class Pagination extends pageResolver(Component) {
};
render() {
const { totalPages, lastPage, dropdownOpen: open } = this.state;
const {
showTotal,
dataSize,
pageListRenderer,
pageButtonRenderer,
paginationTotalRenderer,
hidePageListOnlyOnePage,
totalPages,
lastPage,
onPageChange,
sizePerPageList,
currSizePerPage,
hideSizePerPage,
sizePerPageRenderer,
sizePerPageOptionRenderer,
onSizePerPageChange,
...rest
hidePageListOnlyOnePage
} = this.props;
const pages = this.calculatePageStatus(this.calculatePages(totalPages, lastPage), lastPage);
const pages = this.calculatePageStatus(this.calculatePages(totalPages), lastPage);
const [from, to] = this.calculateFromTo();
const pageListClass = cs(
'react-bootstrap-table-pagination-list',
@@ -57,14 +124,19 @@ class Pagination extends pageResolver(Component) {
return (
<div className="row react-bootstrap-table-pagination">
<div className="col-md-6 col-xs-6 col-sm-6 col-lg-6">
<SizePerPageDropdownAdapter
sizePerPageList={ sizePerPageList }
currSizePerPage={ currSizePerPage }
hideSizePerPage={ hideSizePerPage }
sizePerPageRenderer={ sizePerPageRenderer }
sizePerPageOptionRenderer={ sizePerPageOptionRenderer }
onSizePerPageChange={ onSizePerPageChange }
/>
{
sizePerPageList.length > 1 && !hideSizePerPage ?
(
<SizePerPageDropDown
currSizePerPage={ `${currSizePerPage}` }
options={ this.calculateSizePerPageStatus() }
onSizePerPageChange={ this.handleChangeSizePerPage }
onClick={ this.toggleDropDown }
onBlur={ this.closeDropDown }
open={ open }
/>
) : null
}
{
showTotal ?
this.setTotal(
@@ -75,22 +147,9 @@ class Pagination extends pageResolver(Component) {
) : null
}
</div>
{
pageListRenderer ? pageListRenderer({
pages,
onPageChange
}) : (
<div className={ pageListClass }>
<PaginationListWithAdapter
{ ...rest }
lastPage={ lastPage }
totalPages={ totalPages }
pageButtonRenderer={ pageButtonRenderer }
onPageChange={ onPageChange }
/>
</div>
)
}
<div className={ pageListClass }>
<PaginationList pages={ pages } onPageChange={ this.handleChangePage } />
</div>
</div>
);
}
@@ -106,11 +165,7 @@ Pagination.propTypes = {
pageStartIndex: PropTypes.number,
paginationSize: PropTypes.number,
showTotal: PropTypes.bool,
pageListRenderer: PropTypes.func,
pageButtonRenderer: PropTypes.func,
sizePerPageRenderer: PropTypes.func,
paginationTotalRenderer: PropTypes.func,
sizePerPageOptionRenderer: PropTypes.func,
firstPageText: PropTypes.string,
prePageText: PropTypes.string,
nextPageText: PropTypes.string,
@@ -131,11 +186,7 @@ Pagination.defaultProps = {
withFirstAndLast: Const.With_FIRST_AND_LAST,
alwaysShowAllBtns: Const.SHOW_ALL_PAGE_BTNS,
showTotal: Const.SHOW_TOTAL,
pageListRenderer: null,
pageButtonRenderer: null,
sizePerPageRenderer: null,
paginationTotalRenderer: Const.PAGINATION_TOTAL,
sizePerPageOptionRenderer: null,
firstPageText: Const.FIRST_PAGE_TEXT,
prePageText: Const.PRE_PAGE_TEXT,
nextPageText: Const.NEXT_PAGE_TEXT,
@@ -149,4 +200,4 @@ Pagination.defaultProps = {
hidePageListOnlyOnePage: Const.HIDE_PAGE_LIST_ONLY_ONE_PAGE
};
export default paginationHandler(Pagination);
export default Pagination;

View File

@@ -1,67 +0,0 @@
/* eslint react/prop-types: 0 */
import React, { Component } from 'react';
import pageResolver from './page-resolver';
import SizePerPageDropDown from './size-per-page-dropdown';
const sizePerPageDropdownAdapter = WrappedComponent =>
class SizePerPageDropdownAdapter extends pageResolver(Component) {
constructor(props) {
super(props);
this.closeDropDown = this.closeDropDown.bind(this);
this.toggleDropDown = this.toggleDropDown.bind(this);
this.handleChangeSizePerPage = this.handleChangeSizePerPage.bind(this);
this.state = { dropdownOpen: false };
}
toggleDropDown() {
const dropdownOpen = !this.state.dropdownOpen;
this.setState(() => ({ dropdownOpen }));
}
closeDropDown() {
this.setState(() => ({ dropdownOpen: false }));
}
handleChangeSizePerPage(sizePerPage) {
this.props.onSizePerPageChange(sizePerPage);
this.closeDropDown();
}
render() {
const {
sizePerPageList,
currSizePerPage,
hideSizePerPage,
sizePerPageRenderer,
sizePerPageOptionRenderer
} = this.props;
const { dropdownOpen: open } = this.state;
if (sizePerPageList.length > 1 && !hideSizePerPage) {
if (sizePerPageRenderer) {
return sizePerPageRenderer({
options: this.calculateSizePerPageStatus(),
currSizePerPage: `${currSizePerPage}`,
onSizePerPageChange: this.handleChangeSizePerPage
});
}
return (
<WrappedComponent
currSizePerPage={ `${currSizePerPage}` }
options={ this.calculateSizePerPageStatus() }
optionRenderer={ sizePerPageOptionRenderer }
onSizePerPageChange={ this.handleChangeSizePerPage }
onClick={ this.toggleDropDown }
onBlur={ this.closeDropDown }
open={ open }
/>
);
}
return null;
}
};
export const SizePerPageDropdownAdapter = sizePerPageDropdownAdapter(SizePerPageDropDown);
export default sizePerPageDropdownAdapter;

View File

@@ -1,12 +0,0 @@
import React from 'react';
import SizePerPageDropdown from './size-per-page-dropdown';
import standaloneAdapter from './standalone-adapter';
import paginationHandler from './pagination-handler';
import sizePerPageDropdownAdapter from './size-per-page-dropdown-adapter';
const SizePerPageDropdownStandalone = props => (
<SizePerPageDropdown { ...props } />
);
export default
standaloneAdapter(paginationHandler(sizePerPageDropdownAdapter(SizePerPageDropdownStandalone)));

View File

@@ -16,7 +16,6 @@ const SizePerPageDropDown = (props) => {
className,
variation,
btnContextual,
optionRenderer,
currSizePerPage,
onSizePerPageChange
} = props;
@@ -62,22 +61,14 @@ const SizePerPageDropDown = (props) => {
aria-labelledby="pageDropDown"
>
{
options.map((option) => {
if (optionRenderer) {
return optionRenderer({
...option,
onSizePerPageChange
});
}
return (
<SizePerPageOption
{ ...option }
key={ option.text }
bootstrap4={ bootstrap4 }
onSizePerPageChange={ onSizePerPageChange }
/>
);
})
options.map(option => (
<SizePerPageOption
{ ...option }
key={ option.text }
bootstrap4={ bootstrap4 }
onSizePerPageChange={ onSizePerPageChange }
/>
))
}
</ul>
</span>
@@ -97,16 +88,14 @@ SizePerPageDropDown.propTypes = {
hidden: PropTypes.bool,
btnContextual: PropTypes.string,
variation: PropTypes.oneOf(['dropdown', 'dropup']),
className: PropTypes.string,
optionRenderer: PropTypes.func
className: PropTypes.string
};
SizePerPageDropDown.defaultProps = {
open: false,
hidden: false,
btnContextual: 'btn-default btn-secondary',
variation: 'dropdown',
className: '',
optionRenderer: null
className: ''
};

View File

@@ -1,14 +0,0 @@
/* eslint react/prop-types: 0 */
import React from 'react';
export default WrappedComponent => ({
page,
sizePerPage,
...rest
}) => (
<WrappedComponent
{ ...rest }
currPage={ page }
currSizePerPage={ sizePerPage }
/>
);

View File

@@ -1,169 +0,0 @@
/* eslint react/prop-types: 0 */
/* eslint react/require-default-props: 0 */
/* eslint no-lonely-if: 0 */
import React from 'react';
import Const from './const';
const StateContext = React.createContext();
class StateProvider extends React.Component {
constructor(props) {
super(props);
this.handleChangePage = this.handleChangePage.bind(this);
this.handleChangeSizePerPage = this.handleChangeSizePerPage.bind(this);
let currPage;
let currSizePerPage;
const { options } = props.pagination;
const sizePerPageList = options.sizePerPageList || Const.SIZE_PER_PAGE_LIST;
// initialize current page
if (typeof options.page !== 'undefined') {
currPage = options.page;
} else if (typeof options.pageStartIndex !== 'undefined') {
currPage = options.pageStartIndex;
} else {
currPage = Const.PAGE_START_INDEX;
}
// initialize current sizePerPage
if (typeof options.sizePerPage !== 'undefined') {
currSizePerPage = options.sizePerPage;
} else if (typeof sizePerPageList[0] === 'object') {
currSizePerPage = sizePerPageList[0].value;
} else {
currSizePerPage = sizePerPageList[0];
}
this.currPage = currPage;
this.currSizePerPage = currSizePerPage;
}
componentWillReceiveProps(nextProps) {
const { custom } = nextProps.pagination.options;
// user should align the page when the page is not fit to the data size when remote enable
if (this.isRemotePagination() || custom) {
this.currPage = nextProps.pagination.options.page;
this.currSizePerPage = nextProps.pagination.options.sizePerPage;
}
}
getPaginationProps = () => {
const { pagination: { options }, bootstrap4 } = this.props;
const { currPage, currSizePerPage } = this;
const withFirstAndLast = typeof options.withFirstAndLast === 'undefined' ?
Const.With_FIRST_AND_LAST : options.withFirstAndLast;
const alwaysShowAllBtns = typeof options.alwaysShowAllBtns === 'undefined' ?
Const.SHOW_ALL_PAGE_BTNS : options.alwaysShowAllBtns;
const hideSizePerPage = typeof options.hideSizePerPage === 'undefined' ?
Const.HIDE_SIZE_PER_PAGE : options.hideSizePerPage;
const hidePageListOnlyOnePage = typeof options.hidePageListOnlyOnePage === 'undefined' ?
Const.HIDE_PAGE_LIST_ONLY_ONE_PAGE : options.hidePageListOnlyOnePage;
const pageStartIndex = typeof options.pageStartIndex === 'undefined' ?
Const.PAGE_START_INDEX : options.pageStartIndex;
return {
...options,
bootstrap4,
page: currPage,
sizePerPage: currSizePerPage,
pageStartIndex,
hidePageListOnlyOnePage,
hideSizePerPage,
alwaysShowAllBtns,
withFirstAndLast,
dataSize: options.totalSize,
sizePerPageList: options.sizePerPageList || Const.SIZE_PER_PAGE_LIST,
paginationSize: options.paginationSize || Const.PAGINATION_SIZE,
showTotal: options.showTotal,
pageListRenderer: options.pageListRenderer,
pageButtonRenderer: options.pageButtonRenderer,
sizePerPageRenderer: options.sizePerPageRenderer,
paginationTotalRenderer: options.paginationTotalRenderer,
sizePerPageOptionRenderer: options.sizePerPageOptionRenderer,
firstPageText: options.firstPageText || Const.FIRST_PAGE_TEXT,
prePageText: options.prePageText || Const.PRE_PAGE_TEXT,
nextPageText: options.nextPageText || Const.NEXT_PAGE_TEXT,
lastPageText: options.lastPageText || Const.LAST_PAGE_TEXT,
prePageTitle: options.prePageTitle || Const.PRE_PAGE_TITLE,
nextPageTitle: options.nextPageTitle || Const.NEXT_PAGE_TITLE,
firstPageTitle: options.firstPageTitle || Const.FIRST_PAGE_TITLE,
lastPageTitle: options.lastPageTitle || Const.LAST_PAGE_TITLE,
onPageChange: this.handleChangePage,
onSizePerPageChange: this.handleChangeSizePerPage
};
}
setPaginationRemoteEmitter = (remoteEmitter) => {
this.remoteEmitter = remoteEmitter;
}
getPaginationRemoteEmitter = () => this.remoteEmitter || this.props.remoteEmitter;
isRemotePagination = () => {
const e = {};
this.remoteEmitter.emit('isRemotePagination', e);
return e.result;
};
handleChangePage(currPage) {
const { currSizePerPage } = this;
const { pagination: { options } } = this.props;
if (options.onPageChange) {
options.onPageChange(currPage, currSizePerPage);
}
this.currPage = currPage;
if (this.isRemotePagination()) {
this.getPaginationRemoteEmitter().emit('paginationChange', currPage, currSizePerPage);
return;
}
this.forceUpdate();
}
handleChangeSizePerPage(currSizePerPage, currPage) {
const { pagination: { options } } = this.props;
if (options.onSizePerPageChange) {
options.onSizePerPageChange(currSizePerPage, currPage);
}
this.currPage = currPage;
this.currSizePerPage = currSizePerPage;
if (this.isRemotePagination()) {
this.getPaginationRemoteEmitter().emit('paginationChange', currPage, currSizePerPage);
return;
}
this.forceUpdate();
}
render() {
const paginationProps = this.getPaginationProps();
const pagination = {
...this.props.pagination,
options: paginationProps
};
return (
<StateContext.Provider
value={ {
paginationProps,
paginationTableProps: {
pagination,
setPaginationRemoteEmitter: this.setPaginationRemoteEmitter
}
} }
>
{ this.props.children }
</StateContext.Provider>
);
}
}
export default () => ({
Provider: StateProvider,
Consumer: StateContext.Consumer
});

View File

@@ -0,0 +1,711 @@
import 'jsdom-global/register';
import React from 'react';
import { shallow } from 'enzyme';
import BootstrapTable from 'react-bootstrap-table-next/src/bootstrap-table';
import Pagination from '../src/pagination';
import Const from '../src/const';
import createPaginationContext from '../src/context';
import paginationFactory from '../index';
const data = [];
for (let i = 0; i < 100; i += 1) {
data.push({
id: i,
name: `itme name ${i}`
});
}
describe('PaginationContext', () => {
let wrapper;
let PaginationContext;
const columns = [{
dataField: 'id',
text: 'ID'
}, {
dataField: 'name',
text: 'Name'
}];
const defaultPagination = { options: {} };
const mockBase = jest.fn((props => (
<BootstrapTable
keyField="id"
data={ data }
columns={ columns }
{ ...props }
/>
)));
const handleRemotePaginationChange = jest.fn();
function shallowContext(
customPagination = defaultPagination,
enableRemote = false
) {
mockBase.mockReset();
handleRemotePaginationChange.mockReset();
PaginationContext = createPaginationContext(
jest.fn().mockReturnValue(enableRemote),
handleRemotePaginationChange
);
return (
<PaginationContext.Provider
pagination={ paginationFactory(customPagination) }
columns={ columns }
data={ data }
>
<PaginationContext.Consumer>
{
paginationProps => mockBase(paginationProps)
}
</PaginationContext.Consumer>
</PaginationContext.Provider>
);
}
describe('default render', () => {
beforeEach(() => {
wrapper = shallow(shallowContext());
wrapper.render();
});
it('should have correct Provider property after calling createPaginationContext', () => {
expect(PaginationContext.Provider).toBeDefined();
});
it('should have correct Consumer property after calling createPaginationContext', () => {
expect(PaginationContext.Consumer).toBeDefined();
});
it('should have correct currPage', () => {
expect(wrapper.instance().currPage).toEqual(Const.PAGE_START_INDEX);
});
it('should have correct currSizePerPage', () => {
expect(wrapper.instance().currSizePerPage).toEqual(Const.SIZE_PER_PAGE_LIST[0]);
});
it('should render Pagination component correctly', () => {
expect(wrapper.length).toBe(1);
const instance = wrapper.instance();
const pagination = wrapper.find(Pagination);
expect(pagination).toHaveLength(1);
expect(pagination.prop('dataSize')).toEqual(data.length);
expect(pagination.prop('currPage')).toEqual(instance.currPage);
expect(pagination.prop('currSizePerPage')).toEqual(instance.currSizePerPage);
expect(pagination.prop('onPageChange')).toEqual(instance.handleChangePage);
expect(pagination.prop('onSizePerPageChange')).toEqual(instance.handleChangeSizePerPage);
expect(pagination.prop('sizePerPageList')).toEqual(Const.SIZE_PER_PAGE_LIST);
expect(pagination.prop('paginationSize')).toEqual(Const.PAGINATION_SIZE);
expect(pagination.prop('pageStartIndex')).toEqual(Const.PAGE_START_INDEX);
expect(pagination.prop('withFirstAndLast')).toEqual(Const.With_FIRST_AND_LAST);
expect(pagination.prop('alwaysShowAllBtns')).toEqual(Const.SHOW_ALL_PAGE_BTNS);
expect(pagination.prop('firstPageText')).toEqual(Const.FIRST_PAGE_TEXT);
expect(pagination.prop('prePageText')).toEqual(Const.PRE_PAGE_TEXT);
expect(pagination.prop('nextPageText')).toEqual(Const.NEXT_PAGE_TEXT);
expect(pagination.prop('lastPageText')).toEqual(Const.LAST_PAGE_TEXT);
expect(pagination.prop('firstPageTitle')).toEqual(Const.FIRST_PAGE_TITLE);
expect(pagination.prop('prePageTitle')).toEqual(Const.PRE_PAGE_TITLE);
expect(pagination.prop('nextPageTitle')).toEqual(Const.NEXT_PAGE_TITLE);
expect(pagination.prop('lastPageTitle')).toEqual(Const.LAST_PAGE_TITLE);
expect(pagination.prop('hideSizePerPage')).toEqual(Const.HIDE_SIZE_PER_PAGE);
expect(pagination.prop('hideSizePerPage')).toEqual(Const.HIDE_SIZE_PER_PAGE);
expect(pagination.prop('paginationTotalRenderer')).toBeNull();
});
it('should pass correct cell editing props to children element', () => {
expect(mockBase.mock.calls[0][0].data).toHaveLength(Const.SIZE_PER_PAGE_LIST[0]);
});
});
describe('componentWillReceiveProps', () => {
let instance;
let nextProps;
describe('when nextProps.pagination.options.page is not existing', () => {
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
page: 3
}));
instance = wrapper.instance();
wrapper.render();
nextProps = { data, pagination: defaultPagination };
instance.componentWillReceiveProps(nextProps);
});
it('should not set currPage', () => {
expect(instance.currPage).toEqual(3);
});
});
describe('when nextProps.pagination.options.sizePerPage is not existing', () => {
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
sizePerPage: Const.SIZE_PER_PAGE_LIST[2]
}));
instance = wrapper.instance();
wrapper.render();
nextProps = { data, pagination: defaultPagination };
instance.componentWillReceiveProps(nextProps);
});
it('should not set currSizePerPage', () => {
expect(instance.currSizePerPage).toEqual(Const.SIZE_PER_PAGE_LIST[2]);
});
});
describe('when remote pagination is enable', () => {
beforeEach(() => {
wrapper = shallow(shallowContext({ ...defaultPagination }, true));
instance = wrapper.instance();
wrapper.render();
nextProps = {
data,
pagination: { ...defaultPagination, options: { page: 3, sizePerPage: 5 } }
};
instance.componentWillReceiveProps(nextProps);
});
it('should always set currPage from nextProps.pagination.options.page', () => {
expect(instance.currPage).toEqual(nextProps.pagination.options.page);
});
it('should always set currSizePerPage from nextProps.pagination.options.sizePerPage', () => {
expect(instance.currSizePerPage).toEqual(nextProps.pagination.options.sizePerPage);
});
});
describe('when page is not align', () => {
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
page: 2
}));
instance = wrapper.instance();
wrapper.render();
nextProps = {
data: [],
pagination: { ...defaultPagination }
};
instance.componentWillReceiveProps(nextProps);
});
it('should reset currPage to first page', () => {
expect(instance.currPage).toEqual(1);
});
describe('if options.onPageChange is defined', () => {
const onPageChange = jest.fn();
beforeEach(() => {
onPageChange.mockClear();
wrapper = shallow(shallowContext({
...defaultPagination,
page: 2
}));
instance = wrapper.instance();
wrapper.render();
nextProps = {
data: [],
pagination: { ...defaultPagination, options: { onPageChange } }
};
instance.componentWillReceiveProps(nextProps);
});
it('should call options.onPageChange correctly', () => {
expect(onPageChange).toHaveBeenCalledTimes(1);
expect(onPageChange).toHaveBeenCalledWith(instance.currPage, instance.currSizePerPage);
});
});
});
});
describe('handleChangePage', () => {
let instance;
const newPage = 3;
describe('should update component correctly', () => {
beforeEach(() => {
wrapper = shallow(shallowContext());
instance = wrapper.instance();
jest.spyOn(instance, 'forceUpdate');
instance.handleChangePage(newPage);
});
it('', () => {
expect(instance.currPage).toEqual(newPage);
expect(instance.forceUpdate).toHaveBeenCalledTimes(1);
});
});
describe('if options.onPageChange is defined', () => {
const onPageChange = jest.fn();
beforeEach(() => {
onPageChange.mockClear();
wrapper = shallow(shallowContext({
...defaultPagination,
onPageChange
}));
instance = wrapper.instance();
jest.spyOn(instance, 'forceUpdate');
instance.handleChangePage(newPage);
});
it('should still update component correctly', () => {
expect(instance.currPage).toEqual(newPage);
expect(instance.forceUpdate).toHaveBeenCalledTimes(1);
});
it('should call options.onPageChange correctly', () => {
expect(onPageChange).toHaveBeenCalledTimes(1);
expect(onPageChange).toHaveBeenCalledWith(newPage, instance.currSizePerPage);
});
});
describe('if remote pagination is enable', () => {
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination
}, true));
instance = wrapper.instance();
jest.spyOn(instance, 'forceUpdate');
instance.handleChangePage(newPage);
});
it('should still update component correctly', () => {
expect(instance.currPage).toEqual(newPage);
expect(instance.forceUpdate).toHaveBeenCalledTimes(0);
});
it('should call handleRemotePageChange correctly', () => {
expect(handleRemotePaginationChange).toHaveBeenCalledTimes(1);
expect(handleRemotePaginationChange)
.toHaveBeenCalledWith(newPage, instance.currSizePerPage);
});
});
});
describe('handleChangeSizePerPage', () => {
let instance;
const newPage = 2;
const newSizePerPage = 15;
describe('should update component correctly', () => {
beforeEach(() => {
wrapper = shallow(shallowContext());
instance = wrapper.instance();
jest.spyOn(instance, 'forceUpdate');
instance.handleChangeSizePerPage(newSizePerPage, newPage);
});
it('', () => {
expect(instance.currPage).toEqual(newPage);
expect(instance.currSizePerPage).toEqual(newSizePerPage);
expect(instance.forceUpdate).toHaveBeenCalledTimes(1);
});
});
describe('if options.onSizePerPageChange is defined', () => {
const onSizePerPageChange = jest.fn();
beforeEach(() => {
onSizePerPageChange.mockClear();
wrapper = shallow(shallowContext({
...defaultPagination,
onSizePerPageChange
}));
instance = wrapper.instance();
jest.spyOn(instance, 'forceUpdate');
instance.handleChangeSizePerPage(newSizePerPage, newPage);
});
it('should still update component correctly', () => {
expect(instance.currPage).toEqual(newPage);
expect(instance.currSizePerPage).toEqual(newSizePerPage);
expect(instance.forceUpdate).toHaveBeenCalledTimes(1);
});
it('should call options.onSizePerPageChange correctly', () => {
expect(onSizePerPageChange).toHaveBeenCalledTimes(1);
expect(onSizePerPageChange).toHaveBeenCalledWith(newSizePerPage, newPage);
});
});
describe('if remote pagination is enable', () => {
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination
}, true));
instance = wrapper.instance();
jest.spyOn(instance, 'forceUpdate');
instance.handleChangeSizePerPage(newSizePerPage, newPage);
});
it('should still update component correctly', () => {
expect(instance.currPage).toEqual(newPage);
expect(instance.currSizePerPage).toEqual(newSizePerPage);
expect(instance.forceUpdate).toHaveBeenCalledTimes(0);
});
it('should call handleRemotePageChange correctly', () => {
expect(handleRemotePaginationChange).toHaveBeenCalledTimes(1);
expect(handleRemotePaginationChange)
.toHaveBeenCalledWith(newPage, newSizePerPage);
});
});
});
describe('when options.page is defined', () => {
const page = 3;
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
page
}));
wrapper.render();
});
it('should set correct currPage', () => {
expect(wrapper.instance().currPage).toEqual(page);
});
it('should rendering Pagination correctly', () => {
const pagination = wrapper.find(Pagination);
expect(pagination.length).toBe(1);
expect(pagination.prop('currPage')).toEqual(page);
});
});
describe('when options.sizePerPage is defined', () => {
const sizePerPage = Const.SIZE_PER_PAGE_LIST[2];
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
sizePerPage
}));
wrapper.render();
});
it('should set correct currSizePerPage', () => {
expect(wrapper.instance().currSizePerPage).toEqual(sizePerPage);
});
it('should rendering Pagination correctly', () => {
const pagination = wrapper.find(Pagination);
expect(pagination.length).toBe(1);
expect(pagination.prop('currSizePerPage')).toEqual(sizePerPage);
});
});
describe('when options.totalSize is defined', () => {
const totalSize = 100;
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
totalSize
}));
wrapper.render();
});
it('should rendering Pagination correctly', () => {
const pagination = wrapper.find(Pagination);
expect(pagination.length).toBe(1);
expect(pagination.prop('dataSize')).toEqual(totalSize);
});
});
describe('when options.showTotal is defined', () => {
const showTotal = true;
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
showTotal
}));
wrapper.render();
});
it('should rendering Pagination correctly', () => {
const pagination = wrapper.find(Pagination);
expect(pagination.length).toBe(1);
expect(pagination.prop('showTotal')).toEqual(showTotal);
});
});
describe('when options.pageStartIndex is defined', () => {
const pageStartIndex = -1;
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
pageStartIndex
}));
wrapper.render();
});
it('should rendering Pagination correctly', () => {
const pagination = wrapper.find(Pagination);
expect(pagination.length).toBe(1);
expect(pagination.prop('pageStartIndex')).toEqual(pageStartIndex);
});
});
describe('when options.sizePerPageList is defined', () => {
const sizePerPageList = [10, 40];
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
sizePerPageList
}));
wrapper.render();
});
it('should rendering Pagination correctly', () => {
const pagination = wrapper.find(Pagination);
expect(pagination.length).toBe(1);
expect(pagination.prop('sizePerPageList')).toEqual(sizePerPageList);
});
});
describe('when options.paginationSize is defined', () => {
const paginationSize = 10;
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
paginationSize
}));
wrapper.render();
});
it('should rendering Pagination correctly', () => {
const pagination = wrapper.find(Pagination);
expect(pagination.length).toBe(1);
expect(pagination.prop('paginationSize')).toEqual(paginationSize);
});
});
describe('when options.withFirstAndLast is defined', () => {
const withFirstAndLast = false;
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
withFirstAndLast
}));
wrapper.render();
});
it('should rendering Pagination correctly', () => {
const pagination = wrapper.find(Pagination);
expect(pagination.length).toBe(1);
expect(pagination.prop('withFirstAndLast')).toEqual(withFirstAndLast);
});
});
describe('when options.alwaysShowAllBtns is defined', () => {
const alwaysShowAllBtns = true;
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
alwaysShowAllBtns
}));
wrapper.render();
});
it('should rendering Pagination correctly', () => {
const pagination = wrapper.find(Pagination);
expect(pagination.length).toBe(1);
expect(pagination.prop('alwaysShowAllBtns')).toEqual(alwaysShowAllBtns);
});
});
describe('when options.firstPageText is defined', () => {
const firstPageText = '1st';
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
firstPageText
}));
wrapper.render();
});
it('should rendering Pagination correctly', () => {
const pagination = wrapper.find(Pagination);
expect(pagination.length).toBe(1);
expect(pagination.prop('firstPageText')).toEqual(firstPageText);
});
});
describe('when options.prePageText is defined', () => {
const prePageText = 'PRE';
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
prePageText
}));
wrapper.render();
});
it('should rendering Pagination correctly', () => {
const pagination = wrapper.find(Pagination);
expect(pagination.length).toBe(1);
expect(pagination.prop('prePageText')).toEqual(prePageText);
});
});
describe('when options.nextPageText is defined', () => {
const nextPageText = 'NEXT';
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
nextPageText
}));
wrapper.render();
});
it('should rendering Pagination correctly', () => {
const pagination = wrapper.find(Pagination);
expect(pagination.length).toBe(1);
expect(pagination.prop('nextPageText')).toEqual(nextPageText);
});
});
describe('when options.lastPageText is defined', () => {
const lastPageText = 'LAST';
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
lastPageText
}));
wrapper.render();
});
it('should rendering Pagination correctly', () => {
const pagination = wrapper.find(Pagination);
expect(pagination.length).toBe(1);
expect(pagination.prop('lastPageText')).toEqual(lastPageText);
});
});
describe('when options.firstPageTitle is defined', () => {
const firstPageTitle = '1st';
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
firstPageTitle
}));
wrapper.render();
});
it('should rendering Pagination correctly', () => {
const pagination = wrapper.find(Pagination);
expect(pagination.length).toBe(1);
expect(pagination.prop('firstPageTitle')).toEqual(firstPageTitle);
});
});
describe('when options.prePageTitle is defined', () => {
const prePageTitle = 'PRE';
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
prePageTitle
}));
wrapper.render();
});
it('should rendering Pagination correctly', () => {
const pagination = wrapper.find(Pagination);
expect(pagination.length).toBe(1);
expect(pagination.prop('prePageTitle')).toEqual(prePageTitle);
});
});
describe('when options.nextPageTitle is defined', () => {
const nextPageTitle = 'NEXT';
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
nextPageTitle
}));
wrapper.render();
});
it('should rendering Pagination correctly', () => {
const pagination = wrapper.find(Pagination);
expect(pagination.length).toBe(1);
expect(pagination.prop('nextPageTitle')).toEqual(nextPageTitle);
});
});
describe('when options.lastPageTitle is defined', () => {
const lastPageTitle = 'nth';
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
lastPageTitle
}));
wrapper.render();
});
it('should rendering Pagination correctly', () => {
const pagination = wrapper.find(Pagination);
expect(pagination.length).toBe(1);
expect(pagination.prop('lastPageTitle')).toEqual(lastPageTitle);
});
});
describe('when options.hideSizePerPage is defined', () => {
const hideSizePerPage = true;
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
hideSizePerPage
}));
wrapper.render();
});
it('should rendering Pagination correctly', () => {
const pagination = wrapper.find(Pagination);
expect(pagination.length).toBe(1);
expect(pagination.prop('hideSizePerPage')).toEqual(hideSizePerPage);
});
});
describe('when options.hidePageListOnlyOnePage is defined', () => {
const hidePageListOnlyOnePage = true;
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
hidePageListOnlyOnePage
}));
wrapper.render();
});
it('should rendering Pagination correctly', () => {
const pagination = wrapper.find(Pagination);
expect(pagination.length).toBe(1);
expect(pagination.prop('hidePageListOnlyOnePage')).toEqual(hidePageListOnlyOnePage);
});
});
});

View File

@@ -1,208 +0,0 @@
import 'jsdom-global/register';
import React from 'react';
import { shallow } from 'enzyme';
import paginationFactory from '../index';
import Const from '../src/const';
import createStateContext from '../src/data-context';
import Pagination from '../src/pagination';
import { getByCurrPage } from '../src/page';
const data = [];
for (let i = 0; i < 100; i += 1) {
data.push({
id: i,
name: `itme name ${i}`
});
}
describe('PaginationDataContext', () => {
let wrapper;
let PaginationDataContext;
const defaultPagination = { options: { totalSize: data.length }, createContext: jest.fn() };
const MockComponent = () => null;
const renderMockComponent = jest.fn((props => (
<MockComponent { ...props } />
)));
const handleRemotePaginationChange = jest.fn();
function shallowContext(
customPagination = defaultPagination,
remoteEnabled = false
) {
renderMockComponent.mockReset();
handleRemotePaginationChange.mockReset();
PaginationDataContext = createStateContext();
const isRemotePagination = jest.fn().mockReturnValue(remoteEnabled);
const remoteEmitter = { emit: jest.fn() };
return (
<PaginationDataContext.Provider
pagination={ paginationFactory(customPagination) }
data={ data }
remoteEmitter={ remoteEmitter }
isRemotePagination={ isRemotePagination }
>
<PaginationDataContext.Consumer>
{
paginationProps => renderMockComponent(paginationProps)
}
</PaginationDataContext.Consumer>
</PaginationDataContext.Provider>
);
}
describe('default render', () => {
beforeEach(() => {
wrapper = shallow(shallowContext());
wrapper.render();
});
it('should have correct Provider property after calling createPaginationDataContext', () => {
expect(PaginationDataContext.Provider).toBeDefined();
});
it('should have correct Consumer property after calling createPaginationDataContext', () => {
expect(PaginationDataContext.Consumer).toBeDefined();
});
it('should have correct currPage', () => {
expect(wrapper.instance().currPage).toEqual(Const.PAGE_START_INDEX);
});
it('should have correct currSizePerPage', () => {
expect(wrapper.instance().currSizePerPage).toEqual(Const.SIZE_PER_PAGE_LIST[0]);
});
it('should render correct data props to childrens', () => {
const instance = wrapper.instance();
expect(renderMockComponent).toHaveBeenCalledTimes(1);
expect(renderMockComponent).toHaveBeenCalledWith({
data: getByCurrPage(
data,
instance.currPage,
instance.currSizePerPage,
Const.PAGE_START_INDEX
),
setRemoteEmitter: instance.setRemoteEmitter
});
});
});
describe('default render', () => {
describe('when options.custom is negative', () => {
beforeEach(() => {
wrapper = shallow(shallowContext());
wrapper.render();
});
it('should render Pagination component correctly', () => {
const instance = wrapper.instance();
const pagination = wrapper.find(Pagination);
expect(pagination).toHaveLength(1);
expect(pagination.prop('dataSize')).toEqual(data.length);
expect(pagination.prop('currPage')).toEqual(instance.currPage);
expect(pagination.prop('currSizePerPage')).toEqual(instance.currSizePerPage);
expect(pagination.prop('onPageChange')).toEqual(instance.handleChangePage);
expect(pagination.prop('onSizePerPageChange')).toEqual(instance.handleChangeSizePerPage);
expect(pagination.prop('sizePerPageList')).toEqual(Const.SIZE_PER_PAGE_LIST);
expect(pagination.prop('paginationSize')).toEqual(Const.PAGINATION_SIZE);
expect(pagination.prop('pageStartIndex')).toEqual(Const.PAGE_START_INDEX);
expect(pagination.prop('withFirstAndLast')).toEqual(Const.With_FIRST_AND_LAST);
expect(pagination.prop('alwaysShowAllBtns')).toEqual(Const.SHOW_ALL_PAGE_BTNS);
expect(pagination.prop('firstPageText')).toEqual(Const.FIRST_PAGE_TEXT);
expect(pagination.prop('prePageText')).toEqual(Const.PRE_PAGE_TEXT);
expect(pagination.prop('nextPageText')).toEqual(Const.NEXT_PAGE_TEXT);
expect(pagination.prop('lastPageText')).toEqual(Const.LAST_PAGE_TEXT);
expect(pagination.prop('firstPageTitle')).toEqual(Const.FIRST_PAGE_TITLE);
expect(pagination.prop('prePageTitle')).toEqual(Const.PRE_PAGE_TITLE);
expect(pagination.prop('nextPageTitle')).toEqual(Const.NEXT_PAGE_TITLE);
expect(pagination.prop('lastPageTitle')).toEqual(Const.LAST_PAGE_TITLE);
expect(pagination.prop('hideSizePerPage')).toEqual(Const.HIDE_SIZE_PER_PAGE);
expect(pagination.prop('hideSizePerPage')).toEqual(Const.HIDE_SIZE_PER_PAGE);
expect(pagination.prop('paginationTotalRenderer')).toBeUndefined();
});
});
describe('when options.custom is positive', () => {
beforeEach(() => {
wrapper = shallow(shallowContext({
custom: true
}));
wrapper.render();
});
it('should not render Pagination component', () => {
const pagination = wrapper.find(Pagination);
expect(pagination).toHaveLength(0);
});
});
});
describe('when remote pagination enabled', () => {
beforeEach(() => {
wrapper = shallow(shallowContext({}, true));
wrapper.render();
});
it('just pass data props to children', () => {
const instance = wrapper.instance();
expect(renderMockComponent).toHaveBeenCalledTimes(1);
expect(renderMockComponent).toHaveBeenCalledWith({
data: instance.props.data,
setRemoteEmitter: instance.setRemoteEmitter
});
});
});
describe('componentWillReceiveProps', () => {
let instance;
let nextProps;
describe('when page is not align', () => {
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
page: 2
}));
instance = wrapper.instance();
wrapper.render();
nextProps = {
data: [],
pagination: { ...defaultPagination }
};
instance.componentWillReceiveProps(nextProps);
});
it('should reset currPage to first page', () => {
expect(instance.currPage).toEqual(1);
});
describe('if options.onPageChange is defined', () => {
const onPageChange = jest.fn();
beforeEach(() => {
onPageChange.mockClear();
wrapper = shallow(shallowContext({
...defaultPagination,
page: 2
}));
instance = wrapper.instance();
wrapper.render();
nextProps = {
data: [],
pagination: { ...defaultPagination, options: { onPageChange } }
};
instance.componentWillReceiveProps(nextProps);
});
it('should call options.onPageChange correctly', () => {
expect(onPageChange).toHaveBeenCalledTimes(1);
expect(onPageChange).toHaveBeenCalledWith(instance.currPage, instance.currSizePerPage);
});
});
});
});
});

View File

@@ -46,6 +46,8 @@ describe('PageResolver', () => {
expect(instance.state.lastPage).toBeDefined();
expect(instance.state.lastPage).toEqual(
instance.calculateLastPage(instance.state.totalPages));
expect(instance.state.dropdownOpen).toBeDefined();
expect(instance.state.dropdownOpen).toBeFalsy();
});
});
@@ -79,6 +81,35 @@ describe('PageResolver', () => {
});
});
describe('goToNextPage', () => {
const props = createMockProps();
describe('when props.currPage is not hitting state.lastPage', () => {
beforeEach(() => {
const mockElement = React.createElement(MockComponent, props, null);
wrapper = shallow(mockElement);
});
it('should getting previous page correctly', () => {
const instance = wrapper.instance();
expect(instance.goToNextPage()).toEqual(props.currPage + 1);
});
});
describe('when props.currPage is hitting state.lastpage', () => {
beforeEach(() => {
props.currPage = 10;
const mockElement = React.createElement(MockComponent, props, null);
wrapper = shallow(mockElement);
});
it('should always getting page which must eq props.pageStartIndex', () => {
const instance = wrapper.instance();
expect(instance.goToNextPage()).toEqual(instance.state.lastPage);
});
});
});
describe('calculateFromTo', () => {
const props = createMockProps();
beforeEach(() => {
@@ -161,7 +192,7 @@ describe('PageResolver', () => {
});
describe('calculatePages', () => {
describe('calculate by totalPages and lastPage', () => {
describe('calculate by state.totalPages and state.lastPage', () => {
const props = createMockProps();
beforeEach(() => {
const mockElement = React.createElement(MockComponent, props, null);
@@ -170,7 +201,7 @@ describe('PageResolver', () => {
it('should getting pages list correctly', () => {
const instance = wrapper.instance();
expect(instance.calculatePages(instance.state.totalPages, instance.state.lastPage)).toEqual(
expect(instance.calculatePages()).toEqual(
[props.prePageText, 1, 2, 3, 4, 5, props.nextPageText, props.lastPageText]);
expect(instance.calculatePages(4, 4)).toEqual(
@@ -187,9 +218,7 @@ describe('PageResolver', () => {
currPages.forEach((currPage) => {
props.currPage = currPage + 1;
wrapper = shallow(<MockComponent { ...props } />);
const instance = wrapper.instance();
const pageList = instance.calculatePages(
instance.state.totalPages, instance.state.lastPage);
const pageList = wrapper.instance().calculatePages();
if (props.currPage < 4) {
expect(pageList).toEqual(
@@ -224,9 +253,7 @@ describe('PageResolver', () => {
[1, 3, 5, 8, 10].forEach((paginationSize) => {
props.paginationSize = paginationSize;
wrapper = shallow(<MockComponent { ...props } />);
const instance = wrapper.instance();
const pageList = instance.calculatePages(
instance.state.totalPages, instance.state.lastPage);
const pageList = wrapper.instance().calculatePages();
const result = pageList.filter(p => indicators.indexOf(p) === -1);
expect(result.length).toEqual(props.paginationSize);
});
@@ -240,9 +267,7 @@ describe('PageResolver', () => {
[1, 2, 3, 4, 5, 6, 7].forEach((currPage) => {
props.currPage = currPage;
wrapper = shallow(<MockComponent { ...props } />);
const instance = wrapper.instance();
const pageList = instance.calculatePages(
instance.state.totalPages, instance.state.lastPage);
const pageList = wrapper.instance().calculatePages();
expect(pageList.indexOf(props.lastPageText) > -1).toBeTruthy();
});
});
@@ -253,9 +278,7 @@ describe('PageResolver', () => {
[10, 9, 8, 7, 6, 5, 4].forEach((currPage) => {
props.currPage = currPage;
wrapper = shallow(<MockComponent { ...props } />);
const instance = wrapper.instance();
const pageList = instance.calculatePages(
instance.state.totalPages, instance.state.lastPage);
const pageList = wrapper.instance().calculatePages();
expect(pageList.indexOf(props.firstPageText) > -1).toBeTruthy();
});
});
@@ -270,9 +293,7 @@ describe('PageResolver', () => {
props.currPage = currPage + 1;
props.withFirstAndLast = false;
wrapper = shallow(<MockComponent { ...props } />);
const instance = wrapper.instance();
const pageList = instance.calculatePages(
instance.state.totalPages, instance.state.lastPage);
const pageList = wrapper.instance().calculatePages();
expect(pageList.indexOf(props.lastPageText) > -1).toBeFalsy();
expect(pageList.indexOf(props.firstPageText) > -1).toBeFalsy();
});
@@ -290,9 +311,7 @@ describe('PageResolver', () => {
});
it('should getting last page correctly', () => {
const instance = wrapper.instance();
const pageList = instance.calculatePages(
instance.state.totalPages, instance.state.lastPage);
const pageList = wrapper.instance().calculatePages();
expect(pageList).toEqual(
[props.prePageText, -2, -1, 0, 1, 2, props.nextPageText, props.lastPageText]);
});
@@ -310,9 +329,7 @@ describe('PageResolver', () => {
});
it('should always having next and previous page indication', () => {
const instance = wrapper.instance();
const pageList = instance.calculatePages(
instance.state.totalPages, instance.state.lastPage);
const pageList = wrapper.instance().calculatePages();
expect(pageList.indexOf(props.nextPageText) > -1).toBeTruthy();
expect(pageList.indexOf(props.prePageText) > -1).toBeTruthy();
});
@@ -328,10 +345,7 @@ describe('PageResolver', () => {
});
it('should getting empty array', () => {
const instance = wrapper.instance();
const pageList = instance.calculatePages(
instance.state.totalPages, instance.state.lastPage);
expect(pageList).toEqual([]);
expect(wrapper.instance().calculatePages()).toEqual([]);
});
});
});
@@ -346,9 +360,7 @@ describe('PageResolver', () => {
const mockElement = React.createElement(MockComponent, props, null);
wrapper = shallow(mockElement);
instance = wrapper.instance();
const pageList = instance.calculatePages(
instance.state.totalPages, instance.state.lastPage);
pageStatus = instance.calculatePageStatus(pageList, instance.state.lastPage);
pageStatus = instance.calculatePageStatus(instance.calculatePages());
});
it('should returning correct format for page status', () => {
@@ -376,9 +388,8 @@ describe('PageResolver', () => {
const mockElement = React.createElement(MockComponent, props, null);
wrapper = shallow(mockElement);
instance = wrapper.instance();
const pageList = instance.calculatePages(
instance.state.totalPages, instance.state.lastPage);
pageStatus = instance.calculatePageStatus(pageList, instance.state.lastPage);
const pageList = instance.calculatePages();
pageStatus = instance.calculatePageStatus(pageList);
expect(pageStatus.find(p => p.page === props.prePageText)).not.toBeDefined();
});
@@ -390,9 +401,8 @@ describe('PageResolver', () => {
const mockElement = React.createElement(MockComponent, props, null);
wrapper = shallow(mockElement);
instance = wrapper.instance();
const pageList = instance.calculatePages(
instance.state.totalPages, instance.state.lastPage);
pageStatus = instance.calculatePageStatus(pageList, instance.state.lastPage);
const pageList = instance.calculatePages();
pageStatus = instance.calculatePageStatus(pageList);
expect(pageStatus.find(p => p.page === props.nextPageText)).not.toBeDefined();
});

View File

@@ -46,15 +46,29 @@ describe('Page Functions', () => {
const pageStartIndex = 1;
const sizePerPage = 10;
const page = 3;
describe('if the page does not fit the pages which calculated from the length of data', () => {
describe('if the page does not fit the pages interval calculated from the length of store.data', () => {
beforeEach(() => {
data = [];
for (let i = 0; i < 15; i += 1) {
data.push({ id: i, name: `test_name${i}` });
}
});
it('should return pageStartIndex argument', () => {
expect(alignPage(15, page, sizePerPage, pageStartIndex)).toEqual(pageStartIndex);
expect(alignPage(data, page, sizePerPage, pageStartIndex)).toEqual(pageStartIndex);
});
});
describe('if the length of store.data is large than the end page index', () => {
beforeEach(() => {
data = [];
for (let i = 0; i < 30; i += 1) {
data.push({ id: i, name: `test_name${i}` });
}
});
it('should return current page', () => {
expect(alignPage(30, page, sizePerPage, pageStartIndex)).toEqual(page);
expect(alignPage(data, page, sizePerPage, pageStartIndex)).toEqual(page);
});
});
});

View File

@@ -1,203 +0,0 @@
import React from 'react';
import sinon from 'sinon';
import { shallow } from 'enzyme';
import paginationHandler from '../src/pagination-handler';
const MockComponent = () => null;
const MockComponentWithPaginationHandler = paginationHandler(MockComponent);
describe('paginationHandler', () => {
let wrapper;
let instance;
const createMockProps = props => ({
dataSize: 100,
sizePerPageList: [10, 20, 30, 50],
currPage: 1,
currSizePerPage: 10,
pageStartIndex: 1,
paginationSize: 5,
withFirstAndLast: true,
firstPageText: '<<',
prePageText: '<',
nextPageText: '>',
lastPageText: '>>',
alwaysShowAllBtns: false,
onPageChange: sinon.stub(),
onSizePerPageChange: sinon.stub(),
hidePageListOnlyOnePage: false,
hideSizePerPage: false,
...props
});
describe('default pagiantion', () => {
const props = createMockProps();
beforeEach(() => {
wrapper = shallow(<MockComponentWithPaginationHandler { ...props } />);
instance = wrapper.instance();
});
it('should having correct state', () => {
expect(instance.state).toBeDefined();
expect(instance.state.totalPages).toEqual(instance.calculateTotalPage());
expect(instance.state.lastPage).toEqual(
instance.calculateLastPage(instance.state.totalPages));
});
it('should rendering PaginationList component successfully', () => {
const wrapperedComponent = wrapper.find(MockComponent);
expect(wrapperedComponent.length).toBe(1);
expect(wrapperedComponent.props().lastPage).toEqual(instance.state.lastPage);
expect(wrapperedComponent.props().totalPages).toEqual(instance.state.totalPages);
expect(wrapperedComponent.props().onPageChange).toEqual(instance.handleChangePage);
expect(wrapperedComponent.props().onSizePerPageChange)
.toEqual(instance.handleChangeSizePerPage);
});
});
describe('handleChangePage', () => {
const props = createMockProps();
beforeEach(() => {
props.currPage = 6;
wrapper = shallow(<MockComponentWithPaginationHandler { ...props } />);
instance = wrapper.instance();
});
afterEach(() => {
props.onPageChange.reset();
});
it('should calling props.onPageChange correctly when new page is eq props.prePageText', () => {
instance.handleChangePage(props.prePageText);
expect(props.onPageChange.callCount).toBe(1);
expect(props.onPageChange.calledWith(5)).toBeTruthy();
});
it('should calling props.onPageChange correctly when new page is eq props.nextPageText', () => {
instance.handleChangePage(props.nextPageText);
expect(props.onPageChange.callCount).toBe(1);
expect(props.onPageChange.calledWith(7)).toBeTruthy();
});
it('should calling props.onPageChange correctly when new page is eq props.lastPageText', () => {
instance.handleChangePage(props.lastPageText);
expect(props.onPageChange.callCount).toBe(1);
expect(props.onPageChange.calledWith(10)).toBeTruthy();
});
it('should calling props.onPageChange correctly when new page is eq props.firstPageText', () => {
instance.handleChangePage(props.firstPageText);
expect(props.onPageChange.callCount).toBe(1);
expect(props.onPageChange.calledWith(props.pageStartIndex)).toBeTruthy();
});
it('should calling props.onPageChange correctly when new page is a numeric page', () => {
const newPage = '8';
instance.handleChangePage(newPage);
expect(props.onPageChange.callCount).toBe(1);
expect(props.onPageChange.calledWith(parseInt(newPage, 10))).toBeTruthy();
});
it('should not calling props.onPageChange correctly when page is not changed', () => {
const newPage = props.currPage;
instance.handleChangePage(newPage);
expect(props.onPageChange.callCount).toBe(0);
});
});
describe('handleChangeSizePerPage', () => {
const props = createMockProps();
beforeEach(() => {
wrapper = shallow(<MockComponentWithPaginationHandler { ...props } />);
instance = wrapper.instance();
});
it('should always setting state.dropdownOpen to false', () => {
instance.handleChangeSizePerPage(10);
expect(instance.state.dropdownOpen).toBeFalsy();
});
describe('when new sizePerPage is same as current one', () => {
it('should not calling props.onSizePerPageChange callback', () => {
instance.handleChangeSizePerPage(10);
expect(props.onSizePerPageChange.callCount).toBe(0);
});
});
describe('when new sizePerPage is diff than current one', () => {
it('should not calling props.onSizePerPageChange callback', () => {
instance.handleChangeSizePerPage(30);
expect(props.onSizePerPageChange.callCount).toBe(1);
});
describe('and new current page is still in the new lagination list', () => {
it('should calling props.onSizePerPageChange with correct argument', () => {
expect(props.onSizePerPageChange.calledWith(30, props.currPage));
});
});
describe('and new current page is still in the new lagination list', () => {
beforeEach(() => {
wrapper = shallow(
<MockComponentWithPaginationHandler { ...createMockProps({ currPage: 10 }) } />);
instance = wrapper.instance();
});
it('should calling props.onSizePerPageChange with correct argument', () => {
expect(props.onSizePerPageChange.calledWith(30, 4));
});
});
});
});
describe('componentWillReceiveProps', () => {
describe('when next props.currSizePerPage is diff than current one', () => {
const nextProps = createMockProps({ currSizePerPage: 20 });
beforeEach(() => {
wrapper = shallow(<MockComponentWithPaginationHandler { ...createMockProps() } />);
instance = wrapper.instance();
});
it('should setting correct state.totalPages', () => {
instance.componentWillReceiveProps(nextProps);
expect(instance.state.totalPages).toEqual(
instance.calculateTotalPage(nextProps.currSizePerPage));
});
it('should setting correct state.lastPage', () => {
instance.componentWillReceiveProps(nextProps);
const totalPages = instance.calculateTotalPage(nextProps.currSizePerPage);
expect(instance.state.lastPage).toEqual(
instance.calculateLastPage(totalPages));
});
});
describe('when next props.dataSize is diff than current one', () => {
const nextProps = createMockProps({ dataSize: 33 });
beforeEach(() => {
wrapper = shallow(<MockComponentWithPaginationHandler { ...createMockProps() } />);
instance = wrapper.instance();
});
it('should setting correct state.totalPages', () => {
instance.componentWillReceiveProps(nextProps);
expect(instance.state.totalPages).toEqual(
instance.calculateTotalPage(nextProps.currSizePerPage, nextProps.dataSize));
});
it('should setting correct state.lastPage', () => {
instance.componentWillReceiveProps(nextProps);
const totalPages = instance.calculateTotalPage(
nextProps.currSizePerPage, nextProps.dataSize);
expect(instance.state.lastPage).toEqual(
instance.calculateLastPage(totalPages));
});
});
});
});

View File

@@ -1,32 +0,0 @@
import React from 'react';
import { shallow } from 'enzyme';
import paginationListAdapter from '../src/pagination-list-adapter';
const MockComponent = () => null;
const PaginationListAdapter = paginationListAdapter(MockComponent);
describe('paginationListAdapter', () => {
let wrapper;
const props = {
totalPages: 10,
lastPage: 10,
pageButtonRenderer: jest.fn(),
onPageChange: jest.fn()
};
describe('render', () => {
beforeEach(() => {
wrapper = shallow(<PaginationListAdapter { ...props } />);
});
it('should render successfully', () => {
const mockComponent = wrapper.find(MockComponent);
expect(mockComponent).toHaveLength(1);
expect(mockComponent.props().pages).toBeDefined();
expect(mockComponent.props().pageButtonRenderer).toBeDefined();
expect(mockComponent.props().onPageChange).toBeDefined();
});
});
});

View File

@@ -39,22 +39,4 @@ describe('PaginationList', () => {
expect(wrapper.find('ul.react-bootstrap-table-page-btns-ul').length).toBe(1);
expect(wrapper.find(PageButton).length).toBe(pages.length);
});
describe('when props.pageButtonRenderer is existing', () => {
const pageButtonRenderer = jest.fn().mockReturnValue(null);
beforeEach(() => {
wrapper = shallow(
<PaginationList
pages={ pages }
onPageChange={ onPageChange }
pageButtonRenderer={ pageButtonRenderer }
/>
);
});
it('should call props.pageButtonRenderer correctly', () => {
expect(wrapper.length).toBe(1);
expect(pageButtonRenderer).toHaveBeenCalledTimes(pages.length);
});
});
});

View File

@@ -5,7 +5,6 @@ import { shallow } from 'enzyme';
import SizePerPageDropDown from '../src/size-per-page-dropdown';
import PaginationList from '../src/pagination-list';
import Pagination from '../src/pagination';
import PaginationTotal from '../src/pagination-total';
describe('Pagination', () => {
let wrapper;
@@ -41,7 +40,7 @@ describe('Pagination', () => {
it('should rendering correctly', () => {
expect(wrapper.length).toBe(1);
expect(wrapper.dive().hasClass('react-bootstrap-table-pagination')).toBeTruthy();
expect(wrapper.hasClass('react-bootstrap-table-pagination')).toBeTruthy();
expect(wrapper.find('.react-bootstrap-table-pagination-list-hidden').length).toBe(0);
});
@@ -52,6 +51,50 @@ describe('Pagination', () => {
instance.calculateLastPage(instance.state.totalPages));
expect(instance.state.dropdownOpen).toBeFalsy();
});
it('should rendering PaginationList component successfully', () => {
const paginationList = wrapper.find(PaginationList);
expect(paginationList.length).toBe(1);
expect(paginationList.prop('pages')).toEqual(instance.calculatePageStatus(instance.calculatePages()));
expect(paginationList.prop('onPageChange')).toEqual(instance.handleChangePage);
});
it('should rendering SizePerPageDropDown component successfully', () => {
const sizePerPageDropDown = wrapper.find(SizePerPageDropDown);
expect(sizePerPageDropDown.length).toBe(1);
expect(sizePerPageDropDown.prop('currSizePerPage')).toEqual(`${props.currSizePerPage}`);
expect(sizePerPageDropDown.prop('options')).toEqual(instance.calculateSizePerPageStatus());
expect(sizePerPageDropDown.prop('onSizePerPageChange')).toEqual(instance.handleChangeSizePerPage);
expect(sizePerPageDropDown.prop('onClick')).toEqual(instance.toggleDropDown);
expect(sizePerPageDropDown.prop('open')).toEqual(instance.state.dropdownOpen);
});
});
describe('when props.sizePerPageList is empty array', () => {
beforeEach(() => {
const props = createMockProps({ sizePerPageList: [] });
wrapper = shallow(<Pagination { ...props } />);
instance = wrapper.instance();
});
it('should not rendering SizePerPageDropDown component', () => {
const sizePerPageDropDown = wrapper.find(SizePerPageDropDown);
expect(sizePerPageDropDown.length).toBe(0);
});
});
describe('when props.hideSizePerPage is true', () => {
beforeEach(() => {
const props = createMockProps({ hideSizePerPage: true });
wrapper = shallow(<Pagination { ...props } />);
instance = wrapper.instance();
});
it('should not rendering SizePerPageDropDown component', () => {
const sizePerPageDropDown = wrapper.find(SizePerPageDropDown);
expect(sizePerPageDropDown.length).toBe(0);
});
});
describe('when props.hidePageListOnlyOnePage is true', () => {
@@ -62,78 +105,184 @@ describe('Pagination', () => {
});
it('should find react-bootstrap-table-pagination-list-hidden class when only one page', () => {
expect(wrapper.dive().find('.react-bootstrap-table-pagination-list-hidden').length).toBe(1);
expect(wrapper.find('.react-bootstrap-table-pagination-list-hidden').length).toBe(1);
});
});
describe('when props.pageListRenderer is defined', () => {
let pageListRenderer;
beforeEach(() => {
pageListRenderer = jest.fn().mockReturnValue(null);
const props = createMockProps({ pageListRenderer });
wrapper = shallow(<Pagination { ...props } />);
wrapper.render();
instance = wrapper.instance();
});
it('should not render PaginationList', () => {
expect(wrapper.dive().find(PaginationList)).toHaveLength(0);
});
it('should call props.pageListRenderer correctly', () => {
expect(pageListRenderer).toHaveBeenCalledTimes(1);
});
});
describe('when props.sizePerPageRenderer is defined', () => {
let sizePerPageRenderer;
beforeEach(() => {
sizePerPageRenderer = jest.fn().mockReturnValue(null);
const props = createMockProps({ sizePerPageRenderer });
wrapper = shallow(<Pagination { ...props } />);
wrapper.render();
instance = wrapper.instance();
});
it('should not render SizePerPageDropDown', () => {
expect(wrapper.dive().find(SizePerPageDropDown)).toHaveLength(0);
});
it('should call props.sizePerPageRenderer correctly', () => {
expect(sizePerPageRenderer).toHaveBeenCalledTimes(1);
});
});
describe('when props.showTotal is true', () => {
beforeEach(() => {
const props = createMockProps({ showTotal: true });
wrapper = shallow(<Pagination { ...props } />);
wrapper.render();
instance = wrapper.instance();
});
it('should render PaginationTotal correctly', () => {
expect(wrapper.dive().find(PaginationTotal)).toHaveLength(1);
});
describe('if props.paginationTotalRenderer is defined', () => {
let paginationTotalRenderer;
describe('componentWillReceiveProps', () => {
describe('when next props.currSizePerPage is diff than current one', () => {
const nextProps = createMockProps({ currSizePerPage: 20 });
beforeEach(() => {
paginationTotalRenderer = jest.fn();
const props = createMockProps({ showTotal: true, paginationTotalRenderer });
wrapper = shallow(<Pagination { ...props } />);
wrapper.render();
wrapper = shallow(<Pagination { ...createMockProps() } />);
instance = wrapper.instance();
});
it('should not render PaginationTotal', () => {
expect(wrapper.dive().find(PaginationTotal)).toHaveLength(0);
it('should setting correct state.totalPages', () => {
instance.componentWillReceiveProps(nextProps);
expect(instance.state.totalPages).toEqual(
instance.calculateTotalPage(nextProps.currSizePerPage));
});
it('should call props.paginationTotalRenderer correctly', () => {
expect(paginationTotalRenderer).toHaveBeenCalledTimes(1);
it('should setting correct state.lastPage', () => {
instance.componentWillReceiveProps(nextProps);
const totalPages = instance.calculateTotalPage(nextProps.currSizePerPage);
expect(instance.state.lastPage).toEqual(
instance.calculateLastPage(totalPages));
});
});
describe('when next props.dataSize is diff than current one', () => {
const nextProps = createMockProps({ dataSize: 33 });
beforeEach(() => {
wrapper = shallow(<Pagination { ...createMockProps() } />);
instance = wrapper.instance();
});
it('should setting correct state.totalPages', () => {
instance.componentWillReceiveProps(nextProps);
expect(instance.state.totalPages).toEqual(
instance.calculateTotalPage(nextProps.currSizePerPage, nextProps.dataSize));
});
it('should setting correct state.lastPage', () => {
instance.componentWillReceiveProps(nextProps);
const totalPages = instance.calculateTotalPage(
nextProps.currSizePerPage, nextProps.dataSize);
expect(instance.state.lastPage).toEqual(
instance.calculateLastPage(totalPages));
});
});
});
describe('toggleDropDown', () => {
beforeEach(() => {
const props = createMockProps();
wrapper = shallow(<Pagination { ...props } />);
instance = wrapper.instance();
});
it('should setting state.dropdownOpen as true when it is false', () => {
instance.toggleDropDown();
expect(instance.state.dropdownOpen).toBeTruthy();
});
it('should setting state.dropdownOpen as false when it is true', () => {
instance.toggleDropDown();
instance.toggleDropDown();
expect(instance.state.dropdownOpen).toBeFalsy();
});
});
describe('closeDropDown', () => {
beforeEach(() => {
const props = createMockProps();
wrapper = shallow(<Pagination { ...props } />);
instance = wrapper.instance();
});
it('should always setting state.dropdownOpen as false', () => {
instance.closeDropDown();
expect(instance.state.dropdownOpen).toBeFalsy();
instance.closeDropDown();
expect(instance.state.dropdownOpen).toBeFalsy();
});
});
describe('handleChangeSizePerPage', () => {
const props = createMockProps();
beforeEach(() => {
wrapper = shallow(<Pagination { ...props } />);
instance = wrapper.instance();
});
it('should always setting state.dropdownOpen to false', () => {
instance.handleChangeSizePerPage(10);
expect(instance.state.dropdownOpen).toBeFalsy();
});
describe('when new sizePerPage is same as current one', () => {
it('should not calling props.onSizePerPageChange callback', () => {
instance.handleChangeSizePerPage(10);
expect(props.onSizePerPageChange.callCount).toBe(0);
});
});
describe('when new sizePerPage is diff than current one', () => {
it('should not calling props.onSizePerPageChange callback', () => {
instance.handleChangeSizePerPage(30);
expect(props.onSizePerPageChange.callCount).toBe(1);
});
describe('and new current page is still in the new lagination list', () => {
it('should calling props.onSizePerPageChange with correct argument', () => {
expect(props.onSizePerPageChange.calledWith(30, props.currPage));
});
});
describe('and new current page is still in the new lagination list', () => {
beforeEach(() => {
wrapper = shallow(<Pagination { ...createMockProps({ currPage: 10 }) } />);
instance = wrapper.instance();
});
it('should calling props.onSizePerPageChange with correct argument', () => {
expect(props.onSizePerPageChange.calledWith(30, 4));
});
});
});
});
describe('handleChangePage', () => {
const props = createMockProps();
beforeEach(() => {
props.currPage = 6;
wrapper = shallow(<Pagination { ...props } />);
instance = wrapper.instance();
});
afterEach(() => {
props.onPageChange.reset();
});
it('should calling props.onPageChange correctly when new page is eq props.prePageText', () => {
instance.handleChangePage(props.prePageText);
expect(props.onPageChange.callCount).toBe(1);
expect(props.onPageChange.calledWith(5)).toBeTruthy();
});
it('should calling props.onPageChange correctly when new page is eq props.nextPageText', () => {
instance.handleChangePage(props.nextPageText);
expect(props.onPageChange.callCount).toBe(1);
expect(props.onPageChange.calledWith(7)).toBeTruthy();
});
it('should calling props.onPageChange correctly when new page is eq props.lastPageText', () => {
instance.handleChangePage(props.lastPageText);
expect(props.onPageChange.callCount).toBe(1);
expect(props.onPageChange.calledWith(10)).toBeTruthy();
});
it('should calling props.onPageChange correctly when new page is eq props.firstPageText', () => {
instance.handleChangePage(props.firstPageText);
expect(props.onPageChange.callCount).toBe(1);
expect(props.onPageChange.calledWith(props.pageStartIndex)).toBeTruthy();
});
it('should calling props.onPageChange correctly when new page is a numeric page', () => {
const newPage = '8';
instance.handleChangePage(newPage);
expect(props.onPageChange.callCount).toBe(1);
expect(props.onPageChange.calledWith(parseInt(newPage, 10))).toBeTruthy();
});
it('should not calling props.onPageChange correctly when page is not changed', () => {
const newPage = props.currPage;
instance.handleChangePage(newPage);
expect(props.onPageChange.callCount).toBe(0);
});
});
});

View File

@@ -1,146 +0,0 @@
import React from 'react';
import { shallow } from 'enzyme';
import sizePerPageDropdownAdapter from '../src/size-per-page-dropdown-adapter';
const MockComponent = () => null;
const SizePerPageDropdownAdapter = sizePerPageDropdownAdapter(MockComponent);
describe('sizePerPageDropdownAdapter', () => {
let wrapper;
let instance;
const createMockProps = props => ({
dataSize: 100,
sizePerPageList: [10, 20, 30, 50],
currPage: 1,
currSizePerPage: 10,
alwaysShowAllBtns: false,
onSizePerPageChange: jest.fn(),
hidePageListOnlyOnePage: false,
hideSizePerPage: false,
optionRenderer: jest.fn(),
sizePerPageOptionRenderer: jest.fn(),
...props
});
describe('render', () => {
const props = createMockProps();
beforeEach(() => {
wrapper = shallow(<SizePerPageDropdownAdapter { ...props } />);
instance = wrapper.instance();
});
it('should render successfully', () => {
const mockComponent = wrapper.find(MockComponent);
expect(mockComponent).toHaveLength(1);
expect(mockComponent.props().currSizePerPage).toEqual(`${props.currSizePerPage}`);
expect(mockComponent.props().options).toBeDefined();
expect(mockComponent.props().optionRenderer).toBeDefined();
expect(mockComponent.props().onSizePerPageChange).toEqual(instance.handleChangeSizePerPage);
expect(mockComponent.props().onClick).toEqual(instance.toggleDropDown);
expect(mockComponent.props().onBlur).toEqual(instance.closeDropDown);
expect(mockComponent.props().open).toEqual(instance.state.dropdownOpen);
});
});
describe('when props.sizePerPageList is empty array', () => {
beforeEach(() => {
const props = createMockProps({ sizePerPageList: [] });
wrapper = shallow(<SizePerPageDropdownAdapter { ...props } />);
instance = wrapper.instance();
});
it('should not render component', () => {
const sizePerPageDropDown = wrapper.find(MockComponent);
expect(sizePerPageDropDown.length).toBe(0);
});
});
describe('when props.hideSizePerPage is true', () => {
beforeEach(() => {
const props = createMockProps({ hideSizePerPage: true });
wrapper = shallow(<SizePerPageDropdownAdapter { ...props } />);
instance = wrapper.instance();
});
it('should not rendering SizePerPageDropDown component', () => {
const sizePerPageDropDown = wrapper.find(MockComponent);
expect(sizePerPageDropDown.length).toBe(0);
});
});
describe('toggleDropDown', () => {
beforeEach(() => {
const props = createMockProps();
wrapper = shallow(<SizePerPageDropdownAdapter { ...props } />);
instance = wrapper.instance();
});
it('should set state.dropdownOpen as true when it is false', () => {
instance.toggleDropDown();
expect(instance.state.dropdownOpen).toBeTruthy();
});
it('should set state.dropdownOpen as false when it is true', () => {
instance.toggleDropDown();
instance.toggleDropDown();
expect(instance.state.dropdownOpen).toBeFalsy();
});
});
describe('closeDropDown', () => {
beforeEach(() => {
const props = createMockProps();
wrapper = shallow(<SizePerPageDropdownAdapter { ...props } />);
instance = wrapper.instance();
});
it('should always set state.dropdownOpen as false', () => {
instance.closeDropDown();
expect(instance.state.dropdownOpen).toBeFalsy();
instance.closeDropDown();
expect(instance.state.dropdownOpen).toBeFalsy();
});
});
describe('handleChangeSizePerPage', () => {
let props;
const sizePerPage = 25;
beforeEach(() => {
props = createMockProps();
wrapper = shallow(<SizePerPageDropdownAdapter { ...props } />);
instance = wrapper.instance();
instance.handleChangeSizePerPage(sizePerPage);
});
it('should call props.onSizePerPageChange correctly', () => {
expect(props.onSizePerPageChange).toHaveBeenCalledTimes(1);
expect(props.onSizePerPageChange).toHaveBeenCalledWith(sizePerPage);
});
it('should always set state.dropdownOpen as false', () => {
expect(instance.state.dropdownOpen).toBeFalsy();
});
});
describe('when props.sizePerPageRenderer is defined', () => {
const sizePerPageRenderer = jest.fn().mockReturnValue(null);
beforeEach(() => {
sizePerPageRenderer.mockClear();
const props = createMockProps({ sizePerPageRenderer });
wrapper = shallow(<SizePerPageDropdownAdapter { ...props } />);
instance = wrapper.instance();
});
it('should not render default component', () => {
expect(wrapper.find(MockComponent)).toHaveLength(0);
});
it('should call props.sizePerPageRenderer correctly', () => {
expect(sizePerPageRenderer).toHaveBeenCalledTimes(1);
});
});
});

View File

@@ -178,23 +178,4 @@ describe('SizePerPageDropDown', () => {
expect(wrapper.hasClass(className)).toBeTruthy();
});
});
describe('when optionRenderer prop is defined', () => {
const optionRenderer = jest.fn();
beforeEach(() => {
optionRenderer.mockReset();
wrapper = shallowWithContext(
<SizePerPageDropDown { ...props } optionRenderer={ optionRenderer } />,
{ bootstrap4: false }
);
});
it('should not render SizePerPageOption', () => {
expect(wrapper.find(SizePerPageOption)).toHaveLength(0);
});
it('should call optionRenderer prop correctly', () => {
expect(optionRenderer).toHaveBeenCalledTimes(props.options.length);
});
});
});

View File

@@ -1,44 +0,0 @@
import React from 'react';
import { shallow } from 'enzyme';
import standaloneAdapter from '../src/standalone-adapter';
const MockStandalone = () => null;
const MockStandaloneWithAdapter = standaloneAdapter(MockStandalone);
describe('standaloneAdapter', () => {
let wrapper;
const props = {
page: 2,
sizePerPage: 10,
name1: 'A',
name2: 'B'
};
describe('render', () => {
beforeEach(() => {
wrapper = shallow(<MockStandaloneWithAdapter { ...props } />);
});
it('should render successfully', () => {
expect(wrapper.find(MockStandalone)).toHaveLength(1);
});
it('should convert props.page as currPage to child component', () => {
const mockStandalone = wrapper.find(MockStandalone);
expect(mockStandalone.props().currPage).toEqual(props.page);
});
it('should convert props.sizePerPage as currSizePerPage to child component', () => {
const mockStandalone = wrapper.find(MockStandalone);
expect(mockStandalone.props().currSizePerPage).toEqual(props.sizePerPage);
});
it('should just pass remain props to child component', () => {
const mockStandalone = wrapper.find(MockStandalone);
const { page, sizePerPage, ...origin } = props;
const { currPage, currSizePerPage, ...rest } = mockStandalone.props();
expect(rest).toEqual(origin);
});
});
});

View File

@@ -1,841 +0,0 @@
/* eslint no-param-reassign: 0 */
import 'jsdom-global/register';
import React from 'react';
import { shallow } from 'enzyme';
import Const from '../src/const';
import createStateContext from '../src/state-context';
import paginationFactory from '../index';
const data = [];
for (let i = 0; i < 100; i += 1) {
data.push({
id: i,
name: `itme name ${i}`
});
}
describe('PaginationStateContext', () => {
let wrapper;
let remoteEmitter;
let PaginationStateContext;
const defaultPagination = { options: {}, createContext: jest.fn() };
const MockComponent = () => null;
const renderMockComponent = jest.fn((props => (
<MockComponent { ...props } />
)));
const handleRemotePaginationChange = jest.fn();
function shallowContext(
customPagination = defaultPagination
) {
const additionProps = {};
renderMockComponent.mockReset();
handleRemotePaginationChange.mockReset();
PaginationStateContext = createStateContext();
return (
<PaginationStateContext.Provider
pagination={ paginationFactory(customPagination) }
data={ data }
{ ...additionProps }
>
<PaginationStateContext.Consumer>
{
paginationProps => renderMockComponent(paginationProps)
}
</PaginationStateContext.Consumer>
</PaginationStateContext.Provider>
);
}
function setRemotePaginationEmitter(
instance,
remoteEnabled = false
) {
remoteEmitter = { emit: jest.fn() };
if (remoteEnabled) {
remoteEmitter.emit = jest.fn().mockImplementation((evtName, d = {}) => {
if (evtName === 'isRemotePagination') {
d.result = remoteEnabled;
}
});
}
instance.setPaginationRemoteEmitter(remoteEmitter);
}
describe('default render', () => {
const options = { totalSize: data.length };
beforeEach(() => {
wrapper = shallow(shallowContext(options));
wrapper.render();
});
it('should have correct Provider property after calling createPaginationStateContext', () => {
expect(PaginationStateContext.Provider).toBeDefined();
});
it('should have correct Consumer property after calling createPaginationStateContext', () => {
expect(PaginationStateContext.Consumer).toBeDefined();
});
it('should have correct currPage', () => {
expect(wrapper.instance().currPage).toEqual(Const.PAGE_START_INDEX);
});
it('should have correct currSizePerPage', () => {
expect(wrapper.instance().currSizePerPage).toEqual(Const.SIZE_PER_PAGE_LIST[0]);
});
it('should get correct pagination props', () => {
const instance = wrapper.instance();
expect(wrapper.length).toBe(1);
expect(renderMockComponent).toHaveBeenCalledTimes(1);
expect(renderMockComponent).toHaveBeenCalledWith({
paginationProps: instance.getPaginationProps(),
paginationTableProps: {
pagination: {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
}
});
});
it('should return correct pagination states from getPaginationProps function', () => {
const instance = wrapper.instance();
const paginationProps = instance.getPaginationProps();
expect(paginationProps.dataSize).toEqual(data.length);
expect(paginationProps.page).toEqual(instance.currPage);
expect(paginationProps.sizePerPage).toEqual(instance.currSizePerPage);
expect(paginationProps.onPageChange).toEqual(instance.handleChangePage);
expect(paginationProps.onSizePerPageChange).toEqual(instance.handleChangeSizePerPage);
expect(paginationProps.sizePerPageList).toEqual(Const.SIZE_PER_PAGE_LIST);
expect(paginationProps.paginationSize).toEqual(Const.PAGINATION_SIZE);
expect(paginationProps.showTotal).toEqual(options.showTotal);
expect(paginationProps.hidePageListOnlyOnePage).toEqual(Const.HIDE_PAGE_LIST_ONLY_ONE_PAGE);
expect(paginationProps.pageStartIndex).toEqual(Const.PAGE_START_INDEX);
expect(paginationProps.withFirstAndLast).toEqual(Const.With_FIRST_AND_LAST);
expect(paginationProps.alwaysShowAllBtns).toEqual(Const.SHOW_ALL_PAGE_BTNS);
expect(paginationProps.firstPageText).toEqual(Const.FIRST_PAGE_TEXT);
expect(paginationProps.prePageText).toEqual(Const.PRE_PAGE_TEXT);
expect(paginationProps.nextPageText).toEqual(Const.NEXT_PAGE_TEXT);
expect(paginationProps.lastPageText).toEqual(Const.LAST_PAGE_TEXT);
expect(paginationProps.firstPageTitle).toEqual(Const.FIRST_PAGE_TITLE);
expect(paginationProps.prePageTitle).toEqual(Const.PRE_PAGE_TITLE);
expect(paginationProps.nextPageTitle).toEqual(Const.NEXT_PAGE_TITLE);
expect(paginationProps.lastPageTitle).toEqual(Const.LAST_PAGE_TITLE);
expect(paginationProps.hideSizePerPage).toEqual(Const.HIDE_SIZE_PER_PAGE);
expect(paginationProps.paginationTotalRenderer).toEqual(options.paginationTotalRenderer);
});
});
describe('compoientWillReceiveProps', () => {
let instance;
let nextProps;
describe('if remote pagination is enable', () => {
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination
}, true));
instance = wrapper.instance();
setRemotePaginationEmitter(instance, true);
nextProps = {
data,
pagination: { ...defaultPagination, options: { page: 3, sizePerPage: 5 } }
};
instance.componentWillReceiveProps(nextProps);
});
it('should always reset currPage and currSizePerPage', () => {
expect(instance.currPage).toEqual(nextProps.pagination.options.page);
expect(instance.currSizePerPage).toEqual(nextProps.pagination.options.sizePerPage);
});
});
describe('if options.custom is true', () => {
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
custom: true
}, true));
instance = wrapper.instance();
setRemotePaginationEmitter(instance, true);
nextProps = {
data,
pagination: { ...defaultPagination, options: { page: 3, sizePerPage: 5, custom: true } }
};
instance.componentWillReceiveProps(nextProps);
});
it('should always reset currPage and currSizePerPage', () => {
expect(instance.currPage).toEqual(nextProps.pagination.options.page);
expect(instance.currSizePerPage).toEqual(nextProps.pagination.options.sizePerPage);
});
});
});
describe('handleChangePage', () => {
let instance;
const newPage = 3;
describe('should update component correctly', () => {
beforeEach(() => {
wrapper = shallow(shallowContext());
instance = wrapper.instance();
setRemotePaginationEmitter(instance);
jest.spyOn(instance, 'forceUpdate');
instance.handleChangePage(newPage);
});
it('', () => {
expect(instance.currPage).toEqual(newPage);
expect(instance.forceUpdate).toHaveBeenCalledTimes(1);
});
});
describe('if options.onPageChange is defined', () => {
const onPageChange = jest.fn();
beforeEach(() => {
onPageChange.mockClear();
wrapper = shallow(shallowContext({
...defaultPagination,
onPageChange
}));
instance = wrapper.instance();
setRemotePaginationEmitter(instance);
jest.spyOn(instance, 'forceUpdate');
instance.handleChangePage(newPage);
});
it('should still update component correctly', () => {
expect(instance.currPage).toEqual(newPage);
expect(instance.forceUpdate).toHaveBeenCalledTimes(1);
});
it('should call options.onPageChange correctly', () => {
expect(onPageChange).toHaveBeenCalledTimes(1);
expect(onPageChange).toHaveBeenCalledWith(newPage, instance.currSizePerPage);
});
});
describe('if remote pagination is enable', () => {
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination
}, true));
instance = wrapper.instance();
setRemotePaginationEmitter(instance, true);
jest.spyOn(instance, 'forceUpdate');
instance.handleChangePage(newPage);
});
it('should still update component correctly', () => {
expect(instance.currPage).toEqual(newPage);
expect(instance.forceUpdate).toHaveBeenCalledTimes(0);
});
it('should emit paginationChange event correctly', () => {
expect(remoteEmitter.emit).toHaveBeenLastCalledWith('paginationChange', instance.currPage, instance.currSizePerPage);
});
});
});
describe('handleChangeSizePerPage', () => {
let instance;
const newPage = 2;
const newSizePerPage = 15;
describe('should update component correctly', () => {
beforeEach(() => {
wrapper = shallow(shallowContext());
instance = wrapper.instance();
setRemotePaginationEmitter(instance);
jest.spyOn(instance, 'forceUpdate');
instance.handleChangeSizePerPage(newSizePerPage, newPage);
});
it('', () => {
expect(instance.currPage).toEqual(newPage);
expect(instance.currSizePerPage).toEqual(newSizePerPage);
expect(instance.forceUpdate).toHaveBeenCalledTimes(1);
});
});
describe('if options.onSizePerPageChange is defined', () => {
const onSizePerPageChange = jest.fn();
beforeEach(() => {
onSizePerPageChange.mockClear();
wrapper = shallow(shallowContext({
...defaultPagination,
onSizePerPageChange
}));
instance = wrapper.instance();
setRemotePaginationEmitter(instance);
jest.spyOn(instance, 'forceUpdate');
instance.handleChangeSizePerPage(newSizePerPage, newPage);
});
it('should still update component correctly', () => {
expect(instance.currPage).toEqual(newPage);
expect(instance.currSizePerPage).toEqual(newSizePerPage);
expect(instance.forceUpdate).toHaveBeenCalledTimes(1);
});
it('should call options.onSizePerPageChange correctly', () => {
expect(onSizePerPageChange).toHaveBeenCalledTimes(1);
expect(onSizePerPageChange).toHaveBeenCalledWith(newSizePerPage, newPage);
});
});
describe('if remote pagination is enable', () => {
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination
}, true));
instance = wrapper.instance();
setRemotePaginationEmitter(instance, true);
jest.spyOn(instance, 'forceUpdate');
instance.handleChangeSizePerPage(newSizePerPage, newPage);
});
it('should still update component correctly', () => {
expect(instance.currPage).toEqual(newPage);
expect(instance.currSizePerPage).toEqual(newSizePerPage);
expect(instance.forceUpdate).toHaveBeenCalledTimes(0);
});
it('should emit paginationChange event correctly', () => {
expect(remoteEmitter.emit).toHaveBeenLastCalledWith('paginationChange', instance.currPage, instance.currSizePerPage);
});
});
});
describe('when options.page is defined', () => {
const page = 3;
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
page
}));
wrapper.render();
});
it('should set correct currPage', () => {
expect(wrapper.instance().currPage).toEqual(page);
});
it('should render correctly', () => {
const instance = wrapper.instance();
expect(renderMockComponent).toHaveBeenCalledWith({
paginationProps: instance.getPaginationProps(),
paginationTableProps: {
pagination: {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
}
});
});
});
describe('when options.sizePerPage is defined', () => {
const sizePerPage = Const.SIZE_PER_PAGE_LIST[2];
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
sizePerPage
}));
wrapper.render();
});
it('should set correct currSizePerPage', () => {
expect(wrapper.instance().currSizePerPage).toEqual(sizePerPage);
});
it('should render correctly', () => {
const instance = wrapper.instance();
expect(renderMockComponent).toHaveBeenCalledWith({
paginationProps: instance.getPaginationProps(),
paginationTableProps: {
pagination: {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
}
});
});
});
describe('when options.totalSize is defined', () => {
const totalSize = 100;
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
totalSize
}));
wrapper.render();
});
it('should render correctly', () => {
const instance = wrapper.instance();
expect(renderMockComponent).toHaveBeenCalledWith({
paginationProps: instance.getPaginationProps(),
paginationTableProps: {
pagination: {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
}
});
});
});
describe('when options.showTotal is defined', () => {
const showTotal = true;
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
showTotal
}));
wrapper.render();
});
it('should render correctly', () => {
const instance = wrapper.instance();
expect(renderMockComponent).toHaveBeenCalledWith({
paginationProps: instance.getPaginationProps(),
paginationTableProps: {
pagination: {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
}
});
});
});
describe('when options.pageStartIndex is defined', () => {
const pageStartIndex = -1;
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
pageStartIndex
}));
wrapper.render();
});
it('should render correctly', () => {
const instance = wrapper.instance();
expect(renderMockComponent).toHaveBeenCalledWith({
paginationProps: instance.getPaginationProps(),
paginationTableProps: {
pagination: {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
}
});
});
});
describe('when options.sizePerPageList is defined', () => {
const sizePerPageList = [10, 40];
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
sizePerPageList
}));
wrapper.render();
});
it('should render correctly', () => {
const instance = wrapper.instance();
expect(renderMockComponent).toHaveBeenCalledWith({
paginationProps: instance.getPaginationProps(),
paginationTableProps: {
pagination: {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
}
});
});
});
describe('when options.paginationSize is defined', () => {
const paginationSize = 10;
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
paginationSize
}));
wrapper.render();
});
it('should render correctly', () => {
const instance = wrapper.instance();
expect(renderMockComponent).toHaveBeenCalledWith({
paginationProps: instance.getPaginationProps(),
paginationTableProps: {
pagination: {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
}
});
});
});
describe('when options.withFirstAndLast is defined', () => {
const withFirstAndLast = false;
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
withFirstAndLast
}));
wrapper.render();
});
it('should render correctly', () => {
const instance = wrapper.instance();
expect(renderMockComponent).toHaveBeenCalledWith({
paginationProps: instance.getPaginationProps(),
paginationTableProps: {
pagination: {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
}
});
});
});
describe('when options.alwaysShowAllBtns is defined', () => {
const alwaysShowAllBtns = true;
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
alwaysShowAllBtns
}));
wrapper.render();
});
it('should render correctly', () => {
const instance = wrapper.instance();
expect(renderMockComponent).toHaveBeenCalledWith({
paginationProps: instance.getPaginationProps(),
paginationTableProps: {
pagination: {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
}
});
});
});
describe('when options.firstPageText is defined', () => {
const firstPageText = '1st';
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
firstPageText
}));
wrapper.render();
});
it('should render correctly', () => {
const instance = wrapper.instance();
expect(renderMockComponent).toHaveBeenCalledWith({
paginationProps: instance.getPaginationProps(),
paginationTableProps: {
pagination: {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
}
});
});
});
describe('when options.prePageText is defined', () => {
const prePageText = 'PRE';
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
prePageText
}));
wrapper.render();
});
it('should render correctly', () => {
const instance = wrapper.instance();
expect(renderMockComponent).toHaveBeenCalledWith({
paginationProps: instance.getPaginationProps(),
paginationTableProps: {
pagination: {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
}
});
});
});
describe('when options.nextPageText is defined', () => {
const nextPageText = 'NEXT';
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
nextPageText
}));
wrapper.render();
});
it('should render correctly', () => {
const instance = wrapper.instance();
expect(renderMockComponent).toHaveBeenCalledWith({
paginationProps: instance.getPaginationProps(),
paginationTableProps: {
pagination: {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
}
});
});
});
describe('when options.lastPageText is defined', () => {
const lastPageText = 'LAST';
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
lastPageText
}));
wrapper.render();
});
it('should render correctly', () => {
const instance = wrapper.instance();
expect(renderMockComponent).toHaveBeenCalledWith({
paginationProps: instance.getPaginationProps(),
paginationTableProps: {
pagination: {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
}
});
});
});
describe('when options.firstPageTitle is defined', () => {
const firstPageTitle = '1st';
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
firstPageTitle
}));
wrapper.render();
});
it('should render correctly', () => {
const instance = wrapper.instance();
expect(renderMockComponent).toHaveBeenCalledWith({
paginationProps: instance.getPaginationProps(),
paginationTableProps: {
pagination: {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
}
});
});
});
describe('when options.prePageTitle is defined', () => {
const prePageTitle = 'PRE';
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
prePageTitle
}));
wrapper.render();
});
it('should render correctly', () => {
const instance = wrapper.instance();
expect(renderMockComponent).toHaveBeenCalledWith({
paginationProps: instance.getPaginationProps(),
paginationTableProps: {
pagination: {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
}
});
});
});
describe('when options.nextPageTitle is defined', () => {
const nextPageTitle = 'NEXT';
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
nextPageTitle
}));
wrapper.render();
});
it('should render correctly', () => {
const instance = wrapper.instance();
expect(renderMockComponent).toHaveBeenCalledWith({
paginationProps: instance.getPaginationProps(),
paginationTableProps: {
pagination: {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
}
});
});
});
describe('when options.lastPageTitle is defined', () => {
const lastPageTitle = 'nth';
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
lastPageTitle
}));
wrapper.render();
});
it('should render correctly', () => {
const instance = wrapper.instance();
expect(renderMockComponent).toHaveBeenCalledWith({
paginationProps: instance.getPaginationProps(),
paginationTableProps: {
pagination: {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
}
});
});
});
describe('when options.hideSizePerPage is defined', () => {
const hideSizePerPage = true;
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
hideSizePerPage
}));
wrapper.render();
});
it('should render correctly', () => {
const instance = wrapper.instance();
expect(renderMockComponent).toHaveBeenCalledWith({
paginationProps: instance.getPaginationProps(),
paginationTableProps: {
pagination: {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
}
});
});
});
describe('when options.hidePageListOnlyOnePage is defined', () => {
const hidePageListOnlyOnePage = true;
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultPagination,
hidePageListOnlyOnePage
}));
wrapper.render();
});
it('should render correctly', () => {
const instance = wrapper.instance();
expect(renderMockComponent).toHaveBeenCalledWith({
paginationProps: instance.getPaginationProps(),
paginationTableProps: {
pagination: {
createContext: expect.any(Function),
options: instance.getPaginationProps()
},
setPaginationRemoteEmitter: instance.setPaginationRemoteEmitter
}
});
});
});
});

View File

@@ -1,13 +1,13 @@
import React from 'react';
import PropTypes from 'prop-types';
import statelessDrcorator from './statelessOp';
import statelessDecorator from './statelessOp';
import createContext from './src/search/context';
const ToolkitContext = React.createContext();
class ToolkitProvider extends statelessDrcorator(React.Component) {
class ToolkitProvider extends statelessDecorator(React.Component) {
static propTypes = {
keyField: PropTypes.string.isRequired,
data: PropTypes.array.isRequired,

View File

@@ -1,6 +1,6 @@
{
"name": "react-bootstrap-table2-toolkit",
"version": "1.1.2",
"version": "1.1.1",
"description": "The toolkit for react-bootstrap-table2",
"main": "./lib/index.js",
"repository": {

View File

@@ -2,18 +2,18 @@ import React from 'react';
import PropTypes from 'prop-types';
import ToolkitContext from './context';
const Toolkitprovider = props => (
const ToolkitProvider = props => (
<ToolkitContext.Provider { ...props }>
<ToolkitContext.Consumer>
{
tookKitProps => props.children(tookKitProps)
toolkitProps => props.children(toolkitProps)
}
</ToolkitContext.Consumer>
</ToolkitContext.Provider>
);
Toolkitprovider.propTypes = {
ToolkitProvider.propTypes = {
children: PropTypes.func.isRequired
};
export default Toolkitprovider;
export default ToolkitProvider;

View File

@@ -25,19 +25,13 @@ export default Base =>
let data;
if (typeof source !== 'undefined') {
data = source;
} else if (options.exportAll) {
data = this.props.data;
} else {
const payload = {};
this.tableExposedAPIEmitter.emit('get.table.data', payload);
data = payload.result;
data = options.exportAll ? this.props.data : this.getData();
}
// filter data
if (options.onlyExportSelection) {
const payload = {};
this.tableExposedAPIEmitter.emit('get.selected.rows', payload);
const selections = payload.result;
const selections = this.getSelected();
data = data.filter(row => !!selections.find(sel => row[keyField] === sel));
}
const content = transform(data, meta, this._.get, options);

View File

@@ -2,7 +2,9 @@ import Operation from './src/op';
export default Base =>
class StatelessOperation extends Operation.csvOperation(Base) {
registerExposedAPI = (tableExposedAPIEmitter) => {
this.tableExposedAPIEmitter = tableExposedAPIEmitter;
registerExposedAPI = (...exposedFuncs) => {
exposedFuncs.forEach((func) => {
this[func.name] = func;
});
}
};

View File

@@ -1,6 +1,6 @@
{
"name": "react-bootstrap-table-next",
"version": "2.0.1",
"version": "1.3.1",
"description": "Next generation of react-bootstrap-table",
"main": "./lib/index.js",
"repository": {

View File

@@ -14,11 +14,14 @@ class BootstrapTable extends PropsBaseResolver(Component) {
constructor(props) {
super(props);
this.validateProps();
if (props.registerExposedAPI) {
props.registerExposedAPI(this.getData);
}
}
// Exposed APIs
getData = () => {
return this.visibleRows();
getData() {
return this.props.data;
}
render() {
@@ -36,12 +39,12 @@ class BootstrapTable extends PropsBaseResolver(Component) {
renderTable() {
const {
data,
columns,
keyField,
tabIndexCell,
id,
classes,
bootstrap4,
striped,
hover,
bordered,
@@ -54,7 +57,8 @@ class BootstrapTable extends PropsBaseResolver(Component) {
rowEvents,
selectRow,
expandRow,
cellEdit
cellEdit,
sticky
} = this.props;
const tableWrapperClass = cs('react-bootstrap-table', wrapperClasses);
@@ -63,7 +67,8 @@ class BootstrapTable extends PropsBaseResolver(Component) {
'table-striped': striped,
'table-hover': hover,
'table-bordered': bordered,
[(bootstrap4 ? 'table-sm' : 'table-condensed')]: condensed
'table-condensed': condensed,
'table-sticky': sticky
}, classes);
const tableCaption = (caption && <Caption>{ caption }</Caption>);
@@ -84,7 +89,7 @@ class BootstrapTable extends PropsBaseResolver(Component) {
expandRow={ expandRow }
/>
<Body
data={ this.getData() }
data={ data }
keyField={ keyField }
tabIndexCell={ tabIndexCell }
columns={ columns }
@@ -115,6 +120,7 @@ BootstrapTable.propTypes = {
noDataIndication: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
striped: PropTypes.bool,
bordered: PropTypes.bool,
sticky: PropTypes.bool,
hover: PropTypes.bool,
tabIndexCell: PropTypes.bool,
id: PropTypes.string,
@@ -158,11 +164,7 @@ BootstrapTable.propTypes = {
onlyOneExpanding: PropTypes.bool,
expandByColumnOnly: PropTypes.bool,
expandColumnRenderer: PropTypes.func,
expandHeaderColumnRenderer: PropTypes.func,
expandColumnPosition: PropTypes.oneOf([
Const.INDICATOR_POSITION_LEFT,
Const.INDICATOR_POSITION_RIGHT
])
expandHeaderColumnRenderer: PropTypes.func
}),
rowStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
rowEvents: PropTypes.object,
@@ -191,6 +193,7 @@ BootstrapTable.defaultProps = {
remote: false,
striped: false,
bordered: true,
sticky: false,
hover: false,
condensed: false,
noDataIndication: null,

View File

@@ -6,7 +6,5 @@ export default {
ROW_SELECT_DISABLED: 'ROW_SELECT_DISABLED',
CHECKBOX_STATUS_CHECKED: 'checked',
CHECKBOX_STATUS_INDETERMINATE: 'indeterminate',
CHECKBOX_STATUS_UNCHECKED: 'unchecked',
INDICATOR_POSITION_LEFT: 'left',
INDICATOR_POSITION_RIGHT: 'right'
CHECKBOX_STATUS_UNCHECKED: 'unchecked'
};

View File

@@ -1,8 +1,6 @@
/* eslint no-return-assign: 0 */
/* eslint no-param-reassign: 0 */
/* eslint class-methods-use-this: 0 */
import React, { Component } from 'react';
import EventEmitter from 'events';
import _ from '../utils';
import createDataContext from './data-context';
import createSortContext from './sort-context';
@@ -18,13 +16,6 @@ const withContext = Base =>
super(props);
this.DataContext = createDataContext();
if (props.registerExposedAPI) {
const exposedAPIEmitter = new EventEmitter();
exposedAPIEmitter.on('get.table.data', payload => payload.result = this.table.getData());
exposedAPIEmitter.on('get.selected.rows', payload => payload.result = this.selectionContext.getSelected());
props.registerExposedAPI(exposedAPIEmitter);
}
if (props.columns.filter(col => col.sort).length > 0) {
this.SortContext = createSortContext(
dataOperator, this.isRemoteSort, this.handleRemoteSortChange);
@@ -49,7 +40,8 @@ const withContext = Base =>
}
if (props.pagination) {
this.PaginationContext = props.pagination.createContext();
this.PaginationContext = props.pagination.createContext(
this.isRemotePagination, this.handleRemotePageChange);
}
if (props.search && props.search.searchContext) {
@@ -60,10 +52,6 @@ const withContext = Base =>
if (props.setDependencyModules) {
props.setDependencyModules(_);
}
if (props.setPaginationRemoteEmitter) {
props.setPaginationRemoteEmitter(this.remoteEmitter);
}
}
componentWillReceiveProps(nextProps) {
@@ -162,8 +150,6 @@ const withContext = Base =>
pagination={ this.props.pagination }
data={ rootProps.getData(filterProps, searchProps, sortProps) }
bootstrap4={ this.props.bootstrap4 }
isRemotePagination={ this.isRemotePagination }
remoteEmitter={ this.remoteEmitter }
>
<this.PaginationContext.Consumer>
{
@@ -264,8 +250,9 @@ const withContext = Base =>
}
render() {
const { keyField, columns, bootstrap4 } = this.props;
const { keyField, columns, bootstrap4, registerExposedAPI } = this.props;
const baseProps = { keyField, columns };
if (registerExposedAPI) baseProps.registerExposedAPI = registerExposedAPI;
let base = this.renderBase();

View File

@@ -23,10 +23,7 @@ class RowExpandProvider extends React.Component {
}
handleRowExpand = (rowKey, expanded, rowIndex, e) => {
const { data, keyField, expandRow: { onExpand, onlyOneExpanding, nonExpandable } } = this.props;
if (nonExpandable && nonExpandable.includes(rowKey)) {
return;
}
const { data, keyField, expandRow: { onExpand, onlyOneExpanding } } = this.props;
let currExpanded = [...this.state.expanded];
@@ -76,7 +73,6 @@ class RowExpandProvider extends React.Component {
<RowExpandContext.Provider
value={ {
...this.props.expandRow,
nonExpandable: this.props.expandRow.nonExpandable,
expanded: this.state.expanded,
isAnyExpands: dataOperator.isAnyExpands(data, keyField, this.state.expanded),
onRowExpand: this.handleRowExpand,

View File

@@ -14,6 +14,14 @@ class SelectionProvider extends React.Component {
keyField: PropTypes.string.isRequired
}
constructor(props) {
super(props);
if (props.registerExposedAPI) {
const getSelected = () => this.getSelected();
props.registerExposedAPI(getSelected);
}
}
state = { selected: this.props.selectRow.selected || [] };
componentWillReceiveProps(nextProps) {
@@ -35,24 +43,20 @@ class SelectionProvider extends React.Component {
let currSelected = [...this.state.selected];
let result = true;
if (onSelect) {
const row = dataOperator.getRowByRowId(data, keyField, rowKey);
result = onSelect(row, checked, rowIndex, e);
if (mode === ROW_SELECT_SINGLE) { // when select mode is radio
currSelected = [rowKey];
} else if (checked) { // when select mode is checkbox
currSelected.push(rowKey);
} else {
currSelected = currSelected.filter(value => value !== rowKey);
}
this.setState(() => {
if (result === true || result === undefined) {
if (mode === ROW_SELECT_SINGLE) { // when select mode is radio
currSelected = [rowKey];
} else if (checked) { // when select mode is checkbox
currSelected.push(rowKey);
} else {
currSelected = currSelected.filter(value => value !== rowKey);
}
}
return { selected: currSelected };
});
if (onSelect) {
const row = dataOperator.getRowByRowId(data, keyField, rowKey);
onSelect(row, checked, rowIndex, e);
}
this.setState(() => ({ selected: currSelected }));
}
handleAllRowsSelect = (e, isUnSelect) => {
@@ -74,9 +78,8 @@ class SelectionProvider extends React.Component {
currSelected = selected.filter(s => typeof data.find(d => d[keyField] === s) === 'undefined');
}
let result;
if (onSelectAll) {
result = onSelectAll(
onSelectAll(
!isUnSelect,
dataOperator.getSelectedRows(
data,
@@ -85,10 +88,8 @@ class SelectionProvider extends React.Component {
),
e
);
if (Array.isArray(result)) {
currSelected = result;
}
}
this.setState(() => ({ selected: currSelected }));
}

View File

@@ -7,7 +7,6 @@ import SelectionHeaderCell from './row-selection/selection-header-cell';
import ExpandHeaderCell from './row-expand/expand-header-cell';
import withHeaderSelection from './row-selection/selection-header-cell-consumer';
import withHeaderExpansion from './row-expand/expand-header-cell-consumer';
import Const from './const';
const Header = (props) => {
const {
@@ -19,7 +18,8 @@ const Header = (props) => {
sortOrder,
selectRow,
onExternalFilter,
expandRow
expandRow,
bootstrap4
} = props;
let SelectionHeaderCellComp = () => null;
@@ -33,49 +33,37 @@ const Header = (props) => {
SelectionHeaderCellComp = withHeaderSelection(SelectionHeaderCell);
}
const isRenderExpandColumnInLeft = (
expandColumnPosition = Const.INDICATOR_POSITION_LEFT
) => expandColumnPosition === Const.INDICATOR_POSITION_LEFT;
const childrens = [
columns.map((column, i) => {
if (!column.hidden) {
const currSort = column.dataField === sortField;
const isLastSorting = column.dataField === sortField;
return (
<HeaderCell
index={ i }
key={ column.dataField }
column={ column }
onSort={ onSort }
sorting={ currSort }
onFilter={ onFilter }
onExternalFilter={ onExternalFilter }
sortOrder={ sortOrder }
isLastSorting={ isLastSorting }
/>);
}
return false;
})
];
if (!selectRow.hideSelectColumn) {
childrens.unshift(<SelectionHeaderCellComp key="selection" />);
}
if (expandRow.showExpandColumn) {
if (isRenderExpandColumnInLeft(expandRow.expandColumnPosition)) {
childrens.unshift(<ExpansionHeaderCellComp key="expansion" />);
} else {
childrens.push(<ExpansionHeaderCellComp key="expansion" />);
}
}
return (
<thead>
<tr className={ className }>
{ childrens }
<ExpansionHeaderCellComp />
{
!selectRow.hideSelectColumn ?
<SelectionHeaderCellComp /> : null
}
{
columns.map((column, i) => {
if (!column.hidden) {
const currSort = column.dataField === sortField;
const isLastSorting = column.dataField === sortField;
return (
<HeaderCell
index={ i }
bootstrap4={ bootstrap4 }
key={ column.dataField }
column={ column }
onSort={ onSort }
sorting={ currSort }
onFilter={ onFilter }
onExternalFilter={ onExternalFilter }
sortOrder={ sortOrder }
isLastSorting={ isLastSorting }
/>);
}
return false;
})
}
</tr>
</thead>
);
@@ -90,7 +78,8 @@ Header.propTypes = {
selectRow: PropTypes.object,
onExternalFilter: PropTypes.func,
className: PropTypes.string,
expandRow: PropTypes.object
expandRow: PropTypes.object,
bootstrap4: PropTypes.bool
};
export default Header;

View File

@@ -1,4 +1,3 @@
import _ from '../utils';
import ColumnResolver from './column-resolver';
export default ExtendBase =>
@@ -16,13 +15,4 @@ export default ExtendBase =>
isEmpty() {
return this.props.data.length === 0;
}
visibleRows() {
const { data, hiddenRows, keyField } = this.props;
if (!hiddenRows || hiddenRows.length === 0) return data;
return data.filter((row) => {
const key = _.get(row, keyField);
return !hiddenRows.includes(key);
});
}
};

View File

@@ -1,15 +1,7 @@
import EventEmitter from 'events';
import _ from '../utils';
export default ExtendBase =>
class RemoteResolver extends ExtendBase {
constructor(props) {
super(props);
this.remoteEmitter = new EventEmitter();
this.remoteEmitter.on('paginationChange', this.handleRemotePageChange);
this.remoteEmitter.on('isRemotePagination', this.isRemotePagination);
}
getNewestState = (state = {}) => {
let sortOrder;
let sortField;
@@ -55,10 +47,9 @@ export default ExtendBase =>
return remote === true || (_.isObject(remote) && remote.search) || this.isRemotePagination();
}
isRemotePagination = (e = {}) => {
isRemotePagination = () => {
const { remote } = this.props;
e.result = (remote === true || (_.isObject(remote) && remote.pagination));
return e.result;
return remote === true || (_.isObject(remote) && remote.pagination);
}
isRemoteFiltering = () => {

View File

@@ -10,7 +10,6 @@ export default class ExpandCell extends Component {
static propTypes = {
rowKey: PropTypes.any,
expanded: PropTypes.bool.isRequired,
expandable: PropTypes.bool.isRequired,
onRowExpand: PropTypes.func.isRequired,
expandColumnRenderer: PropTypes.func,
rowIndex: PropTypes.number,
@@ -34,12 +33,12 @@ export default class ExpandCell extends Component {
handleClick(e) {
const { rowKey, expanded, onRowExpand, rowIndex } = this.props;
e.stopPropagation();
onRowExpand(rowKey, !expanded, rowIndex, e);
}
render() {
const { expanded, expandable, expandColumnRenderer, tabIndex, rowKey } = this.props;
const { expanded, expandColumnRenderer, tabIndex } = this.props;
const attrs = {};
if (tabIndex !== -1) attrs.tabIndex = tabIndex;
@@ -47,10 +46,8 @@ export default class ExpandCell extends Component {
<td onClick={ this.handleClick } { ...attrs }>
{
expandColumnRenderer ? expandColumnRenderer({
expandable,
expanded,
rowKey
}) : (expandable ? (expanded ? '(-)' : '(+)') : '')
expanded
}) : (expanded ? '(-)' : '(+)')
}
</td>
);

View File

@@ -73,7 +73,7 @@ export default class SelectionCell extends Component {
<BootstrapContext.Consumer>
{
({ bootstrap4 }) => (
<td onClick={ this.handleClick } { ...attrs }>
<td data-row-selection onClick={ this.handleClick } { ...attrs }>
{
selectionRenderer ? selectionRenderer({
mode: inputType,

View File

@@ -1,4 +1,3 @@
/* eslint class-methods-use-this: 0 */
/* eslint react/prop-types: 0 */
/* eslint no-plusplus: 0 */
import React from 'react';
@@ -9,7 +8,6 @@ import SelectionCell from '../row-selection/selection-cell';
import shouldUpdater from './should-updater';
import eventDelegater from './event-delegater';
import RowPureContent from './row-pure-content';
import Const from '../const';
export default class RowAggregator extends shouldUpdater(eventDelegater(React.Component)) {
static propTypes = {
@@ -33,7 +31,6 @@ export default class RowAggregator extends shouldUpdater(eventDelegater(React.Co
if (
this.props.selected !== nextProps.selected ||
this.props.expanded !== nextProps.expanded ||
this.props.expandable !== nextProps.expandable ||
this.props.selectable !== nextProps.selectable ||
this.shouldUpdatedBySelfProps(nextProps)
) {
@@ -45,12 +42,6 @@ export default class RowAggregator extends shouldUpdater(eventDelegater(React.Co
return this.shouldUpdateRowContent;
}
isRenderExpandColumnInLeft(
expandColumnPosition = Const.INDICATOR_POSITION_LEFT
) {
return expandColumnPosition === Const.INDICATOR_POSITION_LEFT;
}
render() {
const {
row,
@@ -63,7 +54,6 @@ export default class RowAggregator extends shouldUpdater(eventDelegater(React.Co
selectRow,
expandRow,
expanded,
expandable,
selected,
selectable,
visibleColumnSize,
@@ -72,7 +62,7 @@ export default class RowAggregator extends shouldUpdater(eventDelegater(React.Co
} = this.props;
const key = _.get(row, keyField);
const { hideSelectColumn, clickToSelect } = selectRow;
const { showExpandColumn, expandColumnPosition } = expandRow;
const { showExpandColumn } = expandRow;
const newAttrs = this.delegate({ ...attrs });
if (clickToSelect || !!expandRow.renderer) {
@@ -81,59 +71,46 @@ export default class RowAggregator extends shouldUpdater(eventDelegater(React.Co
let tabIndexStart = (rowIndex * visibleColumnSize) + 1;
const childrens = [(
<RowPureContent
key="row"
row={ row }
columns={ columns }
keyField={ keyField }
rowIndex={ rowIndex }
shouldUpdate={ this.shouldUpdateRowContent }
tabIndexStart={ tabIndexCell ? tabIndexStart : -1 }
{ ...rest }
/>
)];
if (!hideSelectColumn) {
childrens.unshift((
<SelectionCell
{ ...selectRow }
key="selection-cell"
rowKey={ key }
rowIndex={ rowIndex }
selected={ selected }
disabled={ !selectable }
tabIndex={ tabIndexCell ? tabIndexStart++ : -1 }
/>
));
}
if (showExpandColumn) {
const expandCell = (
<ExpandCell
{ ...expandRow }
key="expand-cell"
rowKey={ key }
rowIndex={ rowIndex }
expanded={ expanded }
expandable={ expandable }
tabIndex={ tabIndexCell ? tabIndexStart++ : -1 }
/>
);
if (this.isRenderExpandColumnInLeft(expandColumnPosition)) {
childrens.unshift(expandCell);
} else {
childrens.push(expandCell);
}
}
return (
<tr
style={ style }
className={ className }
{ ...newAttrs }
>
{ childrens }
{
showExpandColumn ? (
<ExpandCell
{ ...expandRow }
rowKey={ key }
rowIndex={ rowIndex }
expanded={ expanded }
tabIndex={ tabIndexCell ? tabIndexStart++ : -1 }
/>
) : null
}
{
!hideSelectColumn
? (
<SelectionCell
{ ...selectRow }
rowKey={ key }
rowIndex={ rowIndex }
selected={ selected }
disabled={ !selectable }
tabIndex={ tabIndexCell ? tabIndexStart++ : -1 }
/>
)
: null
}
<RowPureContent
row={ row }
columns={ columns }
keyField={ keyField }
rowIndex={ rowIndex }
shouldUpdate={ this.shouldUpdateRowContent }
tabIndexStart={ tabIndexCell ? tabIndexStart : -1 }
{ ...rest }
/>
</tr>
);
}

View File

@@ -20,19 +20,6 @@ export default ExtendBase =>
);
}
// Only use for simple-row
shouldUpdateByColumnsForSimpleCheck(nextProps) {
if (this.props.columns.length !== nextProps.columns.length) {
return true;
}
for (let i = 0; i < this.props.columns.length; i += 1) {
if (this.props.columns[i].hidden !== nextProps.columns[i].hidden) {
return true;
}
}
return false;
}
shouldUpdatedByNormalProps(nextProps) {
const shouldUpdate =
this.props.rowIndex !== nextProps.rowIndex ||

View File

@@ -15,8 +15,7 @@ class SimpleRow extends shouldUpdater(eventDelegater(Component)) {
shouldComponentUpdate(nextProps) {
this.shouldUpdateRowContent = false;
this.shouldUpdateRowContent =
this.shouldUpdateChild(nextProps) || this.shouldUpdateByColumnsForSimpleCheck(nextProps);
this.shouldUpdateRowContent = this.shouldUpdateChild(nextProps);
if (this.shouldUpdateRowContent) return true;
return this.shouldUpdatedBySelfProps(nextProps);

View File

@@ -0,0 +1 @@
@import "./sticky";

View File

@@ -0,0 +1,56 @@
.react-bootstrap-table {
.table-sticky {
thead,
tbody {
display: block;
width: 100%;
tr {
display: inline-flex;
width: 100%;
th,
td {
width: 100%;
&[data-row-selection] {
width: 30px;
min-width: 30px;
}
}
}
}
tbody {
max-height: 400px;
overflow-y: auto;
}
}
// Disable double strips when table was displayed in bordered.
table.table-sticky.table-bordered {
border-left: 0;
thead,
tbody {
tr {
th {
border-top: 0;
border-right: 0;
}
td {
border-top: 0;
border-right: 0;
}
&:last-child {
td {
border-bottom: 0;
}
}
}
}
}
}

View File

@@ -1,3 +1,5 @@
@import "partials/all";
.react-bootstrap-table {
table {
@@ -55,8 +57,10 @@
content: "\2193";
}
th[data-row-selection] {
th[data-row-selection],
td[data-row-selection] {
width: 30px;
min-width: 30px;
}
th > .selection-input-4,

View File

@@ -60,6 +60,26 @@ describe('BootstrapTable', () => {
});
});
describe('when props.registerExposedAPI is defined', () => {
const registerExposedAPI = jest.fn();
beforeEach(() => {
registerExposedAPI.mockClear();
wrapper = shallow(
<BootstrapTable
keyField="id"
columns={ columns }
data={ data }
registerExposedAPI={ registerExposedAPI }
/>
);
});
it('should call props.registerExposedAPI correctly', () => {
expect(registerExposedAPI).toHaveBeenCalledTimes(1);
expect(registerExposedAPI.mock.calls[0][0].name).toEqual('getData');
});
});
describe('when props.classes was defined', () => {
const classes = 'foo';

View File

@@ -225,31 +225,4 @@ describe('Context', () => {
expect(wrapper.instance().PaginationContext).toBeDefined();
});
});
describe('if registerExposedAPI props is defined', () => {
const registerExposedAPI = jest.fn();
beforeEach(() => {
const PaginationContext = React.createContext();
const paginator = {
createContext: jest.fn().mockReturnValue({
Provider: PaginationContext.Provider,
Consumer: PaginationContext.Consumer
})
};
wrapper = shallow(
<BootstrapTable
keyField={ keyField }
data={ data }
columns={ columns }
pagination={ paginator }
registerExposedAPI={ registerExposedAPI }
/>
);
wrapper.render();
});
it('should call props.registerExposedAPI correctly', () => {
expect(registerExposedAPI).toHaveBeenCalledTimes(1);
});
});
});

View File

@@ -254,33 +254,5 @@ describe('Header', () => {
expect(wrapper.find(ExpandHeaderCell).length).toBe(1);
});
});
describe('if props.expandRow.showExpandColumn is true but props.expandRow.expandColumnPosition is "right"', () => {
beforeEach(() => {
const expandRow = {
renderer: jest.fn(),
showExpandColumn: true,
expandColumnPosition: Const.INDICATOR_POSITION_RIGHT
};
wrapper = mount(
<ExpansionContext.Provider
data={ data }
keyField={ keyField }
expandRow={ expandRow }
>
<Header
{ ...mockHeaderResolvedProps }
columns={ columns }
expandRow={ expandRow }
/>
</ExpansionContext.Provider>
);
});
it('should render expansion column correctly', () => {
const header = wrapper.find(Header).children();
expect(header.children().children().last().find(ExpandHeaderCell)).toHaveLength(1);
});
});
});
});

View File

@@ -25,51 +25,6 @@ describe('TableResolver', () => {
const BootstrapTableMock = extendTo(ExtendBase);
let wrapper;
describe('visibleRows', () => {
describe('if hiddenRows prop is not existing', () => {
beforeEach(() => {
const mockElement = React.createElement(BootstrapTableMock, {
data, columns, keyField
}, null);
wrapper = shallow(mockElement);
});
it('should return correct data', () => {
expect(wrapper.instance().visibleRows()).toEqual(data);
});
});
describe('if hiddenRows prop is an empty array', () => {
beforeEach(() => {
const mockElement = React.createElement(BootstrapTableMock, {
data, columns, keyField, hiddenRows: []
}, null);
wrapper = shallow(mockElement);
});
it('should return correct data', () => {
expect(wrapper.instance().visibleRows()).toEqual(data);
});
});
describe('if hiddenRows prop is not an empty array', () => {
const hiddenRows = [1];
beforeEach(() => {
const mockElement = React.createElement(BootstrapTableMock, {
data, columns, keyField, hiddenRows
}, null);
wrapper = shallow(mockElement);
});
it('should return correct data', () => {
const result = wrapper.instance().visibleRows();
expect(result).toHaveLength(data.length - hiddenRows.length);
expect(result).toEqual(data.filter(d => !hiddenRows.includes(d.id)));
});
});
});
describe('validateProps', () => {
describe('if keyField is defined and columns is all visible', () => {
beforeEach(() => {

View File

@@ -9,7 +9,6 @@ import bindExpansion from '../../src/row-expand/row-consumer';
import ExpandCell from '../../src/row-expand/expand-cell';
import SelectionCell from '../../src/row-selection/selection-cell';
import RowAggregator from '../../src/row/aggregate-row';
import Const from '../../src/const';
describe('Row Aggregator', () => {
let wrapper;
@@ -158,27 +157,6 @@ describe('Row Aggregator', () => {
expect(expandCell.props().expanded).toEqual(rowAggregator.props().expanded);
});
});
describe('if props.expandRow.showExpandColumn is true but props.expandRow.expandColumnPosition is "right"', () => {
beforeEach(() => {
const expandRow = {
renderer: jest.fn(),
showExpandColumn: true,
expandColumnPosition: Const.INDICATOR_POSITION_RIGHT
};
wrapper = mount(
<ExpansionContext.Provider data={ data } keyField={ keyField } expandRow={ expandRow }>
<RowAggregatorWithExpansion { ...getBaseProps() } />
</ExpansionContext.Provider>
);
});
it('should render expansion column correctly', () => {
rowAggregator = wrapper.find(RowAggregator);
expect(rowAggregator).toHaveLength(1);
expect(rowAggregator.children().children().last().type()).toEqual(ExpandCell);
});
});
});
describe('createClickEventHandler', () => {

View File

@@ -104,50 +104,6 @@ describe('Row shouldUpdater', () => {
});
});
describe('shouldUpdateByColumnsForSimpleCheck', () => {
describe('when nextProps.columns.length is not eq props.columns.length', () => {
beforeEach(() => {
props = {
columns: [{ dataField: 'price', text: 'Price' }]
};
wrapper = shallow(<DummyComponent { ...props } />);
});
it('should return true', () => {
nextProps = { ...props, columns: [...props.columns, { dataField: 'name', text: 'Name' }] };
expect(wrapper.instance().shouldUpdateByColumnsForSimpleCheck(nextProps)).toBeTruthy();
});
});
describe('when any nextProps.columns.hidden is change', () => {
beforeEach(() => {
props = {
columns: [{ dataField: 'price', text: 'Price' }]
};
wrapper = shallow(<DummyComponent { ...props } />);
});
it('should return true', () => {
nextProps = { ...props, columns: [{ dataField: 'price', text: 'Price', hidden: true }] };
expect(wrapper.instance().shouldUpdateByColumnsForSimpleCheck(nextProps)).toBeTruthy();
});
});
describe('if any nextProps.columns.hidden is not change and column length is same', () => {
beforeEach(() => {
props = {
columns: [{ dataField: 'price', text: 'Price' }]
};
wrapper = shallow(<DummyComponent { ...props } />);
});
it('should return false', () => {
nextProps = { ...props, columns: [...props.columns] };
expect(wrapper.instance().shouldUpdateByColumnsForSimpleCheck(nextProps)).toBeFalsy();
});
});
});
describe('shouldUpdatedByNormalProps', () => {
describe('when nextProps.rowIndex is not eq props.rowIndex', () => {
beforeEach(() => {