Compare commits

..

92 Commits

Author SHA1 Message Date
AllenFang
40c5ae7459 Publish
- react-bootstrap-table2-editor@1.2.4
 - react-bootstrap-table2-example@1.0.26
 - react-bootstrap-table2-toolkit@2.0.1
 - react-bootstrap-table-next@3.1.4
2019-06-10 20:53:14 +08:00
Allen
3747c36039 Merge pull request #973 from react-bootstrap-table/develop
20190610 release
2019-06-10 20:51:10 +08:00
AllenFang
0d0d1a8913 fix #947 2019-06-08 17:19:39 +08:00
AllenFang
db612eaa99 fix #946 2019-06-08 16:47:14 +08:00
Allen
4d76d88e9a fix #945 (#967) 2019-06-08 13:11:49 +08:00
William Laugesen
1cd31dc54c Added Prop to csv/exporter.js to allow overriding of the Blob's default type (#958) 2019-06-07 13:18:50 +08:00
Bill Parrott
4ec02b294a set tabindex to 0 for table headers; fixes #955 (#965) 2019-06-05 20:13:35 +08:00
AllenFang
60eb47dc9e Publish
- react-bootstrap-table2-overlay@2.0.0
 - react-bootstrap-table2-toolkit@2.0.0
 - react-bootstrap-table-next@3.1.3
2019-05-19 21:19:50 +08:00
Allen
d74ecb63b4 Merge pull request #949 from react-bootstrap-table/develop
20190519 release
2019-05-19 21:14:49 +08:00
AllenFang
2c6cc915f0 fix #932 2019-05-19 17:05:32 +08:00
AllenFang
a1457dfe59 fix #929 2019-05-19 16:28:36 +08:00
AllenFang
036c3fdc32 fix #940 2019-05-19 16:21:14 +08:00
AllenFang
55eea6f337 try to fix #916 2019-05-19 16:12:53 +08:00
Rita Zhao
7c259cd1ee Add aria-label to search input (#931) 2019-05-12 12:58:53 +08:00
Bhathiya Perera
1e164bb3f4 Update row-selection.md (#937) 2019-05-12 12:53:14 +08:00
AllenFang
8a7c1def5b Publish
- react-bootstrap-table2-example@1.0.25
 - react-bootstrap-table2-toolkit@1.4.2
 - react-bootstrap-table-next@3.1.2
2019-04-29 21:20:42 +08:00
Allen
77b8ed53bf Merge pull request #926 from react-bootstrap-table/develop
20190427 release
2019-04-29 21:19:37 +08:00
AllenFang
6bc54ef3ec fix test fail 2019-04-27 16:52:03 +08:00
AllenFang
6168bd7532 fix #905 2019-04-27 16:11:55 +08:00
AllenFang
36fa9b8630 fix #908 2019-04-27 15:38:28 +08:00
AllenFang
737922a5a4 fix #904 2019-04-27 14:58:57 +08:00
AllenFang
0f37fae23d fix #899 2019-04-27 14:38:41 +08:00
Kirill
ce7e05d7f9 Fix default prop tableId for SearchBar (#914) 2019-04-27 13:53:47 +08:00
AllenFang
067006eb72 fix #920 2019-04-27 13:46:47 +08:00
Utkarsh Gupta
8fa10e3b6f Added missed attribute (#913)
You missed 'onlyOneExpanding: true' in the source code.
2019-04-27 13:37:09 +08:00
AllenFang
e2e6c51d40 Publish
- react-bootstrap-table2-example@1.0.24
 - react-bootstrap-table2-filter@1.1.9
 - react-bootstrap-table2-paginator@2.0.6
 - react-bootstrap-table2-toolkit@1.4.1
 - react-bootstrap-table-next@3.1.1
2019-04-15 19:45:38 +08:00
Allen
fb724331d3 Merge pull request #900 from react-bootstrap-table/develop
20180408 release
2019-04-15 19:38:41 +08:00
AllenFang
160dede412 fix #898 2019-04-07 17:33:00 +08:00
AllenFang
363a43251f fix #891 2019-04-07 16:49:03 +08:00
AllenFang
8ad0e65679 Merge branch 'SmaranSingh-master' into develop 2019-04-07 14:32:41 +08:00
AllenFang
6d5cca0047 optimize selection option equals 2019-04-07 14:31:43 +08:00
AllenFang
204e75c9c2 Merge branch 'master' of https://github.com/SmaranSingh/react-bootstrap-table2 into SmaranSingh-master 2019-04-07 14:30:21 +08:00
AllenFang
fc27c56cbb Merge branch 'Jayboy75-develop' into develop 2019-04-07 14:05:40 +08:00
AllenFang
8436edba7e no inline-block on label element 2019-04-07 14:03:42 +08:00
SmaranSingh
3606fa3b7b Update select.js 2019-04-04 16:11:01 +05:30
SmaranSingh
73e8701bde Update select.js 2019-04-04 15:37:34 +05:30
Jay Staudt
6d2493d537 revert page-button title 2019-04-02 14:53:52 -04:00
Jay Staudt
1a1f6969cb adjustments via eslint 2019-04-02 14:42:47 -04:00
Jay Staudt
d47a3757b8 wrap search bar with label and hidden text 2019-04-02 14:10:14 -04:00
Jay Staudt
ba7512969e add non-redundant titles to page buttons 2019-04-02 14:09:53 -04:00
Jay Staudt
955ee17939 wrap filter components with labels and hidden text 2019-04-02 14:09:20 -04:00
AllenFang
497bf44192 Publish
- react-bootstrap-table2-editor@1.2.3
 - react-bootstrap-table2-example@1.0.23
 - react-bootstrap-table2-filter@1.1.8
 - react-bootstrap-table-next@3.1.0
2019-04-02 21:33:49 +08:00
Allen
fcefcf8c84 Merge pull request #886 from react-bootstrap-table/develop
20190331 release
2019-04-02 21:25:03 +08:00
Allen
04e3af0bbb Merge pull request #861 from react-bootstrap-table/feature/row-expand-animate
Feature/row expand animate
2019-03-31 16:02:13 +08:00
AllenFang
9f47fa009c lock version 2019-03-31 15:33:43 +08:00
Alek Lefebvre
0edf9c8891 fix #808 (#874) 2019-03-31 15:17:57 +08:00
AllenFang
df5024892c Publish
- react-bootstrap-table2-example@1.0.22
 - react-bootstrap-table2-paginator@2.0.5
 - react-bootstrap-table-next@3.0.3
2019-03-26 20:41:04 +08:00
Allen
4448c3f28c Merge pull request #875 from react-bootstrap-table/develop
20190326 release
2019-03-26 20:39:13 +08:00
AllenFang
196ae33295 fix #859 2019-03-25 23:07:22 +08:00
AllenFang
7f1b7a6c97 fix #838 2019-03-24 20:52:26 +08:00
AllenFang
a6ccafcc75 fix #866 2019-03-24 16:55:56 +08:00
AllenFang
06d87299a3 Publish
- react-bootstrap-table2-example@1.0.21
 - react-bootstrap-table2-filter@1.1.7
 - react-bootstrap-table2-toolkit@1.4.0
 - react-bootstrap-table-next@3.0.2
2019-03-18 00:31:24 +08:00
Allen
5891ec1b93 Merge pull request #862 from react-bootstrap-table/develop
20190317 release
2019-03-18 00:28:47 +08:00
AllenFang
c5d9e04c2c fix #817 2019-03-17 16:30:39 +08:00
AllenFang
dba3da28c1 Merge branch 'YassienW-animate-row-expansion' into feature/row-expand-animate 2019-03-17 15:24:07 +08:00
AllenFang
a0e09cd804 fix conflicts 2019-03-17 15:20:16 +08:00
AllenFang
d0e70f7246 fix #852 2019-03-17 14:43:39 +08:00
henning-kvinnesland
b93c683f17 Fix typo. (#855)
`to cusom the sort caret` => `to customize the sort-caret`
2019-03-17 13:30:35 +08:00
henning-kvinnesland
f80e1ea66c Fix typo. (#856)
`chagne` => `change`
2019-03-17 13:30:21 +08:00
AllenFang
7642bfa1a3 fix #849 2019-03-17 13:29:17 +08:00
Yassien
8f304a849f Animation now works with custom expand management 2019-03-16 19:03:22 +02:00
AllenFang
956f1cef4d Publish
- react-bootstrap-table2-example@1.0.20
 - react-bootstrap-table2-filter@1.1.6
 - react-bootstrap-table2-paginator@2.0.4
 - react-bootstrap-table2-toolkit@1.3.2
 - react-bootstrap-table-next@3.0.1
2019-03-10 13:38:21 +08:00
Allen
c45deee590 Merge pull request #846 from react-bootstrap-table/develop
20190310 release
2019-03-10 13:37:02 +08:00
AllenFang
2aab4301dd fix #835 2019-03-09 23:01:21 +08:00
AllenFang
43aa280761 Merge branch 'develop' of https://github.com/react-bootstrap-table/react-bootstrap-table2 into develop 2019-03-09 23:00:59 +08:00
AllenFang
3af30a0265 fix #840 2019-03-09 22:35:49 +08:00
AllenFang
4b8b8b261e update story 2019-03-09 22:31:24 +08:00
Norbert Nemeth
e44782f222 fix #863 - expanded row column span does not update (#837) 2019-03-09 18:46:04 +08:00
AllenFang
921e8c7ecc fix #830 2019-03-09 18:18:20 +08:00
AllenFang
a3b3ce0dc4 Merge branch 'develop' of https://github.com/react-bootstrap-table/react-bootstrap-table2 into develop 2019-03-09 15:52:37 +08:00
AllenFang
e9f08d278d fix #826 2019-03-09 15:52:10 +08:00
Sartaj Singh Baveja
b4973c826c Minor update to docs (#841) 2019-03-06 22:28:41 +08:00
Yassien
33c026c7e2 Added original padding without breaking the animation 2019-02-25 13:01:42 +02:00
AllenFang
6cac7f6dc8 Publish
- react-bootstrap-table2-example@1.0.19
 - react-bootstrap-table2-filter@1.1.5
 - react-bootstrap-table2-toolkit@1.3.1
 - react-bootstrap-table-next@3.0.0
2019-02-24 17:01:52 +08:00
Allen
da5b93c3cf Merge pull request #818 from react-bootstrap-table/develop
20190224 release
2019-02-24 16:59:43 +08:00
AllenFang
3ffccce1fe fix #817 2019-02-24 16:20:44 +08:00
AllenFang
09f21e8130 allow to custom className on clear search and export csv button 2019-02-24 16:11:38 +08:00
AllenFang
bf0c5c43a2 fix #735 2019-02-24 15:50:13 +08:00
AllenFang
c01f45a719 fix #789 2019-02-24 14:56:27 +08:00
AllenFang
d26c13b9be fix #815 2019-02-24 14:11:05 +08:00
Yassien
d84fd5c801 CSS Animation for row expansion 2019-02-23 22:40:05 +02:00
AllenFang
8e940112f5 fix #811 2019-02-23 16:13:40 +08:00
AllenFang
6070d150a9 Publish
- react-bootstrap-table2-example@1.0.18
 - react-bootstrap-table2-paginator@2.0.3
 - react-bootstrap-table2-toolkit@1.3.0
 - react-bootstrap-table-next@2.2.0
2019-02-20 23:08:26 +08:00
Allen
dab6f1b206 Merge pull request #810 from react-bootstrap-table/develop
20190220 release
2019-02-20 23:05:03 +08:00
Allen
2a497194e7 Merge pull request #801 from react-bootstrap-table/enhance/795
Implement PaginationTotalStandalone
2019-02-17 17:41:57 +08:00
AllenFang
f5f17897fd add story for PaginationTotalStandalone 2019-02-17 17:29:56 +08:00
AllenFang
2932b8a1b8 fix #795 2019-02-17 17:29:56 +08:00
AllenFang
93103e5ca0 exclude examples from coverage 2019-02-17 17:17:56 +08:00
AllenFang
a7c2a49182 fix #793 2019-02-17 15:25:32 +08:00
Allen
cd27ff98ff Merge pull request #800 from react-bootstrap-table/feat/723
Implement Column Toggle(723)
2019-02-17 15:24:17 +08:00
AllenFang
4d815894e6 add stories for #723 2019-02-17 14:55:44 +08:00
AllenFang
d9ff201373 fix #723 2019-02-17 14:55:17 +08:00
105 changed files with 3694 additions and 894 deletions

View File

@@ -33,6 +33,7 @@
* [pagination](#pagination)
* [filter](#filter)
* [onTableChange](#onTableChange)
* [onDataSizeChange](#onDataSizeChange)
### <a name='keyField'>keyField(**required**) - [String]</a>
Tells `react-bootstrap-table2` which column is unique.
@@ -318,3 +319,19 @@ Following is a shape of `newState`
}
}
```
### <a name='onDataSizeChange'>onDataSizeChange - [Function]</a>
This callback function will be called only when data size change by search/filter etc. This function have one argument which is an object contains below props:
* `dataSize`: The new data size
```js
handleDataChange = ({ dataSize }) => {
this.setState({ rowCount: dataSize });
}
<BootstrapTable
onDataSizeChange={ handleDataChange }
....
/>
```

View File

@@ -69,7 +69,7 @@ const cellEdit: {
// omit...
beforeSaveCell(oldValue, newValue, row, column, done) {
setTimeout(() => {
if (confirm('Do you want to accep this change?')) {
if (confirm('Do you want to accept this change?')) {
done(); // contine to save the changes
} else {
done(false); // reject the changes

View File

@@ -164,7 +164,7 @@ Enable the column sort via a `true` value given.
```
## <a name='sortCaret'>column.sortCaret - [Function]</a>
Use`column.sortCaret` to custom the sort caret. This callback function accept two arguments: `order` and `column`
Use`column.sortCaret` to customize the sort caret. This callback function accept two arguments: `order` and `column`
```js
{

View File

@@ -23,7 +23,7 @@ Currently, **I still can't implement all the mainly features in legacy `react-bo
* [`react-bootstrap-table2-overlay`](https://www.npmjs.com/package/react-bootstrap-table2-overlay)
* Overlay/Loading Addons
* [`react-bootstrap-table2-toolkit`](https://www.npmjs.com/package/react-bootstrap-table2-toolkit)
* Table Toolkits, like search, csv etc.
* Table Toolkits, like search, csv, column toggle etc.
This can help your application with less bundled size and also help `react-bootstrap-table2` have clean design to avoid handling to much logic in kernel module(SRP). Hence, which means you probably need to install above addons when you need specific features.

View File

@@ -2,7 +2,7 @@
# Row expand
`react-bootstrap-table2` supports the row expand feature. By passing prop `expandRow` to enable this functionality.
> Default is click to expand/collapse a row. In addition, we don't support any way to chagne this mechanism!
> Default is click to expand/collapse a row. In addition, we don't support any way to change this mechanism!
## Required
* [renderer (**required**)](#renderer)

View File

@@ -1,6 +1,6 @@
# Row selection
`react-bootstrap-table2` supports the row selection feature. By passing prop `selectRow` to enable row selection. When you enable this feature, `react-bootstrap-table2` will append a new selection column at first.
`react-bootstrap-table2` supports the row selection feature. By passing prop `selectRow` to enable row selection. When you enable this feature, `react-bootstrap-table2` will prepend a new selection column.
## Required
* [mode (**required**)](#mode)
@@ -16,10 +16,13 @@
* [clickToEdit](#clickToEdit)
* [onSelect](#onSelect)
* [onSelectAll](#onSelectAll)
* [selectColumnPosition](#selectColumnPosition)
* [hideSelectColumn](#hideSelectColumn)
* [hideSelectAll](#hideSelectAll)
* [selectionRenderer](#selectionRenderer)
* [selectionHeaderRenderer](#selectionHeaderRenderer)
* [headerColumnStyle](#headerColumnStyle)
* [selectColumnStyle](#selectColumnStyle)
### <a name="mode">selectRow.mode - [String]</a>
@@ -176,7 +179,7 @@ Provide a callback function which allow you to custom the checkbox/radio box. Th
```js
const selectRow = {
mode: 'checkbox',
selectionRenderer: ({ mode, checked, disabled }) => (
selectionRenderer: ({ mode, checked, disabled, rowIndex }) => (
// ....
)
};
@@ -198,6 +201,67 @@ const selectRow = {
> By default, `react-bootstrap-table2` will help you to handle the click event, it's not necessary to handle again by developer.
### <a name='headerColumnStyle'>selectRow.headerColumnStyle - [Object | Function]</a>
A way to custome the selection header cell. `headerColumnStyle` not only accept a simple style object but also a callback function for more flexible customization:
### Style Object
```js
const selectRow = {
mode: 'checkbox',
headerColumnStyle: { backgroundColor: 'blue' }
};
```
### Callback Function
```js
const selectRow = {
mode: 'checkbox',
headerColumnStyle: (status) => (
// status available value is checked, indeterminate and unchecked
return { backgroundColor: 'blue' };
)
};
```
### <a name='selectColumnStyle'>selectRow.selectColumnStyle - [Object | Function]</a>
A way to custome the selection cell. `selectColumnStyle` not only accept a simple style object but also a callback function for more flexible customization:
### Style Object
```js
const selectRow = {
mode: 'checkbox',
selectColumnStyle: { backgroundColor: 'blue' }
};
```
### Callback Function
If a callback function present, you can get below information to custom the selection cell:
* `checked`: Whether current row is seleccted or not
* `disabled`: Whether current row is disabled or not
* `rowIndex`: Current row index
* `rowKey`: Current row key
```js
const selectRow = {
mode: 'checkbox',
selectColumnStyle: ({
checked,
disabled,
rowIndex,
rowKey
}) => (
// ....
return { backgroundColor: 'blue' };
)
};
```
### <a name='onSelect'>selectRow.onSelect - [Function]</a>
This callback function will be called when a row is select/unselect and pass following three arguments:
`row`, `isSelect`, `rowIndex` and `e`.
@@ -249,6 +313,16 @@ const selectRow = {
};
```
### <a name='selectColumnPosition'>selectRow.selectColumnPosition - [String]</a>
Default is `left`. You can give this as `right` for rendering selection column in the right side.
```js
const selectRow = {
mode: 'checkbox',
selectColumnPosition: 'right'
};
```
### <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

@@ -89,7 +89,8 @@
"jest": {
"collectCoverageFrom": [
"packages/*/src/**/*.js",
"packages/*/index.js"
"packages/*/index.js",
"!packages/react-bootstrap-table2-example/**/*.js"
],
"roots": [
"<rootDir>/packages"

View File

@@ -89,7 +89,10 @@ const columns = [
In the following, we go though all the predefined editors:
### Dropdown Editor
Dropdown editor give a select menu to choose a data from a list, the `editor.options` is required property for dropdown editor.
Dropdown editor give a select menu to choose a data from a list. When use dropdown editor, either `editor.options` or `editor.getOptions` should be required prop.
#### editor.options
This is most simple case for assign the dropdown options data directly.
```js
import { Type } from 'react-bootstrap-table2-editor';
@@ -119,6 +122,46 @@ const columns = [
}];
```
#### editor.getOptions
It is much flexible which accept a function and you can assign the dropdown options dynamically.
There are two case for `getOptions`:
* *Synchronous*: Just return the options array in `getOptions` callback function
* *Asynchronous*: Call `setOptions` function argument when you get the options from remote.
```js
// Synchronous
const columns = [
..., {
dataField: 'type',
text: 'Job Type',
editor: {
type: Type.SELECT,
getOptions: () => [.....]
}
}];
// Asynchronous
const columns = [
..., {
dataField: 'type',
text: 'Job Type',
editor: {
type: Type.SELECT,
getOptions: (setOptions) => {
setTimeout(() => setOptions([...]), 1500);
}
}
}];
```
[here](https://react-bootstrap-table.github.io/react-bootstrap-table2/storybook/index.html?selectedKind=Cell%20Editing&selectedStory=Dropdown%20Editor%20with%20Dynamic%20Options) is an online example.
### Date Editor
Date editor is use `<input type="date">`, the configuration is very simple:
@@ -132,7 +175,7 @@ const columns = [
if (typeof cell !== 'object') {
dateObj = new Date(cell);
}
return `${('0' + dateObj.getDate()).slice(-2)}/${('0' + (dateObj.getMonth() + 1)).slice(-2)}/${dateObj.getFullYear()}`;
return `${('0' + dateObj.getUTCDate()).slice(-2)}/${('0' + (dateObj.getUTCMonth() + 1)).slice(-2)}/${dateObj.getUTCFullYear()}`;
},
editor: {
type: Type.DATE

View File

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

View File

@@ -4,6 +4,15 @@ import cs from 'classnames';
import PropTypes from 'prop-types';
class DropDownEditor extends Component {
constructor(props) {
super(props);
let options = props.options;
if (props.getOptions) {
options = props.getOptions(this.setOptions.bind(this)) || [];
}
this.state = { options };
}
componentDidMount() {
const { defaultValue, didMount } = this.props;
this.select.value = defaultValue;
@@ -11,12 +20,16 @@ class DropDownEditor extends Component {
if (didMount) didMount();
}
setOptions(options) {
this.setState({ options });
}
getValue() {
return this.select.value;
}
render() {
const { defaultValue, didMount, className, options, ...rest } = this.props;
const { defaultValue, didMount, getOptions, className, ...rest } = this.props;
const editorClass = cs('form-control editor edit-select', className);
const attr = {
@@ -31,7 +44,7 @@ class DropDownEditor extends Component {
defaultValue={ defaultValue }
>
{
options.map(({ label, value }) => (
this.state.options.map(({ label, value }) => (
<option key={ value } value={ value }>{ label }</option>
))
}
@@ -52,13 +65,16 @@ DropDownEditor.propTypes = {
label: PropTypes.string,
value: PropTypes.any
}))
]).isRequired,
didMount: PropTypes.func
]),
didMount: PropTypes.func,
getOptions: PropTypes.func
};
DropDownEditor.defaultProps = {
className: '',
defaultValue: '',
style: {},
didMount: undefined
options: [],
didMount: undefined,
getOptions: undefined
};
export default DropDownEditor;

View File

@@ -9,6 +9,7 @@ const sourceStylePath = path.join(__dirname, '../../react-bootstrap-table2/style
const paginationStylePath = path.join(__dirname, '../../react-bootstrap-table2-paginator/style');
const filterStylePath = path.join(__dirname, '../../react-bootstrap-table2-filter/style');
const toolkitSourcePath = path.join(__dirname, '../../react-bootstrap-table2-toolkit/index.js');
const toolkitStylePath = path.join(__dirname, '../../react-bootstrap-table2-toolkit/style');
const storyPath = path.join(__dirname, '../stories');
const examplesPath = path.join(__dirname, '../examples');
const srcPath = path.join(__dirname, '../src');
@@ -43,7 +44,13 @@ const loaders = [{
}, {
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader'],
include: [storyPath, sourceStylePath, paginationStylePath, filterStylePath],
include: [
storyPath,
sourceStylePath,
paginationStylePath,
filterStylePath,
toolkitStylePath
],
}, {
test: /\.(jpg|png|woff|woff2|eot|ttf|svg)$/,
loader: 'url-loader?limit=100000',

View File

@@ -45,8 +45,12 @@ class ExposedFunctionTable extends React.Component {
console.log(this.node.table.props.data);
}
handleGetCurrentData = () => {
console.log(this.node.table.props.data);
}
handleGetSelectedData = () => {
console.log(this.node.selectionContext.state.selected);
console.log(this.node.selectionContext.selected);
}
handleGetExpandedData = () => {
@@ -117,7 +121,7 @@ export default class ExposedFunctionTable extends React.Component {
}
handleGetSelectedData = () => {
console.log(this.node.selectionContext.state.selected);
console.log(this.node.selectionContext.selected);
}
handleGetExpandedData = () => {

View File

@@ -0,0 +1,81 @@
/* eslint react/prop-types: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import ToolkitProvider, { ColumnToggle } from 'react-bootstrap-table2-toolkit';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const { ToggleList } = ColumnToggle;
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';
import ToolkitProvider, { ColumnToggle } from 'react-bootstrap-table2-toolkit';
const { ToggleList } = ColumnToggle;
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
<ToolkitProvider
keyField="id"
data={ products }
columns={ columns }
columnToggle
>
{
props => (
<div>
<ToggleList { ...props.columnToggleProps } />
<hr />
<BootstrapTable
{ ...props.baseProps }
/>
</div>
)
}
</ToolkitProvider>
`;
export default () => (
<div>
<ToolkitProvider
keyField="id"
data={ products }
columns={ columns }
columnToggle
>
{
props => (
<div>
<ToggleList { ...props.columnToggleProps } />
<hr />
<BootstrapTable
{ ...props.baseProps }
/>
</div>
)
}
</ToolkitProvider>
<Code>{ sourceCode }</Code>
</div>
);

View File

@@ -0,0 +1,90 @@
/* eslint react/prop-types: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import ToolkitProvider, { Search, CSVExport } from 'react-bootstrap-table2-toolkit';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const { SearchBar, ClearSearchButton } = Search;
const { ExportCSVButton } = CSVExport;
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';
import ToolkitProvider, { Search, CSVExport } from 'react-bootstrap-table2-toolkit';
const { SearchBar, ClearSearchButton } = Search;
const { ExportCSVButton } = CSVExport;
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
<ToolkitProvider
keyField="id"
data={ products }
columns={ columns }
search
>
{
props => (
<div>
<h3>Input something at below input field:</h3>
<SearchBar { ...props.searchProps } />
<ClearSearchButton { ...props.searchProps } />
<hr />
<BootstrapTable
{ ...props.baseProps }
/>
<ExportCSVButton { ...props.csvProps }>Export CSV!!</ExportCSVButton>
</div>
)
}
</ToolkitProvider>
`;
export default () => (
<div>
<ToolkitProvider
keyField="id"
data={ products }
columns={ columns }
search
>
{
props => (
<div>
<h3>Input something at below input field:</h3>
<SearchBar { ...props.searchProps } />
<ClearSearchButton { ...props.searchProps } />
<hr />
<BootstrapTable
{ ...props.baseProps }
/>
<ExportCSVButton { ...props.csvProps }>Export CSV!!</ExportCSVButton>
</div>
)
}
</ToolkitProvider>
<Code>{ sourceCode }</Code>
</div>
);

View File

@@ -18,6 +18,11 @@ class QualityRanger extends React.Component {
static defaultProps = {
value: 0
}
componentDidMount() {
this.range.focus();
}
getValue() {
return parseInt(this.range.value, 10);
}

View File

@@ -23,7 +23,7 @@ const columns = [{
if (typeof cell !== 'object') {
dateObj = new Date(cell);
}
return `${('0' + dateObj.getDate()).slice(-2)}/${('0' + (dateObj.getMonth() + 1)).slice(-2)}/${dateObj.getFullYear()}`;
return `${('0' + dateObj.getUTCDate()).slice(-2)}/${('0' + (dateObj.getUTCMonth() + 1)).slice(-2)}/${dateObj.getUTCFullYear()}`;
},
editor: {
type: Type.DATE
@@ -48,7 +48,7 @@ const columns = [{
if (typeof cell !== 'object') {
dateObj = new Date(cell);
}
return \`$\{('0' + dateObj.getDate()).slice(-2)}/$\{('0' + (dateObj.getMonth() + 1)).slice(-2)}/$\{dateObj.getFullYear()}\`;
return \`$\{('0' + dateObj.getUTCDate()).slice(-2)}/$\{('0' + (dateObj.getUTCMonth() + 1)).slice(-2)}/$\{dateObj.getUTCFullYear()}\`;
},
editor: {
type: Type.DATE

View File

@@ -0,0 +1,155 @@
/* eslint react/prefer-stateless-function: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory, { Type } from 'react-bootstrap-table2-editor';
import Code from 'components/common/code-block';
import { jobsGenerator } from 'utils/common';
const jobs = jobsGenerator().map(j => ({
...j,
type2: j.type
}));
const columns = [{
dataField: 'id',
text: 'Job ID'
}, {
dataField: 'name',
text: 'Job Name'
}, {
dataField: 'owner',
text: 'Job Owner'
}, {
dataField: 'type',
text: 'Job Type1',
editor: {
type: Type.SELECT,
getOptions: () => [{
value: 'A',
label: 'A'
}, {
value: 'B',
label: 'B'
}, {
value: 'C',
label: 'C'
}, {
value: 'D',
label: 'D'
}, {
value: 'E',
label: 'E'
}]
}
}, {
dataField: 'type2',
text: 'Job Type2',
editor: {
type: Type.SELECT,
getOptions: (setOptions) => {
setTimeout(() => {
setOptions([{
value: 'A',
label: 'A'
}, {
value: 'B',
label: 'B'
}, {
value: 'C',
label: 'C'
}, {
value: 'D',
label: 'D'
}, {
value: 'E',
label: 'E'
}]);
}, 2000);
}
}
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory, { Type } from 'react-bootstrap-table2-editor';
const columns = [{
dataField: 'id',
text: 'Job ID'
}, {
dataField: 'name',
text: 'Job Name'
}, {
dataField: 'owner',
text: 'Job Owner'
}, {
dataField: 'type',
text: 'Job Type1',
editor: {
type: Type.SELECT,
getOptions: () => [{
value: 'A',
label: 'A'
}, {
value: 'B',
label: 'B'
}, {
value: 'C',
label: 'C'
}, {
value: 'D',
label: 'D'
}, {
value: 'E',
label: 'E'
}]
}
}, {
dataField: 'type2',
text: 'Job Type2',
editor: {
type: Type.SELECT,
getOptions: (setOptions) => {
setTimeout(() => {
setOptions([{
value: 'A',
label: 'A'
}, {
value: 'B',
label: 'B'
}, {
value: 'C',
label: 'C'
}, {
value: 'D',
label: 'D'
}, {
value: 'E',
label: 'E'
}]);
}, 2000);
}
}
}];
<BootstrapTable
keyField="id"
data={ jobs }
columns={ columns }
cellEdit={ cellEditFactory({ mode: 'click', blurToSave: true }) }
/>
`;
export default () => (
<div>
<h3>Dropdown Editor with Dynamic Options</h3>
<BootstrapTable
keyField="id"
data={ jobs }
columns={ columns }
cellEdit={ cellEditFactory({ mode: 'click', blurToSave: true }) }
/>
<Code>{ sourceCode }</Code>
</div>
);

View File

@@ -0,0 +1,135 @@
/* eslint react/prop-types: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import ToolkitProvider from 'react-bootstrap-table2-toolkit';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const columnsdt = [{
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 ToolkitProvider from 'react-bootstrap-table2-toolkit';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const CustomToggleList = ({
columns,
onColumnToggle,
toggles
}) => (
<div className="btn-group btn-group-toggle btn-group-vertical" data-toggle="buttons">
{
columns
.map(column => ({
...column,
toggle: toggles[column.dataField]
}))
.map(column => (
<button
type="button"
key={ column.dataField }
className={ \`btn btn-warning \${column.toggle ? 'active' : ''}\` }
data-toggle="button"
aria-pressed={ column.toggle ? 'true' : 'false' }
onClick={ () => onColumnToggle(column.dataField) }
>
{ column.text }
</button>
))
}
</div>
);
<ToolkitProvider
keyField="id"
data={ products }
columns={ columnsdt }
columnToggle
>
{
props => (
<div>
<CustomToggleList { ...props.columnToggleProps } />
<hr />
<BootstrapTable
{ ...props.baseProps }
/>
</div>
)
}
</ToolkitProvider>
`;
const CustomToggleList = ({
columns,
onColumnToggle,
toggles
}) => (
<div className="btn-group btn-group-toggle btn-group-vertical" data-toggle="buttons">
{
columns
.map(column => ({
...column,
toggle: toggles[column.dataField]
}))
.map(column => (
<button
type="button"
key={ column.dataField }
className={ `btn btn-warning ${column.toggle ? 'active' : ''}` }
data-toggle="button"
aria-pressed={ column.toggle ? 'true' : 'false' }
onClick={ () => onColumnToggle(column.dataField) }
>
{ column.text }
</button>
))
}
</div>
);
export default () => (
<div>
<ToolkitProvider
keyField="id"
data={ products }
columns={ columnsdt }
columnToggle
>
{
props => (
<div>
<CustomToggleList { ...props.columnToggleProps } />
<hr />
<BootstrapTable
{ ...props.baseProps }
/>
</div>
)
}
</ToolkitProvider>
<Code>{ sourceCode }</Code>
</div>
);

View File

@@ -0,0 +1,81 @@
/* eslint react/prop-types: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import ToolkitProvider, { ColumnToggle } from 'react-bootstrap-table2-toolkit';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const { ToggleList } = ColumnToggle;
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name',
hidden: true
}, {
dataField: 'price',
text: 'Product Price',
hidden: true
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import ToolkitProvider, { ColumnToggle } from 'react-bootstrap-table2-toolkit';
const { ToggleList } = ColumnToggle;
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name',
hidden: true
}, {
dataField: 'price',
text: 'Product Price',
hidden: true
}];
<ToolkitProvider
keyField="id"
data={ products }
columns={ columns }
columnToggle
>
{
props => (
<div>
<ToggleList { ...props.columnToggleProps } />
<hr />
<BootstrapTable { ...props.baseProps } />
</div>
)
}
</ToolkitProvider>
`;
export default () => (
<div>
<ToolkitProvider
keyField="id"
data={ products }
columns={ columns }
columnToggle
>
{
props => (
<div>
<ToggleList { ...props.columnToggleProps } />
<hr />
<BootstrapTable { ...props.baseProps } />
</div>
)
}
</ToolkitProvider>
<Code>{ sourceCode }</Code>
</div>
);

View File

@@ -0,0 +1,81 @@
/* eslint react/prop-types: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import ToolkitProvider, { ColumnToggle } from 'react-bootstrap-table2-toolkit';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const { ToggleList } = ColumnToggle;
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';
import ToolkitProvider, { ColumnToggle } from 'react-bootstrap-table2-toolkit';
const { ToggleList } = ColumnToggle;
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
<ToolkitProvider
keyField="id"
data={ products }
columns={ columns }
columnToggle
>
{
props => (
<div>
<ToggleList { ...props.columnToggleProps } />
<hr />
<BootstrapTable
{ ...props.baseProps }
/>
</div>
)
}
</ToolkitProvider>
`;
export default () => (
<div>
<ToolkitProvider
keyField="id"
data={ products }
columns={ columns }
columnToggle
>
{
props => (
<div>
<ToggleList { ...props.columnToggleProps } />
<hr />
<BootstrapTable
{ ...props.baseProps }
/>
</div>
)
}
</ToolkitProvider>
<Code>{ sourceCode }</Code>
</div>
);

View File

@@ -0,0 +1,91 @@
/* eslint react/prop-types: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import ToolkitProvider, { ColumnToggle } from 'react-bootstrap-table2-toolkit';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const { ToggleList } = ColumnToggle;
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';
import ToolkitProvider, { ColumnToggle } from 'react-bootstrap-table2-toolkit';
const { ToggleList } = ColumnToggle;
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
<ToolkitProvider
keyField="id"
data={ products }
columns={ columns }
columnToggle
>
{
props => (
<div>
<ToggleList
contextual="success"
className="list-custom-class"
btnClassName="list-btn-custom-class"
{ ...props.columnToggleProps }
/>
<hr />
<BootstrapTable
{ ...props.baseProps }
/>
</div>
)
}
</ToolkitProvider>
`;
export default () => (
<div>
<ToolkitProvider
keyField="id"
data={ products }
columns={ columns }
columnToggle
>
{
props => (
<div>
<ToggleList
contextual="success"
className="list-custom-class"
btnClassName="list-btn-custom-class"
{ ...props.columnToggleProps }
/>
<hr />
<BootstrapTable
{ ...props.baseProps }
/>
</div>
)
}
</ToolkitProvider>
<Code>{ sourceCode }</Code>
</div>
);

View File

@@ -11,141 +11,13 @@ const products = [
{ id: 14, name: 'Item 14', price: 14.5, inStock: true }
];
const columns = [
{
dataField: 'id',
text: 'Product ID'
},
{
dataField: 'name',
text: 'Product Name'
},
{
dataField: 'price',
text: 'Product Price'
},
{
dataField: 'inStock',
text: 'In Stock',
formatter: (cellContent, row) => (
<div className="checkbox disabled">
<label>
<input type="checkbox" checked={ row.inStock } disabled />
</label>
</div>
)
},
{
dataField: 'df1',
isDummyField: true,
text: 'Action 1',
formatter: (cellContent, row) => {
if (row.inStock) {
return (
<h5>
<span className="label label-success"> Available</span>
</h5>
);
}
return (
<h5>
<span className="label label-danger"> Backordered</span>
</h5>
);
}
},
{
dataField: 'df2',
isDummyField: true,
text: 'Action 2',
formatter: (cellContent, row) => {
if (row.inStock) {
return (
<h5>
<span className="label label-success"> Available</span>
</h5>
);
}
return (
<h5>
<span className="label label-danger"> Backordered</span>
</h5>
);
}
}
];
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'
},
{
dataField: 'inStock',
text: 'In Stock',
formatter: (cellContent, row) => (
<div className="checkbox disabled">
<label>
<input type="checkbox" checked={ row.inStock } disabled />
</label>
</div>
)
},
{
dataField: 'df1',
isDummyField: true,
text: 'Action 1',
formatter: (cellContent, row) => {
if (row.inStock) {
return (
<h5>
<span className="label label-success"> Available</span>
</h5>
);
}
return (
<h5>
<span className="label label-danger"> Backordered</span>
</h5>
);
}
},
{
dataField: 'df2',
isDummyField: true,
text: 'Action 2',
formatter: (cellContent, row) => {
if (row.inStock) {
return (
<h5>
<span className="label label-success"> Available</span>
</h5>
);
}
return (
<h5>
<span className="label label-danger"> Backordered</span>
</h5>
);
}
}
];
class ProductList extends React.Component {
constructor(props) {
super(props);
this.state = { products };
this.state = { products, count: 0 };
}
toggleInStock = () => {
@@ -163,17 +35,96 @@ class ProductList extends React.Component {
};
render() {
const columns = [
{
dataField: 'id',
text: 'Product ID',
formatter: (cell, row, rowIndex, extraData) => (
<div>
<span>ID: {row.id}</span>
<br />
<span>state: {extraData}</span>
</div>
),
formatExtraData: this.state.count
},
{
dataField: 'name',
text: 'Product Name'
},
{
dataField: 'price',
text: 'Product Price'
},
{
dataField: 'inStock',
text: 'In Stock',
formatter: (cellContent, row) => (
<div className="checkbox disabled">
<label>
<input type="checkbox" checked={ row.inStock } disabled />
</label>
</div>
)
},
{
dataField: 'df1',
isDummyField: true,
text: 'Action 1',
formatter: (cellContent, row) => {
if (row.inStock) {
return (
<h5>
<span className="label label-success"> Available</span>
</h5>
);
}
return (
<h5>
<span className="label label-danger"> Backordered</span>
</h5>
);
}
},
{
dataField: 'df2',
isDummyField: true,
text: 'Action 2',
formatter: (cellContent, row) => {
if (row.inStock) {
return (
<h5>
<span className="label label-success"> Available</span>
</h5>
);
}
return (
<h5>
<span className="label label-danger"> Backordered</span>
</h5>
);
}
}
];
return (
<div>
<h1 className="h2">Products</h1>
<h3>Action 1 and Action 2 are dummy column</h3>
<button onClick={ this.toggleInStock } className="btn btn-primary">
Toggle item 13 stock status
</button>
<button
className="btn btn-success"
onClick={ () => this.setState(() => ({ count: this.state.count + 1 })) }
>
Click me to Increase counter
</button>
<BootstrapTable
keyField="id"
data={ this.state.products }
columns={ columns }
/>
<button onClick={ this.toggleInStock } className="btn btn-primary">
Toggle item 13 stock status
</button>
<Code>{ sourceCode }</Code>
</div>
);
}
@@ -183,7 +134,7 @@ class ProductList extends React.Component {
class ProductList extends React.Component {
constructor(props) {
super(props);
this.state = { products };
this.state = { products, count: 0 };
}
toggleInStock = () => {
@@ -200,13 +151,95 @@ class ProductList extends React.Component {
this.setState(curr => ({ ...curr, products: newProducts }));
};
counter = () => {
this.setState(curr => ({ ...curr, count: this.state.count + 1 }));
}
render() {
const columns = [
{
dataField: 'id',
text: 'Product ID',
formatter: (cell, row, rowIndex, extraData) => (
<div>
<span>ID: {row.id}</span>
<br />
<span>Counter: {extraData}</span>
</div>
),
formatExtraData: this.state.count
},
{
dataField: 'name',
text: 'Product Name'
},
{
dataField: 'price',
text: 'Product Price'
},
{
dataField: 'inStock',
text: 'In Stock',
formatter: (cellContent, row) => (
<div className="checkbox disabled">
<label>
<input type="checkbox" checked={ row.inStock } disabled />
</label>
</div>
)
},
{
dataField: 'df1',
isDummyField: true,
text: 'Action 1',
formatter: (cellContent, row) => {
if (row.inStock) {
return (
<h5>
<span className="label label-success"> Available</span>
</h5>
);
}
return (
<h5>
<span className="label label-danger"> Backordered</span>
</h5>
);
}
},
{
dataField: 'df2',
isDummyField: true,
text: 'Action 2',
formatter: (cellContent, row) => {
if (row.inStock) {
return (
<h5>
<span className="label label-success"> Available</span>
</h5>
);
}
return (
<h5>
<span className="label label-danger"> Backordered</span>
</h5>
);
}
}
];
return (
<div>
<h3>Action 1 and Action 2 are dummy column</h3>
<button onClick={ this.toggleInStock } className="btn btn-primary">
Toggle item 13 stock status
</button>
<button
className="btn btn-success"
onClick={ this.counter }
>
Click me to Increase counter
</button>
<BootstrapTable
keyField="id"
data={ this.state.products }

View File

@@ -0,0 +1,102 @@
/* eslint react/prop-types: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import ToolkitProvider, { CSVExport, Search } from 'react-bootstrap-table2-toolkit';
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
import paginationFactory from 'react-bootstrap-table2-paginator';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const { SearchBar } = Search;
const { ExportCSVButton } = CSVExport;
const products = productsGenerator(150);
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name',
filter: textFilter()
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import ToolkitProvider, { CSVExport, Search } from 'react-bootstrap-table2-toolkit';
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
const { SearchBar } = Search;
const { ExportCSVButton } = CSVExport;
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const selectRow = {
mode: 'checkbox',
clickToSelect: true
};
<ToolkitProvider
keyField="id"
data={ products }
columns={ columns }
exportCSV={ { onlyExportFiltered: true, exportAll: false } }
search
>
{
props => (
<div>
<ExportCSVButton { ...props.csvProps }>Export CSV!!</ExportCSVButton>
<hr />
<SearchBar { ...props.searchProps } />
<BootstrapTable
{ ...props.baseProps }
pagination={ paginationFactory() }
filter={ filterFactory() }
/>
</div>
)
}
</ToolkitProvider>
`;
export default () => (
<div>
<h3>Export all the filtered/searched rows</h3>
<ToolkitProvider
keyField="id"
data={ products }
columns={ columns }
exportCSV={ { onlyExportFiltered: true, exportAll: false } }
search
>
{
props => (
<div>
<ExportCSVButton { ...props.csvProps }>Export CSV!!</ExportCSVButton>
<hr />
<SearchBar { ...props.searchProps } />
<BootstrapTable
{ ...props.baseProps }
pagination={ paginationFactory() }
filter={ filterFactory() }
/>
</div>
)
}
</ToolkitProvider>
<Code>{ sourceCode }</Code>
</div>
);

View File

@@ -0,0 +1,151 @@
/* eslint react/no-multi-comp: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
import paginationFactory from 'react-bootstrap-table2-paginator';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name',
filter: textFilter()
}, {
dataField: 'price',
text: 'Product Price',
filter: textFilter()
}];
const sourceCode1 = `\
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
class Case1 extends React.Component {
constructor(props) {
super(props);
this.state = { rowCount: products.length };
}
handleDataChange = ({ dataSize }) => {
this.setState({ rowCount: dataSize });
}
render() {
return (
<div>
<h5>Row Count:<span className="badge">{ this.state.rowCount }</span></h5>
<BootstrapTable
onDataSizeChange={ this.handleDataChange }
keyField="id"
data={ products }
columns={ columns }
filter={ filterFactory() }
/>
<Code>{ sourceCode }</Code>
</div>
);
}
`;
const sourceCode2 = `\
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
import paginationFactory from 'react-bootstrap-table2-paginator';
class Case2 extends React.Component {
constructor(props) {
super(props);
this.state = { rowCount: products.length };
}
handleDataChange = ({ dataSize }) => {
this.setState({ rowCount: dataSize });
}
render() {
return (
<div>
<h5>Row Count:<span className="badge">{ this.state.rowCount }</span></h5>
<BootstrapTable
onDataSizeChange={ this.handleDataChange }
keyField="id"
data={ products }
columns={ columns }
filter={ filterFactory() }
pagination={ paginationFactory() }
/>
<Code>{ sourceCode }</Code>
</div>
);
}
`;
const products1 = productsGenerator(8);
class WithoutPaginationCase extends React.Component {
constructor(props) {
super(props);
this.state = { rowCount: products1.length };
}
handleDataChange = ({ dataSize }) => {
this.setState({ rowCount: dataSize });
}
render() {
return (
<div>
<h3>Without Pagination Case</h3>
<h5>Row Count:<span className="badge">{ this.state.rowCount }</span></h5>
<BootstrapTable
onDataSizeChange={ this.handleDataChange }
keyField="id"
data={ products1 }
columns={ columns }
filter={ filterFactory() }
/>
<Code>{ sourceCode2 }</Code>
</div>
);
}
}
const products2 = productsGenerator(88);
class WithPaginationCase extends React.Component {
constructor(props) {
super(props);
this.state = { rowCount: products2.length };
}
handleDataChange = ({ dataSize }) => {
this.setState({ rowCount: dataSize });
}
render() {
return (
<div>
<h3>Without Pagination Case</h3>
<h5>Row Count:<span className="badge">{ this.state.rowCount }</span></h5>
<BootstrapTable
onDataSizeChange={ this.handleDataChange }
keyField="id"
data={ products2 }
columns={ columns }
filter={ filterFactory() }
pagination={ paginationFactory() }
/>
<Code>{ sourceCode1 }</Code>
</div>
);
}
}
export default () => (
<div>
<WithoutPaginationCase />
<WithPaginationCase />
</div>
);

View File

@@ -7,7 +7,7 @@ import ToolkitProvider, { Search } from 'react-bootstrap-table2-toolkit';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator(21);
const products = productsGenerator(40);
const { SearchBar } = Search;
const columns = [{
@@ -24,6 +24,12 @@ import paginationFactory, { PaginationProvider, PaginationListStandalone } from
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
class Table extends React.Component {
state = { products }
loadData = () => {
this.setState({ products: productsGenerator(17) });
}
render() {
const options = {
custom: true,
@@ -38,70 +44,84 @@ class Table extends React.Component {
firstPageTitle: 'Next page',
lastPageTitle: 'Last page',
showTotal: true,
totalSize: products.length
};
const contentTable = ({ paginationProps, paginationTableProps }) => (
<div>
<PaginationListStandalone { ...paginationProps } />
<div>
<div>
<BootstrapTable
striped
hover
keyField="id"
data={ products }
columns={ columns }
filter={ filterFactory() }
cellEdit={ cellEditFactory() }
{ ...paginationTableProps }
/>
</div>
</div>
<PaginationListStandalone { ...paginationProps } />
</div>
);
return (
<div>
<h2>PaginationProvider will care the data size change. You dont do anything</h2>
<PaginationProvider
pagination={
paginationFactory(options)
}
>
{ contentTable }
</PaginationProvider>
<Code>{ sourceCode }</Code>
</div >
);
}
}
`;
export default class Table extends React.Component {
render() {
const options = {
custom: true,
paginationSize: 4,
pageStartIndex: 1,
firstPageText: 'First',
prePageText: 'Back',
nextPageText: 'Next',
lastPageText: 'Last',
nextPageTitle: 'First page',
prePageTitle: 'Pre page',
firstPageTitle: 'Next page',
lastPageTitle: 'Last page',
showTotal: true,
totalSize: products.length
totalSize: this.state.products.length
};
const contentTable = ({ paginationProps, paginationTableProps }) => (
<div>
<button className="btn btn-default" onClick={ this.loadData }>Load Another Data</button>
<PaginationListStandalone { ...paginationProps } />
<ToolkitProvider
keyField="id"
columns={ columns }
data={ products }
data={ this.state.products }
search
>
{
toolkitprops => (
<div>
<SearchBar { ...toolkitprops.searchProps } />
<BootstrapTable
striped
hover
{ ...toolkitprops.baseProps }
{ ...paginationTableProps }
/>
</div>
)
}
</ToolkitProvider>
<PaginationListStandalone { ...paginationProps } />
</div>
);
return (
<div>
<h2>PaginationProvider will care the data size change. You dont do anything</h2>
<PaginationProvider
pagination={
paginationFactory(options)
}
>
{ contentTable }
</PaginationProvider>
<Code>{ sourceCode }</Code>
</div >
);
}
}
`;
export default class Table extends React.Component {
state = { products }
loadData = () => {
this.setState({ products: productsGenerator(17) });
}
render() {
const options = {
custom: true,
paginationSize: 4,
pageStartIndex: 1,
firstPageText: 'First',
prePageText: 'Back',
nextPageText: 'Next',
lastPageText: 'Last',
nextPageTitle: 'First page',
prePageTitle: 'Pre page',
firstPageTitle: 'Next page',
lastPageTitle: 'Last page',
showTotal: true,
totalSize: this.state.products.length
};
const contentTable = ({ paginationProps, paginationTableProps }) => (
<div>
<button className="btn btn-default" onClick={ this.loadData }>Load Another Data</button>
<PaginationListStandalone { ...paginationProps } />
<ToolkitProvider
keyField="id"
columns={ columns }
data={ this.state.products }
search
>
{

View File

@@ -3,28 +3,70 @@ import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import paginationFactory, { PaginationProvider, PaginationListStandalone } from 'react-bootstrap-table2-paginator';
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
import filterFactory, { textFilter, selectFilter } from 'react-bootstrap-table2-filter';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
import { productsQualityGenerator } from 'utils/common';
const products = productsGenerator(21);
const products = productsQualityGenerator(21);
const selectOptions = {
0: 'good',
1: 'Bad',
2: 'unknown'
};
const columns = [{
dataField: 'id',
text: 'Product ID',
filter: textFilter({})
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name',
filter: textFilter()
}, {
dataField: 'quality',
text: 'Product Quailty',
formatter: cell => selectOptions[cell],
filter: selectFilter({
options: selectOptions,
defaultValue: 0
})
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import paginationFactory, { PaginationProvider, PaginationListStandalone } from 'react-bootstrap-table2-paginator';
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
import filterFactory, { textFilter, selectFilter } from 'react-bootstrap-table2-filter';
const selectOptions = {
0: 'good',
1: 'Bad',
2: 'unknown'
};
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name',
filter: textFilter()
}, {
dataField: 'quality',
text: 'Product Quailty',
formatter: cell => selectOptions[cell],
filter: selectFilter({
options: selectOptions,
defaultValue: 0
})
}];
class Table extends React.Component {
state = { products }
loadData = () => {
this.setState({ products: productsQualityGenerator(40, 7) });
}
render() {
const options = {
custom: true,
@@ -39,10 +81,11 @@ class Table extends React.Component {
firstPageTitle: 'Next page',
lastPageTitle: 'Last page',
showTotal: true,
totalSize: products.length
totalSize: this.state.products.length
};
const contentTable = ({ paginationProps, paginationTableProps }) => (
<div>
<button className="btn btn-default" onClick={ this.loadData }>Load Another Data</button>
<PaginationListStandalone { ...paginationProps } />
<div>
<div>
@@ -50,10 +93,9 @@ class Table extends React.Component {
striped
hover
keyField="id"
data={ products }
data={ this.state.products }
columns={ columns }
filter={ filterFactory() }
cellEdit={ cellEditFactory() }
{ ...paginationTableProps }
/>
</div>
@@ -72,7 +114,6 @@ class Table extends React.Component {
>
{ contentTable }
</PaginationProvider>
<Code>{ sourceCode }</Code>
</div >
);
}
@@ -80,6 +121,12 @@ class Table extends React.Component {
`;
export default class Table extends React.Component {
state = { products }
loadData = () => {
this.setState({ products: productsQualityGenerator(40, 7) });
}
render() {
const options = {
custom: true,
@@ -94,10 +141,11 @@ export default class Table extends React.Component {
firstPageTitle: 'Next page',
lastPageTitle: 'Last page',
showTotal: true,
totalSize: products.length
totalSize: this.state.products.length
};
const contentTable = ({ paginationProps, paginationTableProps }) => (
<div>
<button className="btn btn-default" onClick={ this.loadData }>Load Another Data</button>
<PaginationListStandalone { ...paginationProps } />
<div>
<div>
@@ -105,7 +153,7 @@ export default class Table extends React.Component {
striped
hover
keyField="id"
data={ products }
data={ this.state.products }
columns={ columns }
filter={ filterFactory() }
{ ...paginationTableProps }

View File

@@ -0,0 +1,150 @@
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';
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import paginationFactory from 'react-bootstrap-table2-paginator';
class BookList extends React.Component {
state = {
books: [
{ id: '1', name: 'Book 1' },
{ id: '2', name: 'Book 2' },
{ id: '3', name: 'Book 3' },
{ id: '4', name: 'Book 4' },
{ id: '5', name: 'Book 5' },
{ id: '6', name: 'Book 6' }
]
};
deleteBookWithId = () => {
const lastOneId = this.state.books.length;
const updatedBooks = this.state.books.filter(m => m.id !== lastOneId.toString());
this.setState({ books: updatedBooks });
};
addBook = () => {
const lastOneId = this.state.books.length + 1;
this.setState({ books: [...this.state.books, {
id: \`$\{lastOneId}\`, name: \`Book $\{lastOneId}\`
}] });
}
render() {
const options = {
// pageStartIndex: 0,
sizePerPage: 5,
hideSizePerPage: true,
hidePageListOnlyOnePage: true
};
const columns = [
{
dataField: 'id',
text: 'Product ID',
Cell: row => (
<div>
<span title={ row.value }>{ row.value }</span>
</div>
)
},
{
dataField: 'name',
text: 'Product Name'
}
];
return (
<React.Fragment>
<BootstrapTable
keyField="id"
data={ this.state.books }
columns={ columns }
pagination={ paginationFactory(options) }
/>
<button className="btn btn-default" onClick={ () => this.deleteBookWithId() }>
delete last one book
</button>
<button className="btn btn-default" onClick={ () => this.addBook() }>
Add a book to the end
</button>
<Code>{ sourceCode }</Code>
</React.Fragment>
);
}
`;
export default class BookList extends React.Component {
state = {
books: [
{ id: '1', name: 'Book 1' },
{ id: '2', name: 'Book 2' },
{ id: '3', name: 'Book 3' },
{ id: '4', name: 'Book 4' },
{ id: '5', name: 'Book 5' },
{ id: '6', name: 'Book 6' },
{ id: '7', name: 'Book 6' },
{ id: '8', name: 'Book 6' },
{ id: '9', name: 'Book 6' },
{ id: '10', name: 'Book 6' },
{ id: '11', name: 'Book 6' }
]
};
deleteBookWithId = () => {
const lastOneId = this.state.books.length;
const updatedBooks = this.state.books.filter(m => m.id !== lastOneId.toString());
this.setState({ books: updatedBooks });
};
addBook = () => {
const lastOneId = this.state.books.length + 1;
this.setState({ books: [...this.state.books, {
id: `${lastOneId}`, name: `Book ${lastOneId}`
}] });
}
render() {
const options = {
// pageStartIndex: 0,
sizePerPage: 5,
hideSizePerPage: true,
hidePageListOnlyOnePage: true
};
const columns = [
{
dataField: 'id',
text: 'Product ID',
Cell: row => (
<div>
<span title={ row.value }>{ row.value }</span>
</div>
)
},
{
dataField: 'name',
text: 'Product Name'
}
];
return (
<React.Fragment>
<BootstrapTable
keyField="id"
data={ this.state.books }
columns={ columns }
pagination={ paginationFactory(options) }
/>
<button className="btn btn-default" onClick={ () => this.deleteBookWithId() }>
delete last one book
</button>
<button className="btn btn-default" onClick={ () => this.addBook() }>
Add a book to the end
</button>
<Code>{ sourceCode }</Code>
</React.Fragment>
);
}
}

View File

@@ -0,0 +1,107 @@
/* eslint react/prefer-stateless-function: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import paginationFactory, { PaginationProvider, PaginationTotalStandalone, 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, PaginationTotalStandalone, 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>
<PaginationTotalStandalone
{ ...paginationProps }
/>
<PaginationListStandalone
{ ...paginationProps }
/>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
{ ...paginationTableProps }
/>
</div>
)
}
</PaginationProvider>
`;
const options = {
custom: true,
totalSize: products.length
};
export default class StandalonePaginationList extends React.Component {
render() {
return (
<div>
<PaginationProvider
pagination={ paginationFactory(options) }
>
{
({
paginationProps,
paginationTableProps
}) => (
<div>
<PaginationTotalStandalone
{ ...paginationProps }
/>
<PaginationListStandalone
{ ...paginationProps }
/>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
{ ...paginationTableProps }
/>
</div>
)
}
</PaginationProvider>
<Code>{ sourceCode }</Code>
</div>
);
}
}

View File

@@ -84,6 +84,7 @@ export default class StandaloneSizePerPage extends React.Component {
<div>
<SizePerPageDropdownStandalone
{ ...paginationProps }
btnContextual="btn btn-primary"
/>
<BootstrapTable
keyField="id"

View File

@@ -43,6 +43,7 @@ const columns = [{
}];
const expandRow = {
onlyOneExpanding: true,
renderer: row => (
<div>
<p>{ \`This Expand row is belong to rowKey $\{row.id}\` }</p>

View File

@@ -0,0 +1,111 @@
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(2);
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const selectRow1 = {
mode: 'checkbox',
clickToSelect: true,
headerColumnStyle: {
backgroundColor: 'blue'
}
};
const sourceCode1 = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = ...
const selectRow = {
mode: 'checkbox',
clickToSelect: true,
headerColumnStyle: {
backgroundColor: 'blue'
}
};
<BootstrapTable
keyField='id'
data={ products }
columns={ columns }
selectRow={ selectRow }
/>
`;
const selectRow2 = {
mode: 'checkbox',
clickToSelect: true,
headerColumnStyle: (status) => {
if (status === 'checked') {
return {
backgroundColor: 'yellow'
};
} else if (status === 'indeterminate') {
return {
backgroundColor: 'pink'
};
} else if (status === 'unchecked') {
return {
backgroundColor: 'grey'
};
}
return {};
}
};
const sourceCode2 = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = ...
const selectRow = {
mode: 'checkbox',
clickToSelect: true,
headerColumnStyle: (status) => {
if (status === 'checked') {
return {
backgroundColor: 'yellow'
};
} else if (status === 'indeterminate') {
return {
backgroundColor: 'pink'
};
} else if (status === 'unchecked') {
return {
backgroundColor: 'grey'
};
}
return {};
}
};
<BootstrapTable
keyField='id'
data={ products }
columns={ columns }
selectRow={ selectRow }
/>
`;
export default () => (
<div>
<BootstrapTable keyField="id" data={ products } columns={ columns } selectRow={ selectRow1 } />
<Code>{ sourceCode1 }</Code>
<BootstrapTable keyField="id" data={ products } columns={ columns } selectRow={ selectRow2 } />
<Code>{ sourceCode2 }</Code>
</div>
);

View File

@@ -0,0 +1,110 @@
/* eslint no-unused-vars: 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(2);
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const selectRow1 = {
mode: 'checkbox',
clickToSelect: true,
selectColumnStyle: {
backgroundColor: 'grey'
}
};
const sourceCode1 = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = ...
const selectRow = {
mode: 'checkbox',
clickToSelect: true,
selectColumnStyle: {
backgroundColor: 'grey'
}
};
<BootstrapTable
keyField='id'
data={ products }
columns={ columns }
selectRow={ selectRow }
/>
`;
const selectRow2 = {
mode: 'checkbox',
clickToSelect: true,
selectColumnStyle: ({
checked,
disabled,
rowIndex,
rowKey
}) => {
if (checked) {
return {
backgroundColor: 'yellow'
};
}
return {
backgroundColor: 'pink'
};
}
};
const sourceCode2 = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = ...
const selectRow = {
mode: 'checkbox',
clickToSelect: true,
selectColumnStyle: ({
checked,
disabled,
rowIndex,
rowKey
}) => {
if (checked) {
return {
backgroundColor: 'yellow'
};
}
return {
backgroundColor: 'pink'
};
}
};
<BootstrapTable
keyField='id'
data={ products }
columns={ columns }
selectRow={ selectRow }
/>
`;
export default () => (
<div>
<BootstrapTable keyField="id" data={ products } columns={ columns } selectRow={ selectRow1 } />
<Code>{ sourceCode1 }</Code>
<BootstrapTable keyField="id" data={ products } columns={ columns } selectRow={ selectRow2 } />
<Code>{ sourceCode2 }</Code>
</div>
);

View File

@@ -0,0 +1,59 @@
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 selectRow = {
mode: 'checkbox',
clickToSelect: true,
selectColumnPosition: '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 selectRow = {
mode: 'checkbox',
clickToSelect: true,
selectColumnPosition: 'right'
};
<BootstrapTable
keyField='id'
data={ products }
columns={ columns }
selectRow={ selectRow }
/>
`;
export default () => (
<div>
<BootstrapTable keyField="id" data={ products } columns={ columns } selectRow={ selectRow } />
<Code>{ sourceCode }</Code>
</div>
);

View File

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

View File

@@ -29,10 +29,10 @@ export const withOnSale = rows => rows.map((row) => {
return row;
});
export const productsQualityGenerator = (quantity = 5) =>
export const productsQualityGenerator = (quantity = 5, factor = 0) =>
Array.from({ length: quantity }, (value, index) => ({
id: index,
name: `Item name ${index}`,
id: index + factor,
name: `Item name ${index + factor}`,
quality: index % 3
}));

View File

@@ -20,6 +20,8 @@ import TabIndexCellTable from 'examples/basic/tabindex-column';
import Bootstrap4DefaultSortTable from 'examples/bootstrap4/sort';
import Bootstrap4RowSelectionTable from 'examples/bootstrap4/row-selection';
import Bootstrap4PaginationTable from 'examples/bootstrap4/pagination';
import Bootstrap4ColumnToggleTable from 'examples/bootstrap4/column-toggle';
import ToolkitsTable from 'examples/bootstrap4/toolkits';
// work on columns
import NestedDataTable from 'examples/columns/nested-data-table';
@@ -123,6 +125,7 @@ import EditorStyleTable from 'examples/cell-edit/editor-style-table';
import EditorClassTable from 'examples/cell-edit/editor-class-table';
import DBClickEditWithSelection from 'examples/cell-edit/dbclick-to-edit-with-selection-table';
import DropdownEditorTable from 'examples/cell-edit/dropdown-editor-table';
import DropdownEditorWithDynamicOptionsTable from 'examples/cell-edit/dropdown-editor-with-dynamic-options-table';
import TextareaEditorTable from 'examples/cell-edit/textarea-editor-table';
import CheckboxEditorTable from 'examples/cell-edit/checkbox-editor-table';
import DateEditorTable from 'examples/cell-edit/date-editor-table';
@@ -140,12 +143,15 @@ import SelectionWithExpansionTable from 'examples/row-selection/selection-with-e
import SelectionNoDataTable from 'examples/row-selection/selection-no-data';
import SelectionStyleTable from 'examples/row-selection/selection-style';
import SelectionClassTable from 'examples/row-selection/selection-class';
import HeaderStyleTable from 'examples/row-selection/header-style';
import HideSelectAllTable from 'examples/row-selection/hide-select-all';
import CustomSelectionTable from 'examples/row-selection/custom-selection';
import NonSelectableRowsTable from 'examples/row-selection/non-selectable-rows';
import SelectionBgColorTable from 'examples/row-selection/selection-bgcolor';
import SelectionHooks from 'examples/row-selection/selection-hooks';
import HideSelectionColumnTable from 'examples/row-selection/hide-selection-column';
import SelectionColumnStyleTable from 'examples/row-selection/select-column-style';
import SelectionColumnPositionTable from 'examples/row-selection/selection-column-position';
// work on row expand
import BasicRowExpand from 'examples/row-expand';
@@ -161,6 +167,7 @@ import ExpandHooks from 'examples/row-expand/expand-hooks';
// pagination
import PaginationTable from 'examples/pagination';
import PaginationHooksTable from 'examples/pagination/pagination-hooks';
import PaginationWithDynamicData from 'examples/pagination/pagination-with-dynamic-data';
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';
@@ -168,6 +175,7 @@ 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 StandalonePaginationTotal from 'examples/pagination/standalone-pagination-total';
import FullyCustomPaginationTable from 'examples/pagination/fully-custom-pagination';
import RemoteStandalonePaginationTable from 'examples/pagination/remote-standalone-pagination';
import CustomePaginationWithFilter from 'examples/pagination/custome-page-list-with-filter';
@@ -188,11 +196,18 @@ import CSVFormatter from 'examples/csv/csv-column-formatter';
import CustomCSVHeader from 'examples/csv/custom-csv-header';
import HideCSVColumn from 'examples/csv/hide-column';
import ExportOnlySelected from 'examples/csv/export-only-selected';
import ExportOnlyFiltered from 'examples/csv/export-only-filtered';
import CSVColumnType from 'examples/csv/csv-column-type';
import CustomCSVButton from 'examples/csv/custom-csv-button';
import ExportCustomData from 'examples/csv/export-custom-data';
import CustomCSV from 'examples/csv/custom-csv';
// Column toggle
import BasicColumnToggle from 'examples/column-toggle';
import DefaultVisibility from 'examples/column-toggle/default-visibility';
import StylingColumnToggle from 'examples/column-toggle/styling-toggle-list';
import CustomToggleList from 'examples/column-toggle/custom-toggle-list';
// loading overlay
import EmptyTableOverlay from 'examples/loading-overlay/empty-table-overlay';
import TableOverlay from 'examples/loading-overlay/table-overlay';
@@ -206,6 +221,7 @@ import RemoteCellEdit from 'examples/remote/remote-celledit';
import RemoteAll from 'examples/remote/remote-all';
// data
import DataChangeListener from 'examples/data/data-change-listener';
import LoadDataWithFilter from 'examples/data/load-data-on-the-fly-with-filter';
import LoadDataWithDefaultFilter from 'examples/data/load-data-on-the-fly-with-default-filter';
import LoadDataWithSearch from 'examples/data/load-data-on-the-fly-with-search';
@@ -218,6 +234,7 @@ import 'stories/stylesheet/storybook.scss';
import '../../react-bootstrap-table2/style/react-bootstrap-table2.scss';
import '../../react-bootstrap-table2-paginator/style/react-bootstrap-table2-paginator.scss';
import '../../react-bootstrap-table2-filter/style/react-bootstrap-table2-filter.scss';
import '../../react-bootstrap-table2-toolkit/style/react-bootstrap-table2-toolkit.scss';
// import bootstrap style by given version
import bootstrapStyle, { BOOTSTRAP_VERSION } from './bootstrap-style';
@@ -240,7 +257,9 @@ storiesOf('Bootstrap 4', module)
.addDecorator(bootstrapStyle(BOOTSTRAP_VERSION.FOUR))
.add('Sort table with bootstrap 4', () => <Bootstrap4DefaultSortTable />)
.add('Row selection table with bootstrap 4', () => <Bootstrap4RowSelectionTable />)
.add('Pagination table with bootstrap 4', () => <Bootstrap4PaginationTable />);
.add('Pagination table with bootstrap 4', () => <Bootstrap4PaginationTable />)
.add('Column Toggle with bootstrap 4', () => <Bootstrap4ColumnToggleTable />)
.add('toolkits Table bootstrap 4', () => <ToolkitsTable />);
storiesOf('Work on Columns', module)
.addDecorator(bootstrapStyle())
@@ -352,6 +371,7 @@ storiesOf('Cell Editing', module)
.add('Custom Editor Style', () => <EditorStyleTable />)
.add('DoubleClick to Edit with Selection', () => <DBClickEditWithSelection />)
.add('Dropdown Editor', () => <DropdownEditorTable />)
.add('Dropdown Editor with Dynamic Options', () => <DropdownEditorWithDynamicOptionsTable />)
.add('Textarea Editor', () => <TextareaEditorTable />)
.add('Checkbox Editor', () => <CheckboxEditorTable />)
.add('Date Editor', () => <DateEditorTable />)
@@ -370,12 +390,15 @@ storiesOf('Row Selection', module)
.add('Selection without Data', () => <SelectionNoDataTable />)
.add('Selection Style', () => <SelectionStyleTable />)
.add('Selection Class', () => <SelectionClassTable />)
.add('Custom Selection Column Header Style', () => <HeaderStyleTable />)
.add('Hide Select All', () => <HideSelectAllTable />)
.add('Custom Selection', () => <CustomSelectionTable />)
.add('Selection Background Color', () => <SelectionBgColorTable />)
.add('Not Selectabled Rows', () => <NonSelectableRowsTable />)
.add('Selection Hooks', () => <SelectionHooks />)
.add('Hide Selection Column', () => <HideSelectionColumnTable />);
.add('Hide Selection Column', () => <HideSelectionColumnTable />)
.add('Custom Selection Column Style', () => <SelectionColumnStyleTable />)
.add('Selection Column Position', () => <SelectionColumnPositionTable />);
storiesOf('Row Expand', module)
.addDecorator(bootstrapStyle())
@@ -393,6 +416,7 @@ storiesOf('Pagination', module)
.addDecorator(bootstrapStyle())
.add('Basic Pagination Table', () => <PaginationTable />)
.add('Pagination Hooks', () => <PaginationHooksTable />)
.add('Pagination with Dynamic Data', () => <PaginationWithDynamicData />)
.add('Custom Pagination', () => <CustomPaginationTable />)
.add('Custom Page Button', () => <CustomPageButtonTable />)
.add('Custom Page List', () => <CustomPageListTable />)
@@ -400,6 +424,7 @@ storiesOf('Pagination', module)
.add('Custom SizePerPage', () => <CustomSizePerPageTable />)
.add('Standalone Pagination List', () => <StandalonePaginationList />)
.add('Standalone SizePerPage Dropdown', () => <StandaloneSizePerPage />)
.add('Standalone Pagination Total', () => <StandalonePaginationTotal />)
.add('Fully Custom Pagination', () => <FullyCustomPaginationTable />)
.add('Remote Fully Custom Pagination', () => <RemoteStandalonePaginationTable />)
.add('Custom Pagination with Filter', () => <CustomePaginationWithFilter />)
@@ -415,6 +440,13 @@ storiesOf('Table Search', module)
.add('Search Fromatted Value', () => <SearchFormattedData />)
.add('Custom Search Value', () => <CustomSearchValue />);
storiesOf('Column Toggle', module)
.addDecorator(bootstrapStyle())
.add('Basic Column Toggle', () => <BasicColumnToggle />)
.add('Default Visibility', () => <DefaultVisibility />)
.add('Styling Column Toggle', () => <StylingColumnToggle />)
.add('Custom Column Toggle', () => <CustomToggleList />);
storiesOf('Export CSV', module)
.addDecorator(bootstrapStyle())
.add('Basic Export CSV', () => <ExportCSV />)
@@ -422,6 +454,7 @@ storiesOf('Export CSV', module)
.add('Custom CSV Header', () => <CustomCSVHeader />)
.add('Hide CSV Column', () => <HideCSVColumn />)
.add('Only Export Selected Rows', () => <ExportOnlySelected />)
.add('Only Export Filtered/Searched Rows', () => <ExportOnlyFiltered />)
.add('CSV Column Type', () => <CSVColumnType />)
.add('Custom CSV Button', () => <CustomCSVButton />)
.add('Export Custom Data', () => <ExportCustomData />)
@@ -443,6 +476,7 @@ storiesOf('Remote', module)
storiesOf('Data', module)
.addDecorator(bootstrapStyle())
.add('Data Change Listener', () => <DataChangeListener />)
.add('Load data with Filter', () => <LoadDataWithFilter />)
.add('Load data with Default Filter', () => <LoadDataWithDefaultFilter />)
.add('Load data with Search', () => <LoadDataWithSearch />)

View File

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

View File

@@ -18,7 +18,7 @@ const legalComparators = [
];
function dateParser(d) {
return `${d.getFullYear()}-${('0' + (d.getMonth() + 1)).slice(-2)}-${('0' + d.getDate()).slice(-2)}`;
return `${d.getUTCFullYear()}-${('0' + (d.getUTCMonth() + 1)).slice(-2)}-${('0' + d.getUTCDate()).slice(-2)}`;
}
class DateFilter extends Component {
@@ -132,8 +132,14 @@ class DateFilter extends Component {
className={ `filter date-filter ${className}` }
style={ style }
>
<label
className="filter-label"
htmlFor={ `date-filter-comparator-${text}` }
>
<span className="sr-only">Filter comparator</span>
<select
ref={ n => this.dateFilterComparator = n }
id={ `date-filter-comparator-${text}` }
style={ comparatorStyle }
className={ `date-filter-comparator form-control ${comparatorClassName}` }
onChange={ this.onChangeComparator }
@@ -141,8 +147,12 @@ class DateFilter extends Component {
>
{ this.getComparatorOptions() }
</select>
</label>
<label htmlFor={ `date-filter-column-${text}` }>
<span className="sr-only">Enter ${ text }</span>
<input
ref={ n => this.inputDate = n }
id={ `date-filter-column-${text}` }
className={ `filter date-filter-input form-control ${dateClassName}` }
style={ dateStyle }
type="date"
@@ -150,6 +160,7 @@ class DateFilter extends Component {
placeholder={ placeholder || `Enter ${text}...` }
defaultValue={ this.getDefaultDate() }
/>
</label>
</div>
);
}

View File

@@ -111,9 +111,15 @@ class MultiSelectFilter extends Component {
`filter select-filter form-control ${className} ${this.state.isSelected ? '' : 'placeholder-selected'}`;
return (
<label
className="filter-label"
htmlFor={ `multiselect-filter-column-${column.text}` }
>
<span className="sr-only">Filter by {column.text}</span>
<select
{ ...rest }
ref={ n => this.selectInput = n }
id={ `multiselect-filter-column-${column.text}` }
style={ style }
multiple
className={ selectClass }
@@ -123,6 +129,7 @@ class MultiSelectFilter extends Component {
>
{ this.getOptions() }
</select>
</label>
);
}
}

View File

@@ -173,28 +173,45 @@ class NumberFilter extends Component {
className={ `filter number-filter ${className}` }
style={ style }
>
<label
className="filter-label"
htmlFor={ `number-filter-comparator-${column.text}` }
>
<span className="sr-only">Filter comparator</span>
<select
ref={ n => this.numberFilterComparator = n }
style={ comparatorStyle }
id={ `number-filter-comparator-${column.text}` }
className={ `number-filter-comparator form-control ${comparatorClassName}` }
onChange={ this.onChangeComparator }
defaultValue={ defaultValue ? defaultValue.comparator : '' }
>
{ this.getComparatorOptions() }
</select>
</label>
{
options ?
<label
className="filter-label"
htmlFor={ `number-filter-column-${column.text}` }
>
<span className="sr-only">{`Select ${column.text}`}</span>
<select
ref={ n => this.numberFilter = n }
id={ `number-filter-column-${column.text}` }
style={ numberStyle }
className={ selectClass }
onChange={ this.onChangeNumberSet }
defaultValue={ defaultValue ? defaultValue.number : '' }
>
{ this.getNumberOptions() }
</select> :
</select>
</label> :
<label htmlFor={ `number-filter-column-${column.text}` }>
<span className="sr-only">{`Enter ${column.text}`}</span>
<input
ref={ n => this.numberFilter = n }
id={ `number-filter-column-${column.text}` }
type="number"
style={ numberStyle }
className={ `number-filter-input form-control ${numberClassName}` }
@@ -202,6 +219,7 @@ class NumberFilter extends Component {
onChange={ this.onChangeNumber }
defaultValue={ defaultValue ? defaultValue.number : '' }
/>
</label>
}
</div>
);

View File

@@ -8,6 +8,7 @@ import { FILTER_TYPE } from '../const';
function optionsEquals(currOpts, prevOpts) {
if (Array.isArray(currOpts)) {
if (currOpts.length === prevOpts.length) {
for (let i = 0; i < currOpts.length; i += 1) {
if (
currOpts[i].value !== prevOpts[i].value ||
@@ -16,7 +17,9 @@ function optionsEquals(currOpts, prevOpts) {
return false;
}
}
return currOpts.length === prevOpts.length;
return true;
}
return false;
}
const keys = Object.keys(currOpts);
for (let i = 0; i < keys.length; i += 1) {
@@ -136,9 +139,15 @@ class SelectFilter extends Component {
`filter select-filter form-control ${className} ${this.state.isSelected ? '' : 'placeholder-selected'}`;
return (
<label
className="filter-label"
htmlFor={ `select-filter-column-${column.text}` }
>
<span className="sr-only">Filter by { column.text }</span>
<select
{ ...rest }
ref={ n => this.selectInput = n }
id={ `select-filter-column-${column.text}` }
style={ style }
className={ selectClass }
onChange={ this.filter }
@@ -147,6 +156,7 @@ class SelectFilter extends Component {
>
{ this.getOptions() }
</select>
</label>
);
}
}

View File

@@ -94,10 +94,16 @@ class TextFilter extends Component {
// stopPropagation for onClick event is try to prevent sort was triggered.
return (
<label
className="filter-label"
htmlFor={ `text-filter-column-${text}` }
>
<span className="sr-only">Filter by {text}</span>
<input
{ ...rest }
ref={ n => this.input = n }
type="text"
id={ `text-filter-column-${text}` }
className={ `filter text-filter form-control ${className}` }
style={ style }
onChange={ this.filter }
@@ -105,6 +111,7 @@ class TextFilter extends Component {
placeholder={ placeholder || `Enter ${text}...` }
value={ this.state.value }
/>
</label>
);
}
}

View File

@@ -27,9 +27,8 @@ export default (
this.onFilter = this.onFilter.bind(this);
this.doFilter = this.doFilter.bind(this);
this.onExternalFilter = this.onExternalFilter.bind(this);
this.state = {
data: props.data
};
this.data = props.data;
this.isEmitDataChange = false;
}
componentDidMount() {
@@ -39,13 +38,12 @@ export default (
}
componentWillReceiveProps(nextProps) {
let nextData = nextProps.data;
if (!isRemoteFiltering() && !_.isEqual(nextProps.data, this.props.data)) {
nextData = this.doFilter(nextProps);
// let nextData = nextProps.data;
if (!isRemoteFiltering() && !_.isEqual(nextProps.data, this.data)) {
this.doFilter(nextProps, undefined, this.isEmitDataChange);
} else {
this.data = nextProps.data;
}
this.setState({
data: nextData
});
}
onFilter(column, filterType, initialize = false) {
@@ -83,9 +81,7 @@ export default (
if (filter.props.onFilter) {
result = filter.props.onFilter(filterVal);
}
result = this.doFilter(this.props, result);
this.setState({ data: result });
this.doFilter(this.props, result);
};
}
@@ -95,21 +91,29 @@ export default (
};
}
doFilter(props, customResult) {
getFiltered() {
return this.data;
}
doFilter(props, customResult, ignoreEmitDataChange = false) {
let result = customResult;
const { dataChangeListener, data, columns } = props;
result = result || filters(data, columns, _)(this.currFilters);
if (dataChangeListener) {
this.data = result;
if (dataChangeListener && !ignoreEmitDataChange) {
this.isEmitDataChange = true;
dataChangeListener.emit('filterChanged', result.length);
} else {
this.isEmitDataChange = false;
this.forceUpdate();
}
return result;
}
render() {
return (
<FilterContext.Provider value={ {
data: this.state.data,
data: this.data,
onFilter: this.onFilter,
onExternalFilter: this.onExternalFilter
} }

View File

@@ -98,9 +98,9 @@ export const filterByDate = _ => (
customFilterValue
) => {
if (!date || !comparator) return data;
const filterDate = date.getDate();
const filterMonth = date.getMonth();
const filterYear = date.getFullYear();
const filterDate = date.getUTCDate();
const filterMonth = date.getUTCMonth();
const filterYear = date.getUTCFullYear();
return data.filter((row) => {
let valid = true;
@@ -114,9 +114,9 @@ export const filterByDate = _ => (
cell = new Date(cell);
}
const targetDate = cell.getDate();
const targetMonth = cell.getMonth();
const targetYear = cell.getFullYear();
const targetDate = cell.getUTCDate();
const targetMonth = cell.getUTCMonth();
const targetYear = cell.getUTCFullYear();
switch (comparator) {

View File

@@ -1,3 +1,7 @@
.react-bootstrap-table > table > thead > tr > th .filter-label {
display: block !important;
}
.react-bootstrap-table > table > thead > tr > th .filter {
font-weight: normal;
}

View File

@@ -283,9 +283,9 @@ describe('FilterContext', () => {
expect(onFilter).toHaveBeenCalledWith(filterVal);
});
it('should set state.data correctly', () => {
it('should set data correctly', () => {
instance.onFilter(customColumns[1], FILTER_TYPE.TEXT)(filterVal);
expect(instance.state.data).toEqual(mockReturn);
expect(instance.data).toEqual(mockReturn);
});
});

View File

@@ -11,10 +11,10 @@ export default options => loading =>
componentDidMount() {
if (loading) {
const { wrapper } = this.overlay;
const masker = wrapper.firstChild;
const headerDOM = wrapper.parentElement.querySelector('thead');
const bodyDOM = wrapper.parentElement.querySelector('tbody');
const captionDOM = wrapper.parentElement.querySelector('caption');
const masker = wrapper.current.firstChild;
const headerDOM = wrapper.current.parentElement.querySelector('thead');
const bodyDOM = wrapper.current.parentElement.querySelector('tbody');
const captionDOM = wrapper.current.parentElement.querySelector('caption');
let marginTop = window.getComputedStyle(headerDOM).height;
if (captionDOM) {

View File

@@ -1,6 +1,6 @@
{
"name": "react-bootstrap-table2-overlay",
"version": "1.0.0",
"version": "2.0.0",
"description": "it's a loading overlay addons for react-bootstrap-table2",
"main": "./lib/index.js",
"repository": {
@@ -37,7 +37,7 @@
}
],
"dependencies": {
"react-loading-overlay": "0.2.8"
"react-loading-overlay": "1.0.1"
},
"peerDependencies": {
"prop-types": "^15.0.0",

View File

@@ -2,199 +2,351 @@
# yarn lockfile v1
asap@~2.0.3:
version "2.0.6"
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
base64-js@^1.0.2:
version "1.2.1"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.1.tgz#a91947da1f4a516ea38e5b4ec0ec3773675e0886"
buffer@^5.0.3:
version "5.0.8"
resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.0.8.tgz#84daa52e7cf2fa8ce4195bc5cf0f7809e0930b24"
"@babel/helper-module-imports@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz#96081b7111e486da4d2cd971ad1a4fe216cc2e3d"
integrity sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==
dependencies:
base64-js "^1.0.2"
ieee754 "^1.1.4"
"@babel/types" "^7.0.0"
chain-function@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/chain-function/-/chain-function-1.0.0.tgz#0d4ab37e7e18ead0bdc47b920764118ce58733dc"
core-js@^1.0.0:
version "1.2.7"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
css-color-keywords@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05"
css-to-react-native@^2.0.3:
version "2.0.4"
resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-2.0.4.tgz#cf4cc407558b3474d4ba8be1a2cd3b6ce713101b"
"@babel/runtime@^7.1.2", "@babel/runtime@^7.4.2":
version "7.4.4"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.4.4.tgz#dc2e34982eb236803aa27a07fea6857af1b9171d"
integrity sha512-w0+uT71b6Yi7i5SE0co4NioIpSYS6lLiXvCzWzGSKvpK5vdQtCbICHMj+gbAKAOtxiV6HsVh/MBdaF9EQ6faSg==
dependencies:
css-color-keywords "^1.0.0"
fbjs "^0.8.5"
postcss-value-parser "^3.3.0"
regenerator-runtime "^0.13.2"
dom-helpers@^3.2.0:
version "3.2.1"
resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.2.1.tgz#3203e07fed217bd1f424b019735582fc37b2825a"
encoding@^0.1.11:
version "0.1.12"
resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb"
"@babel/types@^7.0.0":
version "7.4.4"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.4.4.tgz#8db9e9a629bb7c29370009b4b779ed93fe57d5f0"
integrity sha512-dOllgYdnEFOebhkKCjzSVFqw/PmmB8pH6RGOWkY4GsboQNd47b1fBThBSwlHAq9alF9vc1M3+6oqR47R50L0tQ==
dependencies:
iconv-lite "~0.4.13"
esutils "^2.0.2"
lodash "^4.17.11"
to-fast-properties "^2.0.0"
fbjs@^0.8.16, fbjs@^0.8.5, fbjs@^0.8.9:
version "0.8.16"
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db"
"@emotion/cache@^10.0.9":
version "10.0.9"
resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-10.0.9.tgz#e0c7b7a289f7530edcfad4dcf3858bd2e5700a6f"
integrity sha512-f7MblpE2xoimC4fCMZ9pivmsIn7hyWRIvY75owMDi8pdOSeh+w5tH3r4hBJv/LLrwiMM7cTQURqTPcYoL5pWnw==
dependencies:
core-js "^1.0.0"
isomorphic-fetch "^2.1.1"
loose-envify "^1.0.0"
object-assign "^4.1.0"
promise "^7.1.1"
setimmediate "^1.0.5"
ua-parser-js "^0.7.9"
"@emotion/sheet" "0.9.2"
"@emotion/stylis" "0.8.3"
"@emotion/utils" "0.11.1"
"@emotion/weak-memoize" "0.2.2"
has-flag@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
"@emotion/hash@0.7.1":
version "0.7.1"
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.7.1.tgz#9833722341379fb7d67f06a4b00ab3c37913da53"
integrity sha512-OYpa/Sg+2GDX+jibUfpZVn1YqSVRpYmTLF2eyAfrFTIJSbwyIrc+YscayoykvaOME/wV4BV0Sa0yqdMrgse6mA==
hoist-non-react-statics@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz#aa448cf0986d55cc40773b17174b7dd066cb7cfb"
"@emotion/memoize@0.7.1":
version "0.7.1"
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.1.tgz#e93c13942592cf5ef01aa8297444dc192beee52f"
integrity sha512-Qv4LTqO11jepd5Qmlp3M1YEjBumoTHcHFdgPTQ+sFlIL5myi/7xu/POwP7IRu6odBdmLXdtIs1D6TuW6kbwbbg==
iconv-lite@~0.4.13:
version "0.4.19"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b"
ieee754@^1.1.4:
version "1.1.8"
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4"
is-function@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5"
is-plain-object@^2.0.1:
version "2.0.4"
resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
"@emotion/serialize@^0.11.6":
version "0.11.6"
resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-0.11.6.tgz#78be8b9ee9ff49e0196233ba6ec1c1768ba1e1fc"
integrity sha512-n4zVv2qGLmspF99jaEUwnMV0fnEGsyUMsC/8KZKUSUTZMYljHE+j+B6rSD8PIFtaUIhHaxCG2JawN6L+OgLN0Q==
dependencies:
isobject "^3.0.1"
"@emotion/hash" "0.7.1"
"@emotion/memoize" "0.7.1"
"@emotion/unitless" "0.7.3"
"@emotion/utils" "0.11.1"
csstype "^2.5.7"
is-stream@^1.0.1:
"@emotion/sheet@0.9.2":
version "0.9.2"
resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-0.9.2.tgz#74e5c6b5e489a1ba30ab246ab5eedd96916487c4"
integrity sha512-pVBLzIbC/QCHDKJF2E82V2H/W/B004mDFQZiyo/MSR+VC4pV5JLG0TF/zgQDFvP3fZL/5RTPGEmXlYJBMUuJ+A==
"@emotion/stylis@0.8.3":
version "0.8.3"
resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.8.3.tgz#3ca7e9bcb31b3cb4afbaeb66156d86ee85e23246"
integrity sha512-M3nMfJ6ndJMYloSIbYEBq6G3eqoYD41BpDOxreE8j0cb4fzz/5qvmqU9Mb2hzsXcCnIlGlWhS03PCzVGvTAe0Q==
"@emotion/unitless@0.7.3":
version "0.7.3"
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.3.tgz#6310a047f12d21a1036fb031317219892440416f"
integrity sha512-4zAPlpDEh2VwXswwr/t8xGNDGg8RQiPxtxZ3qQEXyQsBV39ptTdESCjuBvGze1nLMVrxmTIKmnO/nAV8Tqjjzg==
"@emotion/utils@0.11.1":
version "0.11.1"
resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-0.11.1.tgz#8529b7412a6eb4b48bdf6e720cc1b8e6e1e17628"
integrity sha512-8M3VN0hetwhsJ8dH8VkVy7xo5/1VoBsDOk/T4SJOeXwTO1c4uIqVNx2qyecLFnnUWD5vvUqHQ1gASSeUN6zcTg==
"@emotion/weak-memoize@0.2.2":
version "0.2.2"
resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.2.tgz#63985d3d8b02530e0869962f4da09142ee8e200e"
integrity sha512-n/VQ4mbfr81aqkx/XmVicOLjviMuy02eenSdJY33SVA7S2J42EU0P1H0mOogfYedb3wXA0d/LVtBrgTSm04WEA==
argparse@^1.0.7:
version "1.0.10"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
dependencies:
sprintf-js "~1.0.2"
babel-plugin-emotion@^10.0.9:
version "10.0.9"
resolved "https://registry.yarnpkg.com/babel-plugin-emotion/-/babel-plugin-emotion-10.0.9.tgz#04a0404d5a4084d5296357a393d344c0f8303ae4"
integrity sha512-IfWP12e9/wHtWHxVTzD692Nbcmrmcz2tip7acp6YUqtrP7slAyr5B+69hyZ8jd55GsyNSZwryNnmuDEVe0j+7w==
dependencies:
"@babel/helper-module-imports" "^7.0.0"
"@emotion/hash" "0.7.1"
"@emotion/memoize" "0.7.1"
"@emotion/serialize" "^0.11.6"
babel-plugin-macros "^2.0.0"
babel-plugin-syntax-jsx "^6.18.0"
convert-source-map "^1.5.0"
escape-string-regexp "^1.0.5"
find-root "^1.1.0"
source-map "^0.5.7"
babel-plugin-macros@^2.0.0:
version "2.5.1"
resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.5.1.tgz#4a119ac2c2e19b458c259b9accd7ee34fd57ec6f"
integrity sha512-xN3KhAxPzsJ6OQTktCanNpIFnnMsCV+t8OloKxIL72D6+SUZYFn9qfklPgef5HyyDtzYZqqb+fs1S12+gQY82Q==
dependencies:
"@babel/runtime" "^7.4.2"
cosmiconfig "^5.2.0"
resolve "^1.10.0"
babel-plugin-syntax-jsx@^6.18.0:
version "6.18.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946"
integrity sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=
caller-callsite@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134"
integrity sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=
dependencies:
callsites "^2.0.0"
caller-path@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-2.0.0.tgz#468f83044e369ab2010fac5f06ceee15bb2cb1f4"
integrity sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=
dependencies:
caller-callsite "^2.0.0"
callsites@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50"
integrity sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=
convert-source-map@^1.5.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20"
integrity sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==
dependencies:
safe-buffer "~5.1.1"
cosmiconfig@^5.2.0:
version "5.2.1"
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a"
integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==
dependencies:
import-fresh "^2.0.0"
is-directory "^0.3.1"
js-yaml "^3.13.1"
parse-json "^4.0.0"
create-emotion@^10.0.9:
version "10.0.9"
resolved "https://registry.yarnpkg.com/create-emotion/-/create-emotion-10.0.9.tgz#290c2036126171c9566fa24f49c9241d54625138"
integrity sha512-sLKD4bIiTs8PpEqr5vlCoV5lsYE4QOBYEUWaD0R+VGRMCvBKHmYlvLJXsL99Kdc4YEFAFwipi2bbncnvv6UxRg==
dependencies:
"@emotion/cache" "^10.0.9"
"@emotion/serialize" "^0.11.6"
"@emotion/sheet" "0.9.2"
"@emotion/utils" "0.11.1"
csstype@^2.5.7:
version "2.6.4"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.4.tgz#d585a6062096e324e7187f80e04f92bd0f00e37f"
integrity sha512-lAJUJP3M6HxFXbqtGRc0iZrdyeN+WzOWeY0q/VnFzI+kqVrYIzC7bWlKqCW7oCIdzoPkvfp82EVvrTlQ8zsWQg==
dom-helpers@^3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.4.0.tgz#e9b369700f959f62ecde5a6babde4bccd9169af8"
integrity sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==
dependencies:
"@babel/runtime" "^7.1.2"
emotion@^10.0.1:
version "10.0.9"
resolved "https://registry.yarnpkg.com/emotion/-/emotion-10.0.9.tgz#2c37598af13df31dcd35a1957eaa8830f368c066"
integrity sha512-IMFwwWlU2TDt7eh4v6dm58E8VHAYOitqRbVoazQdxIu9/0CAH4a3UrTMnZSlWQAo09MrRRlKfgQFHswnj40meQ==
dependencies:
babel-plugin-emotion "^10.0.9"
create-emotion "^10.0.9"
error-ex@^1.3.1:
version "1.3.2"
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
dependencies:
is-arrayish "^0.2.1"
escape-string-regexp@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
esprima@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
esutils@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=
find-root@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4"
integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==
isobject@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
isomorphic-fetch@^2.1.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"
import-fresh@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546"
integrity sha1-2BNVwVYS04bGH53dOSLUMEgipUY=
dependencies:
node-fetch "^1.0.1"
whatwg-fetch ">=0.10.0"
caller-path "^2.0.0"
resolve-from "^3.0.0"
js-tokens@^3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
is-arrayish@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=
loose-envify@^1.0.0, loose-envify@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848"
is-directory@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1"
integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=
"js-tokens@^3.0.0 || ^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
js-yaml@^3.13.1:
version "3.13.1"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847"
integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==
dependencies:
js-tokens "^3.0.0"
argparse "^1.0.7"
esprima "^4.0.0"
node-fetch@^1.0.1:
version "1.7.3"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef"
json-parse-better-errors@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==
lodash@^4.17.11:
version "4.17.11"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==
loose-envify@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
dependencies:
encoding "^0.1.11"
is-stream "^1.0.1"
js-tokens "^3.0.0 || ^4.0.0"
object-assign@^4.1.0, object-assign@^4.1.1:
object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
postcss-value-parser@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz#87f38f9f18f774a4ab4c8a232f5c5ce8872a9d15"
promise@^7.1.1:
version "7.3.1"
resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf"
parse-json@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0"
integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=
dependencies:
asap "~2.0.3"
error-ex "^1.3.1"
json-parse-better-errors "^1.0.1"
prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.6:
version "15.6.0"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.0.tgz#ceaf083022fc46b4a35f69e13ef75aed0d639856"
path-parse@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
prop-types@^15.6.2:
version "15.7.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
dependencies:
fbjs "^0.8.16"
loose-envify "^1.3.1"
loose-envify "^1.4.0"
object-assign "^4.1.1"
react-is "^16.8.1"
react-loading-overlay@0.2.8:
version "0.2.8"
resolved "https://registry.yarnpkg.com/react-loading-overlay/-/react-loading-overlay-0.2.8.tgz#c1c5531c9cfa4be6caca6b9aa0c1eb19e22b03fe"
react-is@^16.8.1:
version "16.8.6"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16"
integrity sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA==
react-lifecycles-compat@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
react-loading-overlay@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/react-loading-overlay/-/react-loading-overlay-1.0.1.tgz#ee3b1ad56c45bb2f1ba46d4820ba0d06cd319a91"
integrity sha512-aUjtZ8tNXBSx+MbD2SQs0boPbeTAGTh+I5U9nWjDzMasKlYr58RJpr57c8W7uApeLpOkAGbInExRi6GamNC2bA==
dependencies:
prop-types "^15.5.10"
react-transition-group "^1.2.1"
styled-components "^2.1.2"
emotion "^10.0.1"
prop-types "^15.6.2"
react-transition-group "^2.5.0"
react-transition-group@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-1.2.1.tgz#e11f72b257f921b213229a774df46612346c7ca6"
react-transition-group@^2.5.0:
version "2.9.0"
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.9.0.tgz#df9cdb025796211151a436c69a8f3b97b5b07c8d"
integrity sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==
dependencies:
chain-function "^1.0.0"
dom-helpers "^3.2.0"
loose-envify "^1.3.1"
prop-types "^15.5.6"
warning "^3.0.0"
dom-helpers "^3.4.0"
loose-envify "^1.4.0"
prop-types "^15.6.2"
react-lifecycles-compat "^3.0.4"
setimmediate@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
regenerator-runtime@^0.13.2:
version "0.13.2"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz#32e59c9a6fb9b1a4aff09b4930ca2d4477343447"
integrity sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA==
styled-components@^2.1.2:
version "2.2.4"
resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-2.2.4.tgz#dd87fd3dafd359e7a0d570aec1bd07d691c0b5a2"
dependencies:
buffer "^5.0.3"
css-to-react-native "^2.0.3"
fbjs "^0.8.9"
hoist-non-react-statics "^1.2.0"
is-function "^1.0.1"
is-plain-object "^2.0.1"
prop-types "^15.5.4"
stylis "^3.4.0"
supports-color "^3.2.3"
stylis@^3.4.0:
version "3.4.5"
resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.4.5.tgz#d7b9595fc18e7b9c8775eca8270a9a1d3e59806e"
supports-color@^3.2.3:
version "3.2.3"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6"
dependencies:
has-flag "^1.0.0"
ua-parser-js@^0.7.9:
version "0.7.17"
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.17.tgz#e9ec5f9498b9ec910e7ae3ac626a805c4d09ecac"
warning@^3.0.0:
resolve-from@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/warning/-/warning-3.0.0.tgz#32e5377cb572de4ab04753bdf8821c01ed605b7c"
dependencies:
loose-envify "^1.0.0"
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748"
integrity sha1-six699nWiBvItuZTM17rywoYh0g=
whatwg-fetch@>=0.10.0:
version "2.0.3"
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84"
resolve@^1.10.0:
version "1.11.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.11.0.tgz#4014870ba296176b86343d50b60f3b50609ce232"
integrity sha512-WL2pBDjqT6pGUNSUzMw00o4T7If+z4H2x3Gz893WoUQ5KW8Vr9txp00ykiP16VBaZF5+j/OcXJHZ9+PCvdiDKw==
dependencies:
path-parse "^1.0.6"
safe-buffer@~5.1.1:
version "5.1.2"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
source-map@^0.5.7:
version "0.5.7"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
sprintf-js@~1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
to-fast-properties@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=

View File

@@ -69,23 +69,23 @@ Sometime, you may feel above props is not satisfied with your requirement, don't
* [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
### Fully Customization
If you want to customize the pagination component completely, you may get interesting on following solution:
If you want to customize the pagination component completely, you may get interesting on following solutions:
* 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:
`react-bootstrap-table2-paginator` have a `PaginationProvider` which is a react context and that will be easier to customize the pagination components under the scope of `PaginationProvider`. Let's introduce it step by step:
#### Import PaginationProvider
#### 1. Import PaginationProvider
```js
import paginationFactory, { PaginationProvider } from 'react-bootstrap-table2-paginator';
```
#### Declare custom and totalSize in pagination option:
#### 2. Declare custom and totalSize in pagination option:
```js
const paginationOption = {
@@ -94,7 +94,7 @@ const paginationOption = {
};
```
#### Render PaginationProvider
#### 3. Render PaginationProvider
```js
<PaginationProvider
@@ -139,18 +139,24 @@ So far, your customization pagination is supposed to look like it:
</PaginationProvider>
```
Now, you have to choose, your built-in standalne components or you customize all of them by yourself:
Now, you have to choose which solution you like: standalone or non-standalone ?
#### Use Standalone Component
`react-bootstrap-table2-paginator` provider two standalone components:
#### 4.1 Use Standalone Component
`react-bootstrap-table2-paginator` provider three standalone components:
* Size Per Page Dropdwn Standalone
* Pagination List Standalone
* Pagination Total 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';
import paginationFactory, {
PaginationProvider,
PaginationListStandalone,
SizePerPageDropdownStandalone,
PaginationTotalStandalone
} from 'react-bootstrap-table2-paginator';
<PaginationProvider
pagination={ paginationFactory(options) }
@@ -164,6 +170,9 @@ import paginationFactory, { PaginationProvider, PaginationListStandalone, SizePe
<SizePerPageDropdownStandalone
{ ...paginationProps }
/>
<PaginationTotalStandalone
{ ...paginationProps }
/>
<BootstrapTable
keyField="id"
data={ products }
@@ -181,7 +190,20 @@ import paginationFactory, { PaginationProvider, PaginationListStandalone, SizePe
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
##### Customizable props for `PaginationListStandalone`
* N/A
##### Customizable props for `SizePerPageDropdownStandalone`
* `open`: `true` to make dropdown show.
* `hidden`: `true` to hide the size per page dropdown.
* `btnContextual`: Set the button contextual
* `variation`: Variation for dropdown, available value is `dropdown` and `dropup`.
* `className`: Custom the class on size per page dropdown
##### Customizable props for `SizePerPageDropdownStandalone`
* N/A
#### 4.2 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:

View File

@@ -4,6 +4,7 @@ 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 PaginationTotalStandalone from './src/pagination-total-standalone';
export default (options = {}) => ({
createContext: createDataContext,
@@ -23,4 +24,4 @@ CustomizableProvider.propTypes = {
};
export const PaginationProvider = CustomizableProvider;
export { PaginationListStandalone, SizePerPageDropdownStandalone };
export { PaginationListStandalone, SizePerPageDropdownStandalone, PaginationTotalStandalone };

View File

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

View File

@@ -32,7 +32,12 @@ class PaginationDataProvider extends Provider {
// 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);
nextProps.data.length,
this.props.data.length,
this.currPage,
currSizePerPage,
pageStartIndex
);
if (this.currPage !== newPage) {
if (onPageChange) {
@@ -41,6 +46,9 @@ class PaginationDataProvider extends Provider {
this.currPage = newPage;
}
}
if (nextProps.onDataSizeChange && nextProps.data.length !== this.props.data.length) {
nextProps.onDataSizeChange({ dataSize: nextProps.data.length });
}
}
isRemotePagination = () => this.props.isRemotePagination();

View File

@@ -56,7 +56,7 @@ export default ExtendBase =>
alwaysShowAllBtns
} = this.props;
let pages;
let pages = [];
let endPage = totalPages;
if (endPage <= 0) return [];
@@ -68,24 +68,42 @@ export default ExtendBase =>
startPage = endPage - paginationSize + 1;
}
if (startPage !== pageStartIndex && totalPages > paginationSize && withFirstAndLast) {
if (alwaysShowAllBtns) {
if (withFirstAndLast) {
pages = [firstPageText, prePageText];
} else if (totalPages > 1 || alwaysShowAllBtns) {
pages = [prePageText];
} else {
pages = [];
pages = [prePageText];
}
}
if (startPage !== pageStartIndex &&
totalPages > paginationSize &&
withFirstAndLast &&
pages.length === 0
) {
pages = [firstPageText, prePageText];
} else if (totalPages > 1 && pages.length === 0) {
pages = [prePageText];
}
for (let i = startPage; i <= endPage; i += 1) {
if (i >= pageStartIndex) pages.push(i);
}
if (endPage <= lastPage && pages.length > 1) {
if (alwaysShowAllBtns || (endPage <= lastPage && pages.length > 1)) {
pages.push(nextPageText);
}
if (endPage !== lastPage && withFirstAndLast) {
if ((endPage !== lastPage && withFirstAndLast) || (withFirstAndLast && alwaysShowAllBtns)) {
pages.push(lastPageText);
}
// if ((endPage <= lastPage && pages.length > 1) || alwaysShowAllBtns) {
// pages.push(nextPageText);
// }
// if (endPage !== lastPage && withFirstAndLast) {
// pages.push(lastPageText);
// }
return pages;
}

View File

@@ -1,3 +1,5 @@
import Const from './const';
const getNormalizedPage = (
page,
pageStartIndex
@@ -19,12 +21,20 @@ const startIndex = (
export const alignPage = (
dataSize,
prevDataSize,
page,
sizePerPage,
pageStartIndex
) => {
if (page < pageStartIndex || page > (Math.floor(dataSize / sizePerPage) + pageStartIndex)) {
return pageStartIndex;
if (prevDataSize < dataSize) return page;
if (page < pageStartIndex) return pageStartIndex;
if (dataSize <= 0) return pageStartIndex;
if ((page >= (Math.floor(dataSize / sizePerPage) + pageStartIndex)) && pageStartIndex === 1) {
return Math.ceil(dataSize / sizePerPage);
}
if (page >= Math.floor(dataSize / sizePerPage) && pageStartIndex === 0) {
const newPage = Math.ceil(dataSize / sizePerPage);
return newPage - Math.abs((Const.PAGE_START_INDEX - pageStartIndex));
}
return page;
};

View File

@@ -0,0 +1,24 @@
/* eslint react/prop-types: 0 */
import React, { Component } from 'react';
import pageResolver from './page-resolver';
import PaginationTotal from './pagination-total';
const paginationTotalAdapter = WrappedComponent =>
class PaginationTotalAdapter extends pageResolver(Component) {
render() {
const [from, to] = this.calculateFromTo();
return (
<WrappedComponent
from={ from }
to={ to }
dataSize={ this.props.dataSize }
paginationTotalRenderer={ this.props.paginationTotalRenderer }
/>
);
}
};
export const PaginationTotalWithAdapter = paginationTotalAdapter(PaginationTotal);
export default paginationTotalAdapter;

View File

@@ -0,0 +1,11 @@
import React from 'react';
import PaginationTotal from './pagination-total';
import standaloneAdapter from './standalone-adapter';
import paginationTotalAdapter from './pagination-total-adapter';
const PaginationTotalStandalone = props => (
<PaginationTotal { ...props } />
);
export default
standaloneAdapter(paginationTotalAdapter(PaginationTotalStandalone));

View File

@@ -1,16 +1,26 @@
import React from 'react';
import PropTypes from 'prop-types';
const PaginationTotal = props => (
const PaginationTotal = (props) => {
if (props.paginationTotalRenderer) {
return props.paginationTotalRenderer(props.from, props.to, props.dataSize);
}
return (
<span className="react-bootstrap-table-pagination-total">
&nbsp;Showing rows { props.from } to&nbsp;{ props.to } of&nbsp;{ props.dataSize }
</span>
);
};
PaginationTotal.propTypes = {
from: PropTypes.number.isRequired,
to: PropTypes.number.isRequired,
dataSize: PropTypes.number.isRequired
dataSize: PropTypes.number.isRequired,
paginationTotalRenderer: PropTypes.func
};
PaginationTotal.defaultProps = {
paginationTotalRenderer: undefined
};
export default PaginationTotal;

View File

@@ -5,30 +5,16 @@ 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 { SizePerPageDropdownWithAdapter } from './size-per-page-dropdown-adapter';
import { PaginationListWithAdapter } from './pagination-list-adapter';
import PaginationTotal from './pagination-total';
import { PaginationTotalWithAdapter } from './pagination-total-adapter';
import Const from './const';
class Pagination extends pageResolver(Component) {
defaultTotal = (from, to, size) => (
<PaginationTotal
from={ from }
to={ to }
dataSize={ size }
/>
);
setTotal = (from, to, size, total) => {
if (total && (typeof total === 'function')) {
return total(from, to, size);
}
return this.defaultTotal(from, to, size);
};
render() {
const {
currPage,
pageStartIndex,
showTotal,
dataSize,
pageListRenderer,
@@ -48,7 +34,6 @@ class Pagination extends pageResolver(Component) {
} = this.props;
const pages = this.calculatePageStatus(this.calculatePages(totalPages, lastPage), lastPage);
const [from, to] = this.calculateFromTo();
const pageListClass = cs(
'react-bootstrap-table-pagination-list',
'col-md-6 col-xs-6 col-sm-6 col-lg-6', {
@@ -57,7 +42,7 @@ 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
<SizePerPageDropdownWithAdapter
sizePerPageList={ sizePerPageList }
currSizePerPage={ currSizePerPage }
hideSizePerPage={ hideSizePerPage }
@@ -67,12 +52,13 @@ class Pagination extends pageResolver(Component) {
/>
{
showTotal ?
this.setTotal(
from,
to,
dataSize,
paginationTotalRenderer
) : null
<PaginationTotalWithAdapter
currPage={ currPage }
currSizePerPage={ currSizePerPage }
pageStartIndex={ pageStartIndex }
dataSize={ dataSize }
paginationTotalRenderer={ paginationTotalRenderer }
/> : null
}
</div>
{
@@ -83,6 +69,9 @@ class Pagination extends pageResolver(Component) {
<div className={ pageListClass }>
<PaginationListWithAdapter
{ ...rest }
currPage={ currPage }
currSizePerPage={ currSizePerPage }
pageStartIndex={ pageStartIndex }
lastPage={ lastPage }
totalPages={ totalPages }
pageButtonRenderer={ pageButtonRenderer }

View File

@@ -48,6 +48,7 @@ const sizePerPageDropdownAdapter = WrappedComponent =>
}
return (
<WrappedComponent
{ ...this.props }
currSizePerPage={ `${currSizePerPage}` }
options={ this.calculateSizePerPageStatus() }
optionRenderer={ sizePerPageOptionRenderer }
@@ -63,5 +64,5 @@ const sizePerPageDropdownAdapter = WrappedComponent =>
};
export const SizePerPageDropdownAdapter = sizePerPageDropdownAdapter(SizePerPageDropDown);
export const SizePerPageDropdownWithAdapter = sizePerPageDropdownAdapter(SizePerPageDropDown);
export default sizePerPageDropdownAdapter;

View File

@@ -50,11 +50,17 @@ class StateProvider extends React.Component {
// user should align the page when the page is not fit to the data size when remote enable
if (this.isRemotePagination() || custom) {
if (typeof nextProps.pagination.options.page !== 'undefined') {
this.currPage = nextProps.pagination.options.page;
}
if (typeof nextProps.pagination.options.sizePerPage !== 'undefined') {
this.currSizePerPage = nextProps.pagination.options.sizePerPage;
}
if (typeof nextProps.pagination.options.totalSize !== 'undefined') {
this.dataSize = nextProps.pagination.options.totalSize;
}
}
}
getPaginationProps = () => {
const { pagination: { options }, bootstrap4 } = this.props;
@@ -117,13 +123,14 @@ class StateProvider extends React.Component {
const { pagination: { options } } = this.props;
const pageStartIndex = typeof options.pageStartIndex === 'undefined' ?
Const.PAGE_START_INDEX : options.pageStartIndex;
this.dataSize = newDataSize;
this.currPage = alignPage(
newDataSize,
this.dataSize,
this.currPage,
this.currSizePerPage,
pageStartIndex
);
this.dataSize = newDataSize;
this.forceUpdate();
}

View File

@@ -43,18 +43,132 @@ describe('Page Functions', () => {
});
describe('alignPage', () => {
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', () => {
it('should return pageStartIndex argument', () => {
expect(alignPage(15, page, sizePerPage, pageStartIndex)).toEqual(pageStartIndex);
let newDataSize;
let prevDataSize;
let currPage;
let pageStartIndex;
let sizePerPage;
describe('if prevDataSize < newDataSize', () => {
beforeEach(() => {
newDataSize = 10;
prevDataSize = 6;
currPage = 2;
pageStartIndex = 1;
sizePerPage = 5;
});
it('should return same page', () => {
expect(alignPage(
newDataSize,
prevDataSize,
currPage,
sizePerPage,
pageStartIndex
)).toEqual(currPage);
});
});
describe('if the length of store.data is large than the end page index', () => {
it('should return current page', () => {
expect(alignPage(30, page, sizePerPage, pageStartIndex)).toEqual(page);
describe('if currPage < newDataSize', () => {
beforeEach(() => {
newDataSize = 10;
prevDataSize = 12;
currPage = 0;
pageStartIndex = 1;
sizePerPage = 5;
});
it('should return correct page', () => {
expect(alignPage(
newDataSize,
prevDataSize,
currPage,
sizePerPage,
pageStartIndex
)).toEqual(pageStartIndex);
});
});
describe('if partStartIndex is default 1', () => {
describe('and currPage is bigger than newest last page', () => {
beforeEach(() => {
newDataSize = 9;
prevDataSize = 12;
currPage = 3;
pageStartIndex = 1;
sizePerPage = 5;
});
it('should return correct page', () => {
expect(alignPage(
newDataSize,
prevDataSize,
currPage,
sizePerPage,
pageStartIndex
)).toEqual(2);
});
});
describe('and currPage is short than newest last page', () => {
beforeEach(() => {
newDataSize = 11;
prevDataSize = 12;
currPage = 3;
pageStartIndex = 1;
sizePerPage = 5;
});
it('should return correct page', () => {
expect(alignPage(
newDataSize,
prevDataSize,
currPage,
sizePerPage,
pageStartIndex
)).toEqual(currPage);
});
});
});
describe('if partStartIndex is default 0', () => {
describe('and currPage is bigger than newest last page', () => {
beforeEach(() => {
newDataSize = 8;
prevDataSize = 11;
currPage = 2;
pageStartIndex = 0;
sizePerPage = 5;
});
it('should return correct page', () => {
expect(alignPage(
newDataSize,
prevDataSize,
currPage,
sizePerPage,
pageStartIndex
)).toEqual(1);
});
});
describe('and currPage is short than newest last page', () => {
beforeEach(() => {
newDataSize = 11;
prevDataSize = 12;
currPage = 2;
pageStartIndex = 0;
sizePerPage = 5;
});
it('should return correct page', () => {
expect(alignPage(
newDataSize,
prevDataSize,
currPage,
sizePerPage,
pageStartIndex
)).toEqual(currPage);
});
});
});
});

View File

@@ -0,0 +1,34 @@
import React from 'react';
import { shallow } from 'enzyme';
import paginationTotalAdapter from '../src/pagination-total-adapter';
const MockComponent = () => null;
const PaginationTotalAdapter = paginationTotalAdapter(MockComponent);
describe('paginationTotalAdapter', () => {
let wrapper;
const props = {
dataSize: 20,
currPage: 1,
currSizePerPage: 10,
paginationTotalRenderer: jest.fn()
};
describe('render', () => {
beforeEach(() => {
wrapper = shallow(<PaginationTotalAdapter { ...props } />);
});
it('should render successfully', () => {
const mockComponent = wrapper.find(MockComponent);
expect(mockComponent).toHaveLength(1);
expect(mockComponent.props().from).toBeDefined();
expect(mockComponent.props().to).toBeDefined();
expect(mockComponent.props().dataSize).toEqual(props.dataSize);
expect(mockComponent.props().paginationTotalRenderer).toEqual(props.paginationTotalRenderer);
});
});
});

View File

@@ -1,11 +1,10 @@
import React from 'react';
import sinon from 'sinon';
import { shallow } from 'enzyme';
import { shallow, render } 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;
@@ -107,28 +106,24 @@ describe('Pagination', () => {
describe('when props.showTotal is true', () => {
beforeEach(() => {
const props = createMockProps({ showTotal: true });
wrapper = shallow(<Pagination { ...props } />);
wrapper.render();
instance = wrapper.instance();
wrapper = render(<Pagination { ...props } />);
});
it('should render PaginationTotal correctly', () => {
expect(wrapper.dive().find(PaginationTotal)).toHaveLength(1);
expect(wrapper.find('.react-bootstrap-table-pagination-total')).toHaveLength(1);
});
describe('if props.paginationTotalRenderer is defined', () => {
let paginationTotalRenderer;
beforeEach(() => {
paginationTotalRenderer = jest.fn();
paginationTotalRenderer = jest.fn(() => <div />);
const props = createMockProps({ showTotal: true, paginationTotalRenderer });
wrapper = shallow(<Pagination { ...props } />);
wrapper.render();
instance = wrapper.instance();
wrapper = render(<Pagination { ...props } />);
});
it('should not render PaginationTotal', () => {
expect(wrapper.dive().find(PaginationTotal)).toHaveLength(0);
expect(wrapper.find('.react-bootstrap-table-pagination-total')).toHaveLength(0);
});
it('should call props.paginationTotalRenderer correctly', () => {

View File

@@ -2,9 +2,15 @@
`react-bootstrap-table2` support some additional features in [`react-bootstrap-table2-toolkit`](https://github.com/react-bootstrap-table/react-bootstrap-table2/tree/develop/packages/react-bootstrap-table2-toolkit).
In the future, this toolkit will support other feature like row delete, insert etc. Right now we only support Table Search and CSV export.
In the future, this toolkit will support other feature like row delete, insert etc. Right now we only following features:
* Table Search
* Export CSV
* Column Toggle
**[Live Demo For Table Search](https://react-bootstrap-table.github.io/react-bootstrap-table2/storybook/index.html?selectedKind=Table%20Search)**
**[Live Demo For Export CSV](https://react-bootstrap-table.github.io/react-bootstrap-table2/storybook/index.html?selectedKind=Export%20CSV&selectedStory=Basic%20Export%20CSV)**
**[Live Demo For Column Toggle](https://react-bootstrap-table.github.io/react-bootstrap-table2/storybook/index.html?selectedKind=Column%20Toggle&selectedStory=Basic%20Column%20Toggle)**
**[API&Props Definitation](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/pagination-props.html)**
@@ -61,6 +67,19 @@ const { SearchBar } = Search;
3. You should render `SearchBar` with `searchProps` as well. The position of `SearchBar` is depends on you.
### `SearchBar` Props
#### className - [string]
Custom the class on input element.
#### placeholder - [string]
Custom the placeholder on input element.
#### style - [object]
Custom the style on input element.
#### delay = [number]
milionsecond for debounce user input.
### Search Options
#### defaultSearch - [string]
@@ -121,6 +140,8 @@ const { SearchBar, ClearSearchButton } = Search;
</ToolkitProvider>
```
-----
## Export CSV
There are two steps to enable the export CSV functionality:
@@ -164,8 +185,50 @@ Default is `false`. Give true to avoid to attach the csv header.
#### noAutoBOM - [bool]
Default is `true`.
#### blobType - [string]
Default is `text/plain;charset=utf-8`. Change to update the blob type of the exported file.
#### exportAll - [bool]
Default is `true`. `false` will only export current data which display on table.
#### onlyExportSelection - [bool]
Default is `false`. `true` will only export the data which is selected.
#### onlyExportFiltered - [bool]
Default is `false`. `true` will only export the data which is filtered/searched.
>> When you configure this prop as true, you must turn off `exportAll`.
-----
## Column Toggle
Let's see how to render the column toggle in your react component:
```js
import BootstrapTable from 'react-bootstrap-table-next';
import ToolkitProvider, { ColumnToggle } from 'react-bootstrap-table2-toolkit';
<ToolkitProvider
keyField="id"
data={ products }
columns={ columns }
columnToggle
>
{
props => (
<div>
<ToggleList { ...props.columnToggleProps } />
<hr />
<BootstrapTable
{ ...props.baseProps }
/>
</div>
)
}
</ToolkitProvider>
```
> `columnToggleProps` props have enough information to let you custom the toggle list: [demo]([Live Demo For Export CSV](https://react-bootstrap-table.github.io/react-bootstrap-table2/storybook/index.html?selectedKind=Export%20CSV&selectedStory=Custom%20Column%20Toggle))
If you want to have default visibility on specified column, you can just give `true` or `false` on `column.hidden`.

View File

@@ -1,13 +1,14 @@
/* eslint no-param-reassign: 0 */
import React from 'react';
import PropTypes from 'prop-types';
import statelessDrcorator from './statelessOp';
import statelessDecorator from './statelessOp';
import createContext from './src/search/context';
import createSearchContext 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,
@@ -28,7 +29,9 @@ class ToolkitProvider extends statelessDrcorator(React.Component) {
separator: PropTypes.string,
ignoreHeader: PropTypes.bool,
noAutoBOM: PropTypes.bool,
blobType: PropTypes.string,
exportAll: PropTypes.bool,
onlyExportFiltered: PropTypes.bool,
onlyExportSelection: PropTypes.bool
})
])
@@ -42,13 +45,22 @@ class ToolkitProvider extends statelessDrcorator(React.Component) {
constructor(props) {
super(props);
this.state = {
searchText: typeof props.search === 'object' ? (props.search.defaultSearch || '') : ''
};
const state = {};
this._ = null;
this.onClear = this.onClear.bind(this);
this.onSearch = this.onSearch.bind(this);
this.onColumnToggle = this.onColumnToggle.bind(this);
this.setDependencyModules = this.setDependencyModules.bind(this);
if (props.columnToggle) {
state.columnToggle = props.columns
.reduce((obj, column) => {
obj[column.dataField] = !column.hidden;
return obj;
}, {});
}
state.searchText = typeof props.search === 'object' ? (props.search.defaultSearch || '') : '';
this.state = state;
}
onSearch(searchText) {
@@ -61,6 +73,14 @@ class ToolkitProvider extends statelessDrcorator(React.Component) {
this.setState({ searchText: '' });
}
onColumnToggle(dataField) {
const { columnToggle } = this.state;
columnToggle[dataField] = !columnToggle[dataField];
this.setState(({
...this.state,
columnToggle
}));
}
/**
*
* @param {*} _
@@ -84,10 +104,15 @@ class ToolkitProvider extends statelessDrcorator(React.Component) {
};
if (this.props.search) {
baseProps.search = {
searchContext: createContext(this.props.search),
searchContext: createSearchContext(this.props.search),
searchText: this.state.searchText
};
}
if (this.props.columnToggle) {
baseProps.columnToggle = {
toggles: this.state.columnToggle
};
}
return (
<ToolkitContext.Provider value={ {
searchProps: {
@@ -98,6 +123,11 @@ class ToolkitProvider extends statelessDrcorator(React.Component) {
csvProps: {
onExport: this.handleExportCSV
},
columnToggleProps: {
columns: this.props.columns,
toggles: this.state.columnToggle,
onColumnToggle: this.onColumnToggle
},
baseProps
} }
>

View File

@@ -5,3 +5,4 @@ export default ToolkitProvider;
export const ToolkitContext = Context;
export { default as Search } from './src/search';
export { default as CSVExport } from './src/csv';
export { default as ColumnToggle } from './src/column-toggle';

View File

@@ -1,6 +1,6 @@
{
"name": "react-bootstrap-table2-toolkit",
"version": "1.2.2",
"version": "2.0.1",
"description": "The toolkit for react-bootstrap-table2",
"main": "./lib/index.js",
"repository": {
@@ -45,6 +45,6 @@
"react-dom": "^16.3.0"
},
"dependencies": {
"file-saver": "1.3.8"
"file-saver": "2.0.2"
}
}

View File

@@ -0,0 +1,3 @@
import ToggleList from './toggle-list';
export default { ToggleList };

View File

@@ -0,0 +1,50 @@
import React from 'react';
import PropTypes from 'prop-types';
const ToggleList = ({
columns,
onColumnToggle,
toggles,
contextual,
className,
btnClassName
}) => (
<div className={ `btn-group btn-group-toggle ${className}` } data-toggle="buttons">
{
columns
.map(column => ({
...column,
toggle: toggles[column.dataField]
}))
.map(column => (
<button
type="button"
key={ column.dataField }
className={ `${btnClassName} btn btn-${contextual} ${column.toggle ? 'active' : ''}` }
data-toggle="button"
aria-pressed={ column.toggle ? 'true' : 'false' }
onClick={ () => onColumnToggle(column.dataField) }
>
{ column.text }
</button>
))
}
</div>
);
ToggleList.propTypes = {
columns: PropTypes.array.isRequired,
toggles: PropTypes.object.isRequired,
onColumnToggle: PropTypes.func.isRequired,
btnClassName: PropTypes.string,
className: PropTypes.string,
contextual: PropTypes.string
};
ToggleList.defaultProps = {
btnClassName: '',
className: '',
contextual: 'primary'
};
export default ToggleList;

View File

@@ -5,12 +5,14 @@ const ExportCSVButton = (props) => {
const {
onExport,
children,
className,
...rest
} = props;
return (
<button
type="button"
className={ `react-bs-table-csv-btn btn btn-default ${className}` }
onClick={ () => onExport() }
{ ...rest }
>
@@ -26,7 +28,7 @@ ExportCSVButton.propTypes = {
style: PropTypes.object
};
ExportCSVButton.defaultProps = {
className: 'react-bs-table-csv-btn btn btn-default',
className: '',
style: {}
};

View File

@@ -42,7 +42,7 @@ export const transform = (
cellContent = m.formatter(cellContent, row, rowIndex, m.formatExtraData);
}
if (m.type === String) {
return `"${cellContent}"`;
return `"${`${cellContent}`.replace(/"/g, '""')}"`;
}
return cellContent;
}).join(separator)).join('\n');
@@ -54,11 +54,12 @@ export const save = (
content,
{
noAutoBOM,
fileName
fileName,
blobType
}
) => {
FileSaver.saveAs(
new Blob([content], { type: 'text/plain;charset=utf-8' }),
new Blob([content], { type: blobType }),
fileName,
noAutoBOM
);

View File

@@ -5,6 +5,7 @@ const csvDefaultOptions = {
separator: ',',
ignoreHeader: false,
noAutoBOM: true,
blobType: 'text/plain;charset=utf-8',
exportAll: true,
onlyExportSelection: false
};
@@ -27,19 +28,24 @@ export default Base =>
data = source;
} else if (options.exportAll) {
data = this.props.data;
} else if (options.onlyExportFiltered) {
const payload = {};
this.tableExposedAPIEmitter.emit('get.filtered.rows', payload);
data = payload.result;
} else {
const payload = {};
this.tableExposedAPIEmitter.emit('get.table.data', payload);
data = payload.result;
}
// filter data
// filter data by row selection
if (options.onlyExportSelection) {
const payload = {};
this.tableExposedAPIEmitter.emit('get.selected.rows', payload);
const selections = payload.result;
data = data.filter(row => !!selections.find(sel => row[keyField] === sel));
}
const content = transform(data, meta, this._.get, options);
save(content, options);
}

View File

@@ -54,20 +54,29 @@ class SearchBar extends React.Component {
const {
className,
style,
placeholder
placeholder,
tableId
} = this.props;
return (
<label
htmlFor={ `search-bar-${tableId}` }
className="search-label"
>
<span className="sr-only">Search this table</span>
<input
ref={ n => this.input = n }
id={ `search-bar-${tableId}` }
type="text"
style={ style }
aria-label="enter text you want to search"
onKeyUp={ () => this.onKeyup() }
onChange={ this.onChangeValue }
className={ `form-control ${className}` }
value={ this.state.value }
placeholder={ placeholder || SearchBar.defaultProps.placeholder }
/>
</label>
);
}
}
@@ -78,7 +87,8 @@ SearchBar.propTypes = {
placeholder: PropTypes.string,
style: PropTypes.object,
delay: PropTypes.number,
searchText: PropTypes.string
searchText: PropTypes.string,
tableId: PropTypes.string
};
SearchBar.defaultProps = {
@@ -86,7 +96,8 @@ SearchBar.defaultProps = {
style: {},
placeholder: 'Search',
delay: 250,
searchText: ''
searchText: '',
tableId: '0'
};
export default SearchBar;

View File

@@ -3,18 +3,21 @@ import PropTypes from 'prop-types';
const ClearButton = ({
onClear,
text
text,
className
}) => (
<button className="btn btn-default" onClick={ onClear }>{ text }</button>
<button className={ `btn btn-default ${className}` } onClick={ onClear }>{ text }</button>
);
ClearButton.propTypes = {
onClear: PropTypes.func.isRequired,
className: PropTypes.string,
text: PropTypes.string
};
ClearButton.defaultProps = {
text: 'Clear'
text: 'Clear',
className: ''
};
export default ClearButton;

View File

@@ -59,6 +59,10 @@ export default (options = {
}
}
getSearched() {
return this.state.data;
}
triggerListener(result) {
if (this.props.dataChangeListener) {
this.props.dataChangeListener.emit('filterChanged', result.length);

View File

@@ -0,0 +1,3 @@
.search-label {
display: block !important;
}

View File

@@ -2,6 +2,7 @@
# yarn lockfile v1
file-saver@1.3.8:
version "1.3.8"
resolved "https://registry.yarnpkg.com/file-saver/-/file-saver-1.3.8.tgz#e68a30c7cb044e2fb362b428469feb291c2e09d8"
file-saver@2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/file-saver/-/file-saver-2.0.2.tgz#06d6e728a9ea2df2cce2f8d9e84dfcdc338ec17a"
integrity sha512-Wz3c3XQ5xroCxd1G8b7yL0Ehkf0TC9oYC6buPFkNnU9EnaPlifeAFCyCh+iewXTyFRcg0a6j3J7FmJsIhlhBdw==

View File

@@ -1,6 +1,6 @@
{
"name": "react-bootstrap-table-next",
"version": "2.1.2",
"version": "3.1.4",
"description": "Next generation of react-bootstrap-table",
"main": "./lib/index.js",
"repository": {
@@ -37,6 +37,7 @@
],
"dependencies": {
"classnames": "2.2.5",
"react-transition-group": "2.5.3",
"underscore": "1.9.1"
},
"peerDependencies": {

View File

@@ -17,7 +17,6 @@ class Body extends React.Component {
super(props);
const {
keyField,
visibleColumnSize,
cellEdit,
selectRow,
expandRow
@@ -34,7 +33,7 @@ class Body extends React.Component {
const expandRowEnabled = !!expandRow.renderer;
if (expandRowEnabled) {
RowComponent = withRowExpansion(RowAggregator, visibleColumnSize);
RowComponent = withRowExpansion(RowAggregator);
}
if (selectRowEnabled) {

View File

@@ -18,6 +18,14 @@ class BootstrapTable extends PropsBaseResolver(Component) {
this.validateProps();
}
componentWillReceiveProps(nextProps) {
if (nextProps.onDataSizeChange && !nextProps.pagination) {
if (nextProps.data.length !== this.props.data.length) {
nextProps.onDataSizeChange({ dataSize: nextProps.data.length });
}
}
}
// Exposed APIs
getData = () => {
return this.visibleRows();
@@ -159,7 +167,13 @@ BootstrapTable.propTypes = {
bgColor: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
hideSelectColumn: PropTypes.bool,
selectionRenderer: PropTypes.func,
selectionHeaderRenderer: PropTypes.func
selectionHeaderRenderer: PropTypes.func,
headerColumnStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
selectColumnStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
selectColumnPosition: PropTypes.oneOf([
Const.INDICATOR_POSITION_LEFT,
Const.INDICATOR_POSITION_RIGHT
])
}),
expandRow: PropTypes.shape({
renderer: PropTypes.func,
@@ -192,6 +206,7 @@ BootstrapTable.propTypes = {
onSort: PropTypes.func,
onFilter: PropTypes.func,
onExternalFilter: PropTypes.func,
onDataSizeChange: PropTypes.func,
// Inject from toolkit
search: PropTypes.shape({
searchText: PropTypes.string,

View File

@@ -8,7 +8,7 @@ import _ from './utils';
class Cell extends eventDelegater(Component) {
constructor(props) {
super(props);
this.handleEditingCell = this.handleEditingCell.bind(this);
this.createHandleEditingCell = this.createHandleEditingCell.bind(this);
}
shouldComponentUpdate(nextProps) {
@@ -23,7 +23,10 @@ class Cell extends eventDelegater(Component) {
if (shouldUpdate) return true;
// if (nextProps.formatter)
shouldUpdate =
(nextProps.column.formatter ? !_.isEqual(this.props.row, nextProps.row) : false) ||
this.props.column.hidden !== nextProps.column.hidden ||
this.props.rowIndex !== nextProps.rowIndex ||
this.props.columnIndex !== nextProps.columnIndex ||
@@ -40,17 +43,10 @@ class Cell extends eventDelegater(Component) {
return shouldUpdate;
}
handleEditingCell(e) {
const { column, onStart, rowIndex, columnIndex, clickToEdit, dbclickToEdit } = this.props;
const { events } = column;
if (events) {
if (clickToEdit) {
const customClick = events.onClick;
if (_.isFunction(customClick)) customClick(e);
} else if (dbclickToEdit) {
const customDbClick = events.onDoubleClick;
if (_.isFunction(customDbClick)) customDbClick(e);
}
createHandleEditingCell = originFunc => (e) => {
const { onStart, rowIndex, columnIndex, clickToEdit, dbclickToEdit } = this.props;
if ((clickToEdit || dbclickToEdit) && _.isFunction(originFunc)) {
originFunc(e);
}
if (onStart) {
onStart(rowIndex, columnIndex);
@@ -82,9 +78,9 @@ class Cell extends eventDelegater(Component) {
}
if (clickToEdit && editable) {
attrs.onClick = this.handleEditingCell;
attrs.onClick = this.createHandleEditingCell(attrs.onClick);
} else if (dbclickToEdit && editable) {
attrs.onDoubleClick = this.handleEditingCell;
attrs.onDoubleClick = this.createHandleEditingCell(attrs.onDoubleClick);
}
return (

View File

@@ -0,0 +1,39 @@
/* eslint react/prop-types: 0 */
/* eslint react/prefer-stateless-function: 0 */
import React from 'react';
import PropTypes from 'prop-types';
export default () => {
const ColumnManagementContext = React.createContext();
class ColumnManagementProvider extends React.Component {
static propTypes = {
columns: PropTypes.array.isRequired,
toggles: PropTypes.object
}
static defaultProps = {
toggles: null
}
render() {
let toggleColumn;
const { columns, toggles } = this.props;
if (toggles) {
toggleColumn = columns.filter(column => toggles[column.dataField]);
} else {
toggleColumn = columns.filter(column => !column.hidden);
}
return (
<ColumnManagementContext.Provider value={ { columns: toggleColumn } }>
{ this.props.children }
</ColumnManagementContext.Provider>
);
}
}
return {
Provider: ColumnManagementProvider,
Consumer: ColumnManagementContext.Consumer
};
};

View File

@@ -5,6 +5,7 @@ import React, { Component } from 'react';
import EventEmitter from 'events';
import _ from '../utils';
import createDataContext from './data-context';
import createColumnMgtContext from './column-context';
import createSortContext from './sort-context';
import SelectionContext from './selection-context';
import RowExpandContext from './row-expand-context';
@@ -22,6 +23,15 @@ const withContext = Base =>
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());
exposedAPIEmitter.on('get.filtered.rows', (payload) => {
if (this.searchContext) {
payload.result = this.searchContext.getSearched();
} else if (this.filterContext) {
payload.result = this.filterContext.getFiltered();
} else {
payload.result = this.table.getData();
}
});
props.registerExposedAPI(exposedAPIEmitter);
}
@@ -30,6 +40,13 @@ const withContext = Base =>
dataOperator, this.isRemoteSort, this.handleRemoteSortChange);
}
if (
props.columnToggle ||
props.columns.filter(col => col.hidden).length > 0
) {
this.ColumnManagementContext = createColumnMgtContext();
}
if (props.selectRow) {
this.SelectionContext = SelectionContext;
}
@@ -83,6 +100,7 @@ const withContext = Base =>
searchProps,
sortProps,
paginationProps,
columnToggleProps
) => (
<Base
ref={ n => this.table = n }
@@ -91,11 +109,40 @@ const withContext = Base =>
{ ...filterProps }
{ ...searchProps }
{ ...paginationProps }
{ ...columnToggleProps }
data={ rootProps.getData(filterProps, searchProps, sortProps, paginationProps) }
/>
);
}
renderWithColumnManagementCtx(base, baseProps) {
return (
rootProps,
filterProps,
searchProps,
sortProps,
paginationProps
) => (
<this.ColumnManagementContext.Provider
{ ...baseProps }
toggles={ this.props.columnToggle ? this.props.columnToggle.toggles : null }
>
<this.ColumnManagementContext.Consumer>
{
columnToggleProps => base(
rootProps,
filterProps,
searchProps,
sortProps,
paginationProps,
columnToggleProps
)
}
</this.ColumnManagementContext.Consumer>
</this.ColumnManagementContext.Provider>
);
}
renderWithSelectionCtx(base, baseProps) {
return (
rootProps,
@@ -164,6 +211,7 @@ const withContext = Base =>
bootstrap4={ this.props.bootstrap4 }
isRemotePagination={ this.isRemotePagination }
remoteEmitter={ this.remoteEmitter }
onDataSizeChange={ this.props.onDataSizeChange }
>
<this.PaginationContext.Consumer>
{
@@ -256,6 +304,7 @@ const withContext = Base =>
return rootProps => (
<this.CellEditContext.Provider
{ ...baseProps }
ref={ n => this.cellEditContext = n }
selectRow={ this.props.selectRow }
cellEdit={ this.props.cellEdit }
data={ rootProps.getData() }
@@ -271,6 +320,10 @@ const withContext = Base =>
let base = this.renderBase();
if (this.ColumnManagementContext) {
base = this.renderWithColumnManagementCtx(base, baseProps);
}
if (this.SelectionContext) {
base = this.renderWithSelectionCtx(base, baseProps);
}

View File

@@ -2,6 +2,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import dataOperator from '../store/operators';
import _ from '../utils';
const RowExpandContext = React.createContext();
@@ -10,18 +11,35 @@ class RowExpandProvider extends React.Component {
children: PropTypes.node.isRequired,
data: PropTypes.array.isRequired,
keyField: PropTypes.string.isRequired
}
};
state = { expanded: this.props.expandRow.expanded || [] };
state = { expanded: this.props.expandRow.expanded || [],
isClosing: this.props.expandRow.isClosing || [] };
componentWillReceiveProps(nextProps) {
if (nextProps.expandRow) {
const nextExpanded = nextProps.expandRow.expanded || this.state.expanded;
const isClosing = this.state.expanded.reduce((acc, cur) => {
if (!nextExpanded.includes(cur)) {
acc.push(cur);
}
return acc;
}, []);
this.setState(() => ({
expanded: nextProps.expandRow.expanded || this.state.expanded
expanded: nextExpanded,
isClosing
}));
} else {
this.setState(() => ({
expanded: this.state.expanded
}));
}
}
onClosed = (closedRow) => {
this.setState({ isClosing: this.state.isClosing.filter(value => value !== closedRow) });
};
handleRowExpand = (rowKey, expanded, rowIndex, e) => {
const { data, keyField, expandRow: { onExpand, onlyOneExpanding, nonExpandable } } = this.props;
if (nonExpandable && nonExpandable.includes(rowKey)) {
@@ -29,11 +47,15 @@ class RowExpandProvider extends React.Component {
}
let currExpanded = [...this.state.expanded];
let isClosing = [...this.state.isClosing];
if (expanded) {
if (onlyOneExpanding) currExpanded = [rowKey];
else currExpanded.push(rowKey);
if (onlyOneExpanding) {
isClosing = isClosing.concat(currExpanded);
currExpanded = [rowKey];
} else currExpanded.push(rowKey);
} else {
isClosing.push(rowKey);
currExpanded = currExpanded.filter(value => value !== rowKey);
}
@@ -41,8 +63,8 @@ class RowExpandProvider extends React.Component {
const row = dataOperator.getRowByRowId(data, keyField, rowKey);
onExpand(row, expanded, rowIndex, e);
}
this.setState(() => ({ expanded: currExpanded }));
}
this.setState(() => ({ expanded: currExpanded, isClosing }));
};
handleAllRowExpand = (e, expandAll) => {
const {
@@ -60,7 +82,7 @@ class RowExpandProvider extends React.Component {
if (expandAll) {
currExpanded = expanded.concat(dataOperator.expandableKeys(data, keyField, nonExpandable));
} else {
currExpanded = expanded.filter(s => typeof data.find(d => d[keyField] === s) === 'undefined');
currExpanded = expanded.filter(s => typeof data.find(d => _.get(d, keyField) === s) === 'undefined');
}
if (onExpandAll) {
@@ -68,7 +90,7 @@ class RowExpandProvider extends React.Component {
}
this.setState(() => ({ expanded: currExpanded }));
}
};
render() {
const { data, keyField } = this.props;
@@ -78,6 +100,8 @@ class RowExpandProvider extends React.Component {
...this.props.expandRow,
nonExpandable: this.props.expandRow.nonExpandable,
expanded: this.state.expanded,
isClosing: this.state.isClosing,
onClosed: this.onClosed,
isAnyExpands: dataOperator.isAnyExpands(data, keyField, this.state.expanded),
onRowExpand: this.handleRowExpand,
onAllRowExpand: this.handleAllRowExpand

View File

@@ -14,26 +14,27 @@ class SelectionProvider extends React.Component {
keyField: PropTypes.string.isRequired
}
state = { selected: this.props.selectRow.selected || [] };
constructor(props) {
super(props);
this.selected = props.selectRow.selected || [];
}
componentWillReceiveProps(nextProps) {
if (nextProps.selectRow) {
this.setState(() => ({
selected: nextProps.selectRow.selected || this.state.selected
}));
this.selected = nextProps.selectRow.selected || this.selected;
}
}
// exposed API
getSelected() {
return this.state.selected;
return this.selected;
}
handleRowSelect = (rowKey, checked, rowIndex, e) => {
const { data, keyField, selectRow: { mode, onSelect } } = this.props;
const { ROW_SELECT_SINGLE } = Const;
let currSelected = [...this.state.selected];
let currSelected = [...this.selected];
let result = true;
if (onSelect) {
@@ -41,7 +42,6 @@ class SelectionProvider extends React.Component {
result = onSelect(row, checked, rowIndex, e);
}
this.setState(() => {
if (result === true || result === undefined) {
if (mode === ROW_SELECT_SINGLE) { // when select mode is radio
currSelected = [rowKey];
@@ -51,8 +51,8 @@ class SelectionProvider extends React.Component {
currSelected = currSelected.filter(value => value !== rowKey);
}
}
return { selected: currSelected };
});
this.selected = currSelected;
this.forceUpdate();
}
handleAllRowsSelect = (e, isUnSelect) => {
@@ -64,7 +64,7 @@ class SelectionProvider extends React.Component {
nonSelectable
}
} = this.props;
const { selected } = this.state;
const { selected } = this;
let currSelected;
@@ -81,7 +81,7 @@ class SelectionProvider extends React.Component {
dataOperator.getSelectedRows(
data,
keyField,
isUnSelect ? this.state.selected : currSelected
isUnSelect ? selected : currSelected
),
e
);
@@ -89,7 +89,8 @@ class SelectionProvider extends React.Component {
currSelected = result;
}
}
this.setState(() => ({ selected: currSelected }));
this.selected = currSelected;
this.forceUpdate();
}
render() {
@@ -99,7 +100,7 @@ class SelectionProvider extends React.Component {
} = getSelectionSummary(
this.props.data,
this.props.keyField,
this.state.selected
this.selected
);
let checkedStatus;
@@ -113,7 +114,7 @@ class SelectionProvider extends React.Component {
<SelectionContext.Provider
value={ {
...this.props.selectRow,
selected: this.state.selected,
selected: this.selected,
onRowSelect: this.handleRowSelect,
onAllRowsSelect: this.handleAllRowsSelect,
allRowsSelected,

View File

@@ -11,12 +11,12 @@ const Footer = (props) => {
const SelectionFooterCellComp = () => <th />;
const ExpansionFooterCellComp = () => <th />;
const isRenderExpandColumnInLeft = (
expandColumnPosition = Const.INDICATOR_POSITION_LEFT
) => expandColumnPosition === Const.INDICATOR_POSITION_LEFT;
const isRenderFunctionColumnInLeft = (
position = Const.INDICATOR_POSITION_LEFT
) => position === Const.INDICATOR_POSITION_LEFT;
const childrens = columns.map((column, i) => {
if (column.footer === undefined || column.footer === null || column.hidden) {
if (column.footer === undefined || column.footer === null) {
return false;
}
@@ -33,11 +33,15 @@ const Footer = (props) => {
});
if (selectRow && selectRow.hideSelectColumn !== true) {
if (isRenderFunctionColumnInLeft(selectRow.selectColumnPosition)) {
childrens.unshift(<SelectionFooterCellComp key="selection" />);
} else {
childrens.push(<SelectionFooterCellComp key="selection" />);
}
}
if (expandRow.showExpandColumn) {
if (isRenderExpandColumnInLeft(expandRow.expandColumnPosition)) {
if (isRenderFunctionColumnInLeft(expandRow.expandColumnPosition)) {
childrens.unshift(<ExpansionFooterCellComp key="expansion" />);
} else {
childrens.push(<ExpansionFooterCellComp key="expansion" />);

View File

@@ -40,7 +40,8 @@ const HeaderCell = (props) => {
const cellAttrs = {
..._.isFunction(headerAttrs) ? headerAttrs(column, index) : headerAttrs,
...headerEvents
...headerEvents,
tabIndex: 0
};
let sortSymbol;

View File

@@ -33,13 +33,12 @@ const Header = (props) => {
SelectionHeaderCellComp = withHeaderSelection(SelectionHeaderCell);
}
const isRenderExpandColumnInLeft = (
expandColumnPosition = Const.INDICATOR_POSITION_LEFT
) => expandColumnPosition === Const.INDICATOR_POSITION_LEFT;
const isRenderFunctionColumnInLeft = (
position = Const.INDICATOR_POSITION_LEFT
) => position === Const.INDICATOR_POSITION_LEFT;
const childrens = [
columns.map((column, i) => {
if (!column.hidden) {
const currSort = column.dataField === sortField;
const isLastSorting = column.dataField === sortField;
@@ -55,17 +54,19 @@ const Header = (props) => {
sortOrder={ sortOrder }
isLastSorting={ isLastSorting }
/>);
}
return false;
})
];
if (!selectRow.hideSelectColumn) {
if (isRenderFunctionColumnInLeft(selectRow.selectColumnPosition)) {
childrens.unshift(<SelectionHeaderCellComp key="selection" />);
} else {
childrens.push(<SelectionHeaderCellComp key="selection" />);
}
}
if (expandRow.showExpandColumn) {
if (isRenderExpandColumnInLeft(expandRow.expandColumnPosition)) {
if (isRenderFunctionColumnInLeft(expandRow.expandColumnPosition)) {
childrens.unshift(<ExpansionHeaderCellComp key="expansion" />);
} else {
childrens.push(<ExpansionHeaderCellComp key="expansion" />);

View File

@@ -1,18 +1,37 @@
import React from 'react';
import PropTypes from 'prop-types';
import { CSSTransition } from 'react-transition-group';
const ExpandRow = ({ children, ...rest }) => (
<tr className="expanding-row">
<td { ...rest }>{ children }</td>
const ExpandRow = ({ children, expanded, onClosed, ...rest }) => (
<tr>
<td className="reset-expansion-style" { ...rest }>
<CSSTransition
appear
in={ expanded }
timeout={ 400 }
classNames="row-expand-slide"
onExited={ onClosed }
>
<div>
<div className="row-expansion-style">
{ children }
</div>
</div>
</CSSTransition>
</td>
</tr>
);
ExpandRow.propTypes = {
children: PropTypes.node
children: PropTypes.node,
expanded: PropTypes.bool,
onClosed: PropTypes.func
};
ExpandRow.defaultProps = {
children: null
children: null,
expanded: false,
onClosed: null
};
export default ExpandRow;

View File

@@ -3,13 +3,13 @@ import React from 'react';
import ExpandRow from './expand-row';
import ExpansionContext from '../contexts/row-expand-context';
export default (Component, visibleColumnSize) => {
export default (Component) => {
const renderWithExpansion = (props, expandRow) => {
const key = props.value;
const expanded = expandRow.expanded.includes(key);
const isClosing = expandRow.isClosing.includes(key);
const expandable = !expandRow.nonExpandable || !expandRow.nonExpandable.includes(key);
return [
<Component
{ ...props }
@@ -18,9 +18,11 @@ export default (Component, visibleColumnSize) => {
expandable={ expandable }
expandRow={ { ...expandRow } }
/>,
expanded ? <ExpandRow
expanded || isClosing ? <ExpandRow
key={ `${key}-expanding` }
colSpan={ visibleColumnSize }
colSpan={ props.visibleColumnSize }
expanded={ expanded }
onClosed={ () => expandRow.onClosed(key) }
>
{ expandRow.renderer(props.row) }
</ExpandRow> : null

View File

@@ -5,6 +5,7 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Const from '../const';
import _ from '../utils';
import { BootstrapContext } from '../contexts/bootstrap';
export default class SelectionCell extends Component {
@@ -17,7 +18,8 @@ export default class SelectionCell extends Component {
rowIndex: PropTypes.number,
tabIndex: PropTypes.number,
clickToSelect: PropTypes.bool,
selectionRenderer: PropTypes.func
selectionRenderer: PropTypes.func,
selectColumnStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.func])
}
constructor() {
@@ -31,7 +33,8 @@ export default class SelectionCell extends Component {
this.props.selected !== nextProps.selected ||
this.props.disabled !== nextProps.disabled ||
this.props.rowKey !== nextProps.rowKey ||
this.props.tabIndex !== nextProps.tabIndex;
this.props.tabIndex !== nextProps.tabIndex ||
this.props.selectColumnStyle !== nextProps.selectColumnStyle;
return shouldUpdate;
}
@@ -43,12 +46,10 @@ export default class SelectionCell extends Component {
selected,
onRowSelect,
disabled,
rowIndex,
clickToSelect
rowIndex
} = this.props;
e.stopPropagation();
if (disabled) return;
if (clickToSelect) return;
const checked = inputType === Const.ROW_SELECT_SINGLE
? true
@@ -59,16 +60,28 @@ export default class SelectionCell extends Component {
render() {
const {
rowKey,
mode: inputType,
selected,
disabled,
tabIndex,
selectionRenderer
rowIndex,
selectionRenderer,
selectColumnStyle
} = this.props;
const attrs = {};
if (tabIndex !== -1) attrs.tabIndex = tabIndex;
attrs.style = _.isFunction(selectColumnStyle) ?
selectColumnStyle({
checked: selected,
disabled,
rowIndex,
rowKey
}) :
selectColumnStyle;
return (
<BootstrapContext.Consumer>
{
@@ -78,7 +91,8 @@ export default class SelectionCell extends Component {
selectionRenderer ? selectionRenderer({
mode: inputType,
checked: selected,
disabled
disabled,
rowIndex
}) : (
<input
type={ inputType }

View File

@@ -3,6 +3,7 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Const from '../const';
import { BootstrapContext } from '../contexts/bootstrap';
import _ from '../utils';
export const CheckBox = ({ className, checked, indeterminate }) => (
<input
@@ -28,7 +29,8 @@ export default class SelectionHeaderCell extends Component {
checkedStatus: PropTypes.string,
onAllRowsSelect: PropTypes.func,
hideSelectAll: PropTypes.bool,
selectionHeaderRenderer: PropTypes.func
selectionHeaderRenderer: PropTypes.func,
headerColumnStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.func])
}
constructor() {
@@ -64,7 +66,13 @@ export default class SelectionHeaderCell extends Component {
CHECKBOX_STATUS_CHECKED, CHECKBOX_STATUS_INDETERMINATE, ROW_SELECT_MULTIPLE
} = Const;
const { mode, checkedStatus, selectionHeaderRenderer, hideSelectAll } = this.props;
const {
mode,
checkedStatus,
selectionHeaderRenderer,
hideSelectAll,
headerColumnStyle
} = this.props;
if (hideSelectAll) {
return <th data-row-selection />;
}
@@ -79,6 +87,10 @@ export default class SelectionHeaderCell extends Component {
attrs.onClick = this.handleCheckBoxClick;
}
attrs.style = _.isFunction(headerColumnStyle) ?
headerColumnStyle(checkedStatus) :
headerColumnStyle;
return (
<BootstrapContext.Consumer>
{

View File

@@ -45,10 +45,10 @@ export default class RowAggregator extends shouldUpdater(eventDelegater(React.Co
return this.shouldUpdateRowContent;
}
isRenderExpandColumnInLeft(
expandColumnPosition = Const.INDICATOR_POSITION_LEFT
isRenderFunctionColumnInLeft(
position = Const.INDICATOR_POSITION_LEFT
) {
return expandColumnPosition === Const.INDICATOR_POSITION_LEFT;
return position === Const.INDICATOR_POSITION_LEFT;
}
render() {
@@ -71,7 +71,7 @@ export default class RowAggregator extends shouldUpdater(eventDelegater(React.Co
...rest
} = this.props;
const key = _.get(row, keyField);
const { hideSelectColumn, clickToSelect } = selectRow;
const { hideSelectColumn, selectColumnPosition, clickToSelect } = selectRow;
const { showExpandColumn, expandColumnPosition } = expandRow;
const newAttrs = this.delegate({ ...attrs });
@@ -95,7 +95,7 @@ export default class RowAggregator extends shouldUpdater(eventDelegater(React.Co
)];
if (!hideSelectColumn) {
childrens.unshift((
const selectCell = (
<SelectionCell
{ ...selectRow }
key="selection-cell"
@@ -105,7 +105,12 @@ export default class RowAggregator extends shouldUpdater(eventDelegater(React.Co
disabled={ !selectable }
tabIndex={ tabIndexCell ? tabIndexStart++ : -1 }
/>
));
);
if (this.isRenderFunctionColumnInLeft(selectColumnPosition)) {
childrens.unshift(selectCell);
} else {
childrens.push(selectCell);
}
}
if (showExpandColumn) {
@@ -120,7 +125,7 @@ export default class RowAggregator extends shouldUpdater(eventDelegater(React.Co
tabIndex={ tabIndexCell ? tabIndexStart++ : -1 }
/>
);
if (this.isRenderExpandColumnInLeft(expandColumnPosition)) {
if (this.isRenderFunctionColumnInLeft(expandColumnPosition)) {
childrens.unshift(expandCell);
} else {
childrens.push(expandCell);

View File

@@ -33,7 +33,6 @@ export default class RowPureContent extends React.Component {
let tabIndex = tabIndexStart;
return columns.map((column, index) => {
if (!column.hidden) {
const { dataField } = column;
const content = _.get(row, dataField);
if (rowIndex === editingRowIdx && index === editingColIdx) {
@@ -117,8 +116,6 @@ export default class RowPureContent extends React.Component {
{ ...cellAttrs }
/>
);
}
return false;
});
}
}

View File

@@ -8,7 +8,8 @@ export default ExtendBase =>
return (
nextProps.editingRowIdx === nextProps.rowIndex ||
(this.props.editingRowIdx === nextProps.rowIndex &&
nextProps.editingRowIdx === null)
nextProps.editingRowIdx === null) ||
this.props.editingRowIdx === nextProps.rowIndex
);
}
@@ -26,7 +27,7 @@ export default ExtendBase =>
return true;
}
for (let i = 0; i < this.props.columns.length; i += 1) {
if (this.props.columns[i].hidden !== nextProps.columns[i].hidden) {
if (!_.isEqual(this.props.columns[i], nextProps.columns[i])) {
return true;
}
}

View File

@@ -1,4 +1,5 @@
import _ from '../utils';
export const matchRow = (keyField, id) => row => row[keyField] === id;
export const matchRow = (keyField, id) => row => _.get(row, keyField) === id;
export const getRowByRowId = (data, keyField, id) => data.find(matchRow(keyField, id));

View File

@@ -68,10 +68,6 @@
text-align: center;
}
tr.expanding-row {
padding: 5px;
}
td.react-bootstrap-table-editing-cell {
.animated {
animation-fill-mode: both;
@@ -161,4 +157,26 @@
animation-name: bounceOut;
}
}
.reset-expansion-style{
padding: 0;
}
.row-expansion-style{
padding: 8px;
}
.row-expand-slide-appear{
max-height: 0;
overflow: hidden;
}
.row-expand-slide-appear-active{
max-height: 1000px;
transition: max-height 3s linear;
}
.row-expand-slide-exit{
max-height: 1000px;
}
.row-expand-slide-exit-active{
max-height: 0;
overflow: hidden;
transition: max-height 400ms cubic-bezier(0, 0.95, 0, 0.95)
}
}

View File

@@ -124,10 +124,10 @@ describe('Cell', () => {
onClick: sinon.stub()
};
});
it('should calling custom onClick callback also', () => {
it('should call onStart correctly', () => {
wrapper.find('td').simulate('click');
expect(onStartCallBack.callCount).toBe(1);
expect(column.events.onClick.callCount).toBe(1);
});
});
});
@@ -164,10 +164,10 @@ describe('Cell', () => {
onDoubleClick: sinon.stub()
};
});
it('should calling custom onDoubleClick callback also', () => {
it('should call onStart correctly', () => {
wrapper.find('td').simulate('doubleclick');
expect(onStartCallBack.callCount).toBe(1);
expect(column.events.onDoubleClick.callCount).toBe(1);
});
});
});
@@ -218,6 +218,47 @@ describe('Cell', () => {
});
});
describe('when props.row is change', () => {
describe('and column.formatter is enable', () => {
const column = { dataField: 'name', text: 'Product Name', formatter: () => 123 };
beforeEach(() => {
props = {
row,
columnIndex: 1,
rowIndex: 1,
tabIndex: 5,
column
};
wrapper = shallow(
<Cell { ...props } />);
});
it('should return true', () => {
nextProps = { ...props, row: { ...row, alert: 'test' } };
expect(wrapper.instance().shouldComponentUpdate(nextProps)).toBe(true);
});
});
describe('but column.formatter is disable', () => {
const column = { dataField: 'name', text: 'Product Name' };
beforeEach(() => {
props = {
row,
columnIndex: 1,
rowIndex: 1,
tabIndex: 5,
column
};
wrapper = shallow(
<Cell { ...props } />);
});
it('should return true', () => {
nextProps = { ...props, row: { ...row, alert: 'test' } };
expect(wrapper.instance().shouldComponentUpdate(nextProps)).toBe(false);
});
});
});
describe('if column.isDummyField is true', () => {
describe('when content is change', () => {
const column = { dataField: '', text: 'Product Name', isDummyField: true };

View File

@@ -0,0 +1,104 @@
import 'jsdom-global/register';
import React from 'react';
import { shallow } from 'enzyme';
import BootstrapTable from '../../src/bootstrap-table';
import createColumnManagementContext from '../../src/contexts/column-context';
describe('ColumnManagementContext', () => {
let wrapper;
const data = [{
id: 1,
name: 'A'
}, {
id: 2,
name: 'B'
}];
const columns = [{
dataField: 'id',
text: 'ID'
}, {
dataField: 'name',
text: 'Name'
}];
const mockBase = jest.fn((props => (
<BootstrapTable
data={ data }
columns={ columns }
keyField="id"
{ ...props }
/>
)));
const ColumnManagementContext = createColumnManagementContext();
function shallowContext(options = {}) {
return (
<ColumnManagementContext.Provider
data={ data }
columns={ columns }
{ ...options }
>
<ColumnManagementContext.Consumer>
{
columnToggleProps => mockBase(columnToggleProps)
}
</ColumnManagementContext.Consumer>
</ColumnManagementContext.Provider>
);
}
describe('default render', () => {
beforeEach(() => {
wrapper = shallow(shallowContext());
wrapper.render();
});
it('should have correct Provider property after calling createColumnManagementContext', () => {
expect(ColumnManagementContext.Provider).toBeDefined();
});
it('should have correct Consumer property after calling createColumnManagementContext', () => {
expect(ColumnManagementContext.Consumer).toBeDefined();
});
});
describe('when toggles props exist', () => {
beforeEach(() => {
wrapper = shallow(shallowContext({
toggles: {
id: true,
name: false
}
}));
});
it('should render component with correct columns props', () => {
expect(wrapper.prop('value').columns).toHaveLength(columns.length - 1);
expect(wrapper.prop('value').columns[0].dataField).toEqual('id');
});
});
describe('if there is any column.hidden is true', () => {
beforeEach(() => {
wrapper = shallow(shallowContext({
columns: [{
dataField: 'id',
text: 'ID'
}, {
dataField: 'name',
text: 'Name',
hidden: true
}]
}));
});
it('should render component with correct columns props', () => {
expect(wrapper.prop('value').columns).toHaveLength(columns.length - 1);
expect(wrapper.prop('value').columns[0].dataField).toEqual('id');
});
});
});

Some files were not shown because too many files have changed in this diff Show More