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) * [pagination](#pagination)
* [filter](#filter) * [filter](#filter)
* [onTableChange](#onTableChange) * [onTableChange](#onTableChange)
* [onDataSizeChange](#onDataSizeChange)
### <a name='keyField'>keyField(**required**) - [String]</a> ### <a name='keyField'>keyField(**required**) - [String]</a>
Tells `react-bootstrap-table2` which column is unique. 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... // omit...
beforeSaveCell(oldValue, newValue, row, column, done) { beforeSaveCell(oldValue, newValue, row, column, done) {
setTimeout(() => { 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 done(); // contine to save the changes
} else { } else {
done(false); // reject the changes 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> ## <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 ```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) * [`react-bootstrap-table2-overlay`](https://www.npmjs.com/package/react-bootstrap-table2-overlay)
* Overlay/Loading Addons * Overlay/Loading Addons
* [`react-bootstrap-table2-toolkit`](https://www.npmjs.com/package/react-bootstrap-table2-toolkit) * [`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. 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 # Row expand
`react-bootstrap-table2` supports the row expand feature. By passing prop `expandRow` to enable this functionality. `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 ## Required
* [renderer (**required**)](#renderer) * [renderer (**required**)](#renderer)

View File

@@ -1,6 +1,6 @@
# Row selection # 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 ## Required
* [mode (**required**)](#mode) * [mode (**required**)](#mode)
@@ -16,10 +16,13 @@
* [clickToEdit](#clickToEdit) * [clickToEdit](#clickToEdit)
* [onSelect](#onSelect) * [onSelect](#onSelect)
* [onSelectAll](#onSelectAll) * [onSelectAll](#onSelectAll)
* [selectColumnPosition](#selectColumnPosition)
* [hideSelectColumn](#hideSelectColumn) * [hideSelectColumn](#hideSelectColumn)
* [hideSelectAll](#hideSelectAll) * [hideSelectAll](#hideSelectAll)
* [selectionRenderer](#selectionRenderer) * [selectionRenderer](#selectionRenderer)
* [selectionHeaderRenderer](#selectionHeaderRenderer) * [selectionHeaderRenderer](#selectionHeaderRenderer)
* [headerColumnStyle](#headerColumnStyle)
* [selectColumnStyle](#selectColumnStyle)
### <a name="mode">selectRow.mode - [String]</a> ### <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 ```js
const selectRow = { const selectRow = {
mode: 'checkbox', 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. > 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> ### <a name='onSelect'>selectRow.onSelect - [Function]</a>
This callback function will be called when a row is select/unselect and pass following three arguments: This callback function will be called when a row is select/unselect and pass following three arguments:
`row`, `isSelect`, `rowIndex` and `e`. `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> ### <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` 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": { "jest": {
"collectCoverageFrom": [ "collectCoverageFrom": [
"packages/*/src/**/*.js", "packages/*/src/**/*.js",
"packages/*/index.js" "packages/*/index.js",
"!packages/react-bootstrap-table2-example/**/*.js"
], ],
"roots": [ "roots": [
"<rootDir>/packages" "<rootDir>/packages"

View File

@@ -89,7 +89,10 @@ const columns = [
In the following, we go though all the predefined editors: In the following, we go though all the predefined editors:
### Dropdown Editor ### 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 ```js
import { Type } from 'react-bootstrap-table2-editor'; 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
Date editor is use `<input type="date">`, the configuration is very simple: Date editor is use `<input type="date">`, the configuration is very simple:
@@ -132,7 +175,7 @@ const columns = [
if (typeof cell !== 'object') { if (typeof cell !== 'object') {
dateObj = new Date(cell); 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: { editor: {
type: Type.DATE type: Type.DATE

View File

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

View File

@@ -4,6 +4,15 @@ import cs from 'classnames';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
class DropDownEditor extends Component { 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() { componentDidMount() {
const { defaultValue, didMount } = this.props; const { defaultValue, didMount } = this.props;
this.select.value = defaultValue; this.select.value = defaultValue;
@@ -11,12 +20,16 @@ class DropDownEditor extends Component {
if (didMount) didMount(); if (didMount) didMount();
} }
setOptions(options) {
this.setState({ options });
}
getValue() { getValue() {
return this.select.value; return this.select.value;
} }
render() { 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 editorClass = cs('form-control editor edit-select', className);
const attr = { const attr = {
@@ -31,7 +44,7 @@ class DropDownEditor extends Component {
defaultValue={ defaultValue } defaultValue={ defaultValue }
> >
{ {
options.map(({ label, value }) => ( this.state.options.map(({ label, value }) => (
<option key={ value } value={ value }>{ label }</option> <option key={ value } value={ value }>{ label }</option>
)) ))
} }
@@ -52,13 +65,16 @@ DropDownEditor.propTypes = {
label: PropTypes.string, label: PropTypes.string,
value: PropTypes.any value: PropTypes.any
})) }))
]).isRequired, ]),
didMount: PropTypes.func didMount: PropTypes.func,
getOptions: PropTypes.func
}; };
DropDownEditor.defaultProps = { DropDownEditor.defaultProps = {
className: '', className: '',
defaultValue: '', defaultValue: '',
style: {}, style: {},
didMount: undefined options: [],
didMount: undefined,
getOptions: undefined
}; };
export default DropDownEditor; 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 paginationStylePath = path.join(__dirname, '../../react-bootstrap-table2-paginator/style');
const filterStylePath = path.join(__dirname, '../../react-bootstrap-table2-filter/style'); const filterStylePath = path.join(__dirname, '../../react-bootstrap-table2-filter/style');
const toolkitSourcePath = path.join(__dirname, '../../react-bootstrap-table2-toolkit/index.js'); 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 storyPath = path.join(__dirname, '../stories');
const examplesPath = path.join(__dirname, '../examples'); const examplesPath = path.join(__dirname, '../examples');
const srcPath = path.join(__dirname, '../src'); const srcPath = path.join(__dirname, '../src');
@@ -43,7 +44,13 @@ const loaders = [{
}, { }, {
test: /\.scss$/, test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader'], 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)$/, test: /\.(jpg|png|woff|woff2|eot|ttf|svg)$/,
loader: 'url-loader?limit=100000', loader: 'url-loader?limit=100000',

View File

@@ -45,8 +45,12 @@ class ExposedFunctionTable extends React.Component {
console.log(this.node.table.props.data); console.log(this.node.table.props.data);
} }
handleGetCurrentData = () => {
console.log(this.node.table.props.data);
}
handleGetSelectedData = () => { handleGetSelectedData = () => {
console.log(this.node.selectionContext.state.selected); console.log(this.node.selectionContext.selected);
} }
handleGetExpandedData = () => { handleGetExpandedData = () => {
@@ -117,7 +121,7 @@ export default class ExposedFunctionTable extends React.Component {
} }
handleGetSelectedData = () => { handleGetSelectedData = () => {
console.log(this.node.selectionContext.state.selected); console.log(this.node.selectionContext.selected);
} }
handleGetExpandedData = () => { 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 = { static defaultProps = {
value: 0 value: 0
} }
componentDidMount() {
this.range.focus();
}
getValue() { getValue() {
return parseInt(this.range.value, 10); return parseInt(this.range.value, 10);
} }

View File

@@ -23,7 +23,7 @@ const columns = [{
if (typeof cell !== 'object') { if (typeof cell !== 'object') {
dateObj = new Date(cell); 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: { editor: {
type: Type.DATE type: Type.DATE
@@ -48,7 +48,7 @@ const columns = [{
if (typeof cell !== 'object') { if (typeof cell !== 'object') {
dateObj = new Date(cell); 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: { editor: {
type: Type.DATE 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 } { 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 = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next'; 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 { class ProductList extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { products }; this.state = { products, count: 0 };
} }
toggleInStock = () => { toggleInStock = () => {
@@ -163,17 +35,96 @@ class ProductList extends React.Component {
}; };
render() { 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 ( return (
<div> <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 <BootstrapTable
keyField="id" keyField="id"
data={ this.state.products } data={ this.state.products }
columns={ columns } columns={ columns }
/> />
<button onClick={ this.toggleInStock } className="btn btn-primary"> <Code>{ sourceCode }</Code>
Toggle item 13 stock status
</button>
</div> </div>
); );
} }
@@ -183,7 +134,7 @@ class ProductList extends React.Component {
class ProductList extends React.Component { class ProductList extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { products }; this.state = { products, count: 0 };
} }
toggleInStock = () => { toggleInStock = () => {
@@ -200,13 +151,95 @@ class ProductList extends React.Component {
this.setState(curr => ({ ...curr, products: newProducts })); this.setState(curr => ({ ...curr, products: newProducts }));
}; };
counter = () => {
this.setState(curr => ({ ...curr, count: this.state.count + 1 }));
}
render() { 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 ( return (
<div> <div>
<h3>Action 1 and Action 2 are dummy column</h3> <h3>Action 1 and Action 2 are dummy column</h3>
<button onClick={ this.toggleInStock } className="btn btn-primary"> <button onClick={ this.toggleInStock } className="btn btn-primary">
Toggle item 13 stock status Toggle item 13 stock status
</button> </button>
<button
className="btn btn-success"
onClick={ this.counter }
>
Click me to Increase counter
</button>
<BootstrapTable <BootstrapTable
keyField="id" keyField="id"
data={ this.state.products } 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 Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';
const products = productsGenerator(21); const products = productsGenerator(40);
const { SearchBar } = Search; const { SearchBar } = Search;
const columns = [{ const columns = [{
@@ -24,61 +24,12 @@ import paginationFactory, { PaginationProvider, PaginationListStandalone } from
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter'; import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
class Table extends React.Component { class Table extends React.Component {
render() { state = { products }
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
};
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 ( loadData = () => {
<div> this.setState({ products: productsGenerator(17) });
<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() { render() {
const options = { const options = {
custom: true, custom: true,
@@ -93,15 +44,84 @@ export default class Table extends React.Component {
firstPageTitle: 'Next page', firstPageTitle: 'Next page',
lastPageTitle: 'Last page', lastPageTitle: 'Last page',
showTotal: true, showTotal: true,
totalSize: products.length totalSize: this.state.products.length
}; };
const contentTable = ({ paginationProps, paginationTableProps }) => ( const contentTable = ({ paginationProps, paginationTableProps }) => (
<div> <div>
<button className="btn btn-default" onClick={ this.loadData }>Load Another Data</button>
<PaginationListStandalone { ...paginationProps } /> <PaginationListStandalone { ...paginationProps } />
<ToolkitProvider <ToolkitProvider
keyField="id" keyField="id"
columns={ columns } 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 search
> >
{ {

View File

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

View File

@@ -43,6 +43,7 @@ const columns = [{
}]; }];
const expandRow = { const expandRow = {
onlyOneExpanding: true,
renderer: row => ( renderer: row => (
<div> <div>
<p>{ \`This Expand row is belong to rowKey $\{row.id}\` }</p> <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", "name": "react-bootstrap-table2-example",
"version": "1.0.17", "version": "1.0.26",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"private": true, "private": true,

View File

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

View File

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

View File

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

View File

@@ -18,7 +18,7 @@ const legalComparators = [
]; ];
function dateParser(d) { 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 { class DateFilter extends Component {
@@ -132,24 +132,35 @@ class DateFilter extends Component {
className={ `filter date-filter ${className}` } className={ `filter date-filter ${className}` }
style={ style } style={ style }
> >
<select <label
ref={ n => this.dateFilterComparator = n } className="filter-label"
style={ comparatorStyle } htmlFor={ `date-filter-comparator-${text}` }
className={ `date-filter-comparator form-control ${comparatorClassName}` }
onChange={ this.onChangeComparator }
defaultValue={ defaultValue ? defaultValue.comparator : '' }
> >
{ this.getComparatorOptions() } <span className="sr-only">Filter comparator</span>
</select> <select
<input ref={ n => this.dateFilterComparator = n }
ref={ n => this.inputDate = n } id={ `date-filter-comparator-${text}` }
className={ `filter date-filter-input form-control ${dateClassName}` } style={ comparatorStyle }
style={ dateStyle } className={ `date-filter-comparator form-control ${comparatorClassName}` }
type="date" onChange={ this.onChangeComparator }
onChange={ this.onChangeDate } defaultValue={ defaultValue ? defaultValue.comparator : '' }
placeholder={ placeholder || `Enter ${text}...` } >
defaultValue={ this.getDefaultDate() } { 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"
onChange={ this.onChangeDate }
placeholder={ placeholder || `Enter ${text}...` }
defaultValue={ this.getDefaultDate() }
/>
</label>
</div> </div>
); );
} }

View File

@@ -111,18 +111,25 @@ class MultiSelectFilter extends Component {
`filter select-filter form-control ${className} ${this.state.isSelected ? '' : 'placeholder-selected'}`; `filter select-filter form-control ${className} ${this.state.isSelected ? '' : 'placeholder-selected'}`;
return ( return (
<select <label
{ ...rest } className="filter-label"
ref={ n => this.selectInput = n } htmlFor={ `multiselect-filter-column-${column.text}` }
style={ style }
multiple
className={ selectClass }
onChange={ this.filter }
onClick={ e => e.stopPropagation() }
defaultValue={ defaultValue !== undefined ? defaultValue : '' }
> >
{ this.getOptions() } <span className="sr-only">Filter by {column.text}</span>
</select> <select
{ ...rest }
ref={ n => this.selectInput = n }
id={ `multiselect-filter-column-${column.text}` }
style={ style }
multiple
className={ selectClass }
onChange={ this.filter }
onClick={ e => e.stopPropagation() }
defaultValue={ defaultValue !== undefined ? defaultValue : '' }
>
{ this.getOptions() }
</select>
</label>
); );
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

@@ -98,9 +98,9 @@ export const filterByDate = _ => (
customFilterValue customFilterValue
) => { ) => {
if (!date || !comparator) return data; if (!date || !comparator) return data;
const filterDate = date.getDate(); const filterDate = date.getUTCDate();
const filterMonth = date.getMonth(); const filterMonth = date.getUTCMonth();
const filterYear = date.getFullYear(); const filterYear = date.getUTCFullYear();
return data.filter((row) => { return data.filter((row) => {
let valid = true; let valid = true;
@@ -114,9 +114,9 @@ export const filterByDate = _ => (
cell = new Date(cell); cell = new Date(cell);
} }
const targetDate = cell.getDate(); const targetDate = cell.getUTCDate();
const targetMonth = cell.getMonth(); const targetMonth = cell.getUTCMonth();
const targetYear = cell.getFullYear(); const targetYear = cell.getUTCFullYear();
switch (comparator) { 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 { .react-bootstrap-table > table > thead > tr > th .filter {
font-weight: normal; font-weight: normal;
} }

View File

@@ -283,9 +283,9 @@ describe('FilterContext', () => {
expect(onFilter).toHaveBeenCalledWith(filterVal); expect(onFilter).toHaveBeenCalledWith(filterVal);
}); });
it('should set state.data correctly', () => { it('should set data correctly', () => {
instance.onFilter(customColumns[1], FILTER_TYPE.TEXT)(filterVal); 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() { componentDidMount() {
if (loading) { if (loading) {
const { wrapper } = this.overlay; const { wrapper } = this.overlay;
const masker = wrapper.firstChild; const masker = wrapper.current.firstChild;
const headerDOM = wrapper.parentElement.querySelector('thead'); const headerDOM = wrapper.current.parentElement.querySelector('thead');
const bodyDOM = wrapper.parentElement.querySelector('tbody'); const bodyDOM = wrapper.current.parentElement.querySelector('tbody');
const captionDOM = wrapper.parentElement.querySelector('caption'); const captionDOM = wrapper.current.parentElement.querySelector('caption');
let marginTop = window.getComputedStyle(headerDOM).height; let marginTop = window.getComputedStyle(headerDOM).height;
if (captionDOM) { if (captionDOM) {

View File

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

View File

@@ -2,199 +2,351 @@
# yarn lockfile v1 # yarn lockfile v1
asap@~2.0.3: "@babel/helper-module-imports@^7.0.0":
version "2.0.6" version "7.0.0"
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz#96081b7111e486da4d2cd971ad1a4fe216cc2e3d"
integrity sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==
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"
dependencies: dependencies:
base64-js "^1.0.2" "@babel/types" "^7.0.0"
ieee754 "^1.1.4"
chain-function@^1.0.0: "@babel/runtime@^7.1.2", "@babel/runtime@^7.4.2":
version "1.0.0" version "7.4.4"
resolved "https://registry.yarnpkg.com/chain-function/-/chain-function-1.0.0.tgz#0d4ab37e7e18ead0bdc47b920764118ce58733dc" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.4.4.tgz#dc2e34982eb236803aa27a07fea6857af1b9171d"
integrity sha512-w0+uT71b6Yi7i5SE0co4NioIpSYS6lLiXvCzWzGSKvpK5vdQtCbICHMj+gbAKAOtxiV6HsVh/MBdaF9EQ6faSg==
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"
dependencies: dependencies:
css-color-keywords "^1.0.0" regenerator-runtime "^0.13.2"
fbjs "^0.8.5"
postcss-value-parser "^3.3.0"
dom-helpers@^3.2.0: "@babel/types@^7.0.0":
version "3.2.1" version "7.4.4"
resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.2.1.tgz#3203e07fed217bd1f424b019735582fc37b2825a" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.4.4.tgz#8db9e9a629bb7c29370009b4b779ed93fe57d5f0"
integrity sha512-dOllgYdnEFOebhkKCjzSVFqw/PmmB8pH6RGOWkY4GsboQNd47b1fBThBSwlHAq9alF9vc1M3+6oqR47R50L0tQ==
encoding@^0.1.11:
version "0.1.12"
resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb"
dependencies: 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: "@emotion/cache@^10.0.9":
version "0.8.16" version "10.0.9"
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db" resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-10.0.9.tgz#e0c7b7a289f7530edcfad4dcf3858bd2e5700a6f"
integrity sha512-f7MblpE2xoimC4fCMZ9pivmsIn7hyWRIvY75owMDi8pdOSeh+w5tH3r4hBJv/LLrwiMM7cTQURqTPcYoL5pWnw==
dependencies: dependencies:
core-js "^1.0.0" "@emotion/sheet" "0.9.2"
isomorphic-fetch "^2.1.1" "@emotion/stylis" "0.8.3"
loose-envify "^1.0.0" "@emotion/utils" "0.11.1"
object-assign "^4.1.0" "@emotion/weak-memoize" "0.2.2"
promise "^7.1.1"
setimmediate "^1.0.5"
ua-parser-js "^0.7.9"
has-flag@^1.0.0: "@emotion/hash@0.7.1":
version "1.0.0" version "0.7.1"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" 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: "@emotion/memoize@0.7.1":
version "1.2.0" version "0.7.1"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz#aa448cf0986d55cc40773b17174b7dd066cb7cfb" resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.1.tgz#e93c13942592cf5ef01aa8297444dc192beee52f"
integrity sha512-Qv4LTqO11jepd5Qmlp3M1YEjBumoTHcHFdgPTQ+sFlIL5myi/7xu/POwP7IRu6odBdmLXdtIs1D6TuW6kbwbbg==
iconv-lite@~0.4.13: "@emotion/serialize@^0.11.6":
version "0.4.19" version "0.11.6"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-0.11.6.tgz#78be8b9ee9ff49e0196233ba6ec1c1768ba1e1fc"
integrity sha512-n4zVv2qGLmspF99jaEUwnMV0fnEGsyUMsC/8KZKUSUTZMYljHE+j+B6rSD8PIFtaUIhHaxCG2JawN6L+OgLN0Q==
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"
dependencies: 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" 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: import-fresh@^2.0.0:
version "3.0.1" version "2.0.0"
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546"
integrity sha1-2BNVwVYS04bGH53dOSLUMEgipUY=
isomorphic-fetch@^2.1.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"
dependencies: dependencies:
node-fetch "^1.0.1" caller-path "^2.0.0"
whatwg-fetch ">=0.10.0" resolve-from "^3.0.0"
js-tokens@^3.0.0: is-arrayish@^0.2.1:
version "3.0.2" version "0.2.1"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" 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: is-directory@^0.3.1:
version "1.3.1" version "0.3.1"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" 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: dependencies:
js-tokens "^3.0.0" argparse "^1.0.7"
esprima "^4.0.0"
node-fetch@^1.0.1: json-parse-better-errors@^1.0.1:
version "1.7.3" version "1.0.2"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" 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: dependencies:
encoding "^0.1.11" js-tokens "^3.0.0 || ^4.0.0"
is-stream "^1.0.1"
object-assign@^4.1.0, object-assign@^4.1.1: object-assign@^4.1.1:
version "4.1.1" version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
postcss-value-parser@^3.3.0: parse-json@^4.0.0:
version "3.3.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz#87f38f9f18f774a4ab4c8a232f5c5ce8872a9d15" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0"
integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=
promise@^7.1.1:
version "7.3.1"
resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf"
dependencies: 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: path-parse@^1.0.6:
version "15.6.0" version "1.0.6"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.0.tgz#ceaf083022fc46b4a35f69e13ef75aed0d639856" 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: dependencies:
fbjs "^0.8.16" loose-envify "^1.4.0"
loose-envify "^1.3.1"
object-assign "^4.1.1" object-assign "^4.1.1"
react-is "^16.8.1"
react-loading-overlay@0.2.8: react-is@^16.8.1:
version "0.2.8" version "16.8.6"
resolved "https://registry.yarnpkg.com/react-loading-overlay/-/react-loading-overlay-0.2.8.tgz#c1c5531c9cfa4be6caca6b9aa0c1eb19e22b03fe" 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: dependencies:
prop-types "^15.5.10" emotion "^10.0.1"
react-transition-group "^1.2.1" prop-types "^15.6.2"
styled-components "^2.1.2" react-transition-group "^2.5.0"
react-transition-group@^1.2.1: react-transition-group@^2.5.0:
version "1.2.1" version "2.9.0"
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-1.2.1.tgz#e11f72b257f921b213229a774df46612346c7ca6" 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: dependencies:
chain-function "^1.0.0" dom-helpers "^3.4.0"
dom-helpers "^3.2.0" loose-envify "^1.4.0"
loose-envify "^1.3.1" prop-types "^15.6.2"
prop-types "^15.5.6" react-lifecycles-compat "^3.0.4"
warning "^3.0.0"
setimmediate@^1.0.5: regenerator-runtime@^0.13.2:
version "1.0.5" version "0.13.2"
resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" 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: resolve-from@^3.0.0:
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:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/warning/-/warning-3.0.0.tgz#32e5377cb572de4ab04753bdf8821c01ed605b7c" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748"
dependencies: integrity sha1-six699nWiBvItuZTM17rywoYh0g=
loose-envify "^1.0.0"
whatwg-fetch@>=0.10.0: resolve@^1.10.0:
version "2.0.3" version "1.11.0"
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84" 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) * [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) * [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 * Standalone
* Non-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 ```js
import paginationFactory, { PaginationProvider } from 'react-bootstrap-table2-paginator'; import paginationFactory, { PaginationProvider } from 'react-bootstrap-table2-paginator';
``` ```
#### Declare custom and totalSize in pagination option: #### 2. Declare custom and totalSize in pagination option:
```js ```js
const paginationOption = { const paginationOption = {
@@ -94,7 +94,7 @@ const paginationOption = {
}; };
``` ```
#### Render PaginationProvider #### 3. Render PaginationProvider
```js ```js
<PaginationProvider <PaginationProvider
@@ -139,18 +139,24 @@ So far, your customization pagination is supposed to look like it:
</PaginationProvider> </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 #### 4.1 Use Standalone Component
`react-bootstrap-table2-paginator` provider two standalone components: `react-bootstrap-table2-paginator` provider three standalone components:
* Size Per Page Dropdwn Standalone * Size Per Page Dropdwn Standalone
* Pagination List Standalone * Pagination List Standalone
* Pagination Total Standalone
When render each standalone, you just need to pass the `paginationProps` props to standalone component: When render each standalone, you just need to pass the `paginationProps` props to standalone component:
```js ```js
import paginationFactory, { PaginationProvider, PaginationListStandalone, SizePerPageDropdownStandalone } from 'react-bootstrap-table2-paginator'; import paginationFactory, {
PaginationProvider,
PaginationListStandalone,
SizePerPageDropdownStandalone,
PaginationTotalStandalone
} from 'react-bootstrap-table2-paginator';
<PaginationProvider <PaginationProvider
pagination={ paginationFactory(options) } pagination={ paginationFactory(options) }
@@ -164,6 +170,9 @@ import paginationFactory, { PaginationProvider, PaginationListStandalone, SizePe
<SizePerPageDropdownStandalone <SizePerPageDropdownStandalone
{ ...paginationProps } { ...paginationProps }
/> />
<PaginationTotalStandalone
{ ...paginationProps }
/>
<BootstrapTable <BootstrapTable
keyField="id" keyField="id"
data={ products } 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. 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: 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 createDataContext from './src/data-context';
import PaginationListStandalone from './src/pagination-list-standalone'; import PaginationListStandalone from './src/pagination-list-standalone';
import SizePerPageDropdownStandalone from './src/size-per-page-dropdown-standalone'; import SizePerPageDropdownStandalone from './src/size-per-page-dropdown-standalone';
import PaginationTotalStandalone from './src/pagination-total-standalone';
export default (options = {}) => ({ export default (options = {}) => ({
createContext: createDataContext, createContext: createDataContext,
@@ -23,4 +24,4 @@ CustomizableProvider.propTypes = {
}; };
export const PaginationProvider = CustomizableProvider; export const PaginationProvider = CustomizableProvider;
export { PaginationListStandalone, SizePerPageDropdownStandalone }; export { PaginationListStandalone, SizePerPageDropdownStandalone, PaginationTotalStandalone };

View File

@@ -1,6 +1,6 @@
{ {
"name": "react-bootstrap-table2-paginator", "name": "react-bootstrap-table2-paginator",
"version": "2.0.2", "version": "2.0.6",
"description": "it's the pagination addon for react-bootstrap-table2", "description": "it's the pagination addon for react-bootstrap-table2",
"main": "./lib/index.js", "main": "./lib/index.js",
"repository": { "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 // user should align the page when the page is not fit to the data size when remote enable
if (!this.isRemotePagination() && !custom) { if (!this.isRemotePagination() && !custom) {
const newPage = alignPage( 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 (this.currPage !== newPage) {
if (onPageChange) { if (onPageChange) {
@@ -41,6 +46,9 @@ class PaginationDataProvider extends Provider {
this.currPage = newPage; this.currPage = newPage;
} }
} }
if (nextProps.onDataSizeChange && nextProps.data.length !== this.props.data.length) {
nextProps.onDataSizeChange({ dataSize: nextProps.data.length });
}
} }
isRemotePagination = () => this.props.isRemotePagination(); isRemotePagination = () => this.props.isRemotePagination();

View File

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

View File

@@ -1,3 +1,5 @@
import Const from './const';
const getNormalizedPage = ( const getNormalizedPage = (
page, page,
pageStartIndex pageStartIndex
@@ -19,12 +21,20 @@ const startIndex = (
export const alignPage = ( export const alignPage = (
dataSize, dataSize,
prevDataSize,
page, page,
sizePerPage, sizePerPage,
pageStartIndex pageStartIndex
) => { ) => {
if (page < pageStartIndex || page > (Math.floor(dataSize / sizePerPage) + pageStartIndex)) { if (prevDataSize < dataSize) return page;
return pageStartIndex; 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; 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 React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
const PaginationTotal = props => ( const PaginationTotal = (props) => {
<span className="react-bootstrap-table-pagination-total"> if (props.paginationTotalRenderer) {
&nbsp;Showing rows { props.from } to&nbsp;{ props.to } of&nbsp;{ props.dataSize } return props.paginationTotalRenderer(props.from, props.to, props.dataSize);
</span> }
); return (
<span className="react-bootstrap-table-pagination-total">
&nbsp;Showing rows { props.from } to&nbsp;{ props.to } of&nbsp;{ props.dataSize }
</span>
);
};
PaginationTotal.propTypes = { PaginationTotal.propTypes = {
from: PropTypes.number.isRequired, from: PropTypes.number.isRequired,
to: 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; export default PaginationTotal;

View File

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

View File

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

View File

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

View File

@@ -43,18 +43,132 @@ describe('Page Functions', () => {
}); });
describe('alignPage', () => { describe('alignPage', () => {
const pageStartIndex = 1; let newDataSize;
const sizePerPage = 10; let prevDataSize;
const page = 3; let currPage;
describe('if the page does not fit the pages which calculated from the length of data', () => { let pageStartIndex;
it('should return pageStartIndex argument', () => { let sizePerPage;
expect(alignPage(15, page, sizePerPage, pageStartIndex)).toEqual(pageStartIndex);
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', () => { describe('if currPage < newDataSize', () => {
it('should return current page', () => { beforeEach(() => {
expect(alignPage(30, page, sizePerPage, pageStartIndex)).toEqual(page); 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 React from 'react';
import sinon from 'sinon'; import sinon from 'sinon';
import { shallow } from 'enzyme'; import { shallow, render } from 'enzyme';
import SizePerPageDropDown from '../src/size-per-page-dropdown'; import SizePerPageDropDown from '../src/size-per-page-dropdown';
import PaginationList from '../src/pagination-list'; import PaginationList from '../src/pagination-list';
import Pagination from '../src/pagination'; import Pagination from '../src/pagination';
import PaginationTotal from '../src/pagination-total';
describe('Pagination', () => { describe('Pagination', () => {
let wrapper; let wrapper;
@@ -107,28 +106,24 @@ describe('Pagination', () => {
describe('when props.showTotal is true', () => { describe('when props.showTotal is true', () => {
beforeEach(() => { beforeEach(() => {
const props = createMockProps({ showTotal: true }); const props = createMockProps({ showTotal: true });
wrapper = shallow(<Pagination { ...props } />); wrapper = render(<Pagination { ...props } />);
wrapper.render();
instance = wrapper.instance();
}); });
it('should render PaginationTotal correctly', () => { 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', () => { describe('if props.paginationTotalRenderer is defined', () => {
let paginationTotalRenderer; let paginationTotalRenderer;
beforeEach(() => { beforeEach(() => {
paginationTotalRenderer = jest.fn(); paginationTotalRenderer = jest.fn(() => <div />);
const props = createMockProps({ showTotal: true, paginationTotalRenderer }); const props = createMockProps({ showTotal: true, paginationTotalRenderer });
wrapper = shallow(<Pagination { ...props } />); wrapper = render(<Pagination { ...props } />);
wrapper.render();
instance = wrapper.instance();
}); });
it('should not render PaginationTotal', () => { 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', () => { 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). `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 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)** **[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. 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 ### Search Options
#### defaultSearch - [string] #### defaultSearch - [string]
@@ -121,6 +140,8 @@ const { SearchBar, ClearSearchButton } = Search;
</ToolkitProvider> </ToolkitProvider>
``` ```
-----
## Export CSV ## Export CSV
There are two steps to enable the export CSV functionality: 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] #### noAutoBOM - [bool]
Default is `true`. Default is `true`.
#### blobType - [string]
Default is `text/plain;charset=utf-8`. Change to update the blob type of the exported file.
#### exportAll - [bool] #### exportAll - [bool]
Default is `true`. `false` will only export current data which display on table. Default is `true`. `false` will only export current data which display on table.
#### onlyExportSelection - [bool] #### onlyExportSelection - [bool]
Default is `false`. `true` will only export the data which is selected. 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 React from 'react';
import PropTypes from 'prop-types'; 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(); const ToolkitContext = React.createContext();
class ToolkitProvider extends statelessDrcorator(React.Component) { class ToolkitProvider extends statelessDecorator(React.Component) {
static propTypes = { static propTypes = {
keyField: PropTypes.string.isRequired, keyField: PropTypes.string.isRequired,
data: PropTypes.array.isRequired, data: PropTypes.array.isRequired,
@@ -28,7 +29,9 @@ class ToolkitProvider extends statelessDrcorator(React.Component) {
separator: PropTypes.string, separator: PropTypes.string,
ignoreHeader: PropTypes.bool, ignoreHeader: PropTypes.bool,
noAutoBOM: PropTypes.bool, noAutoBOM: PropTypes.bool,
blobType: PropTypes.string,
exportAll: PropTypes.bool, exportAll: PropTypes.bool,
onlyExportFiltered: PropTypes.bool,
onlyExportSelection: PropTypes.bool onlyExportSelection: PropTypes.bool
}) })
]) ])
@@ -42,13 +45,22 @@ class ToolkitProvider extends statelessDrcorator(React.Component) {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { const state = {};
searchText: typeof props.search === 'object' ? (props.search.defaultSearch || '') : ''
};
this._ = null; this._ = null;
this.onClear = this.onClear.bind(this); this.onClear = this.onClear.bind(this);
this.onSearch = this.onSearch.bind(this); this.onSearch = this.onSearch.bind(this);
this.onColumnToggle = this.onColumnToggle.bind(this);
this.setDependencyModules = this.setDependencyModules.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) { onSearch(searchText) {
@@ -61,6 +73,14 @@ class ToolkitProvider extends statelessDrcorator(React.Component) {
this.setState({ searchText: '' }); this.setState({ searchText: '' });
} }
onColumnToggle(dataField) {
const { columnToggle } = this.state;
columnToggle[dataField] = !columnToggle[dataField];
this.setState(({
...this.state,
columnToggle
}));
}
/** /**
* *
* @param {*} _ * @param {*} _
@@ -84,10 +104,15 @@ class ToolkitProvider extends statelessDrcorator(React.Component) {
}; };
if (this.props.search) { if (this.props.search) {
baseProps.search = { baseProps.search = {
searchContext: createContext(this.props.search), searchContext: createSearchContext(this.props.search),
searchText: this.state.searchText searchText: this.state.searchText
}; };
} }
if (this.props.columnToggle) {
baseProps.columnToggle = {
toggles: this.state.columnToggle
};
}
return ( return (
<ToolkitContext.Provider value={ { <ToolkitContext.Provider value={ {
searchProps: { searchProps: {
@@ -98,6 +123,11 @@ class ToolkitProvider extends statelessDrcorator(React.Component) {
csvProps: { csvProps: {
onExport: this.handleExportCSV onExport: this.handleExportCSV
}, },
columnToggleProps: {
columns: this.props.columns,
toggles: this.state.columnToggle,
onColumnToggle: this.onColumnToggle
},
baseProps baseProps
} } } }
> >

View File

@@ -5,3 +5,4 @@ export default ToolkitProvider;
export const ToolkitContext = Context; export const ToolkitContext = Context;
export { default as Search } from './src/search'; export { default as Search } from './src/search';
export { default as CSVExport } from './src/csv'; 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", "name": "react-bootstrap-table2-toolkit",
"version": "1.2.2", "version": "2.0.1",
"description": "The toolkit for react-bootstrap-table2", "description": "The toolkit for react-bootstrap-table2",
"main": "./lib/index.js", "main": "./lib/index.js",
"repository": { "repository": {
@@ -45,6 +45,6 @@
"react-dom": "^16.3.0" "react-dom": "^16.3.0"
}, },
"dependencies": { "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 { const {
onExport, onExport,
children, children,
className,
...rest ...rest
} = props; } = props;
return ( return (
<button <button
type="button" type="button"
className={ `react-bs-table-csv-btn btn btn-default ${className}` }
onClick={ () => onExport() } onClick={ () => onExport() }
{ ...rest } { ...rest }
> >
@@ -26,7 +28,7 @@ ExportCSVButton.propTypes = {
style: PropTypes.object style: PropTypes.object
}; };
ExportCSVButton.defaultProps = { ExportCSVButton.defaultProps = {
className: 'react-bs-table-csv-btn btn btn-default', className: '',
style: {} style: {}
}; };

View File

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

View File

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

View File

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

View File

@@ -3,18 +3,21 @@ import PropTypes from 'prop-types';
const ClearButton = ({ const ClearButton = ({
onClear, 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 = { ClearButton.propTypes = {
onClear: PropTypes.func.isRequired, onClear: PropTypes.func.isRequired,
className: PropTypes.string,
text: PropTypes.string text: PropTypes.string
}; };
ClearButton.defaultProps = { ClearButton.defaultProps = {
text: 'Clear' text: 'Clear',
className: ''
}; };
export default ClearButton; export default ClearButton;

View File

@@ -59,6 +59,10 @@ export default (options = {
} }
} }
getSearched() {
return this.state.data;
}
triggerListener(result) { triggerListener(result) {
if (this.props.dataChangeListener) { if (this.props.dataChangeListener) {
this.props.dataChangeListener.emit('filterChanged', result.length); 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 # yarn lockfile v1
file-saver@1.3.8: file-saver@2.0.2:
version "1.3.8" version "2.0.2"
resolved "https://registry.yarnpkg.com/file-saver/-/file-saver-1.3.8.tgz#e68a30c7cb044e2fb362b428469feb291c2e09d8" 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", "name": "react-bootstrap-table-next",
"version": "2.1.2", "version": "3.1.4",
"description": "Next generation of react-bootstrap-table", "description": "Next generation of react-bootstrap-table",
"main": "./lib/index.js", "main": "./lib/index.js",
"repository": { "repository": {
@@ -37,6 +37,7 @@
], ],
"dependencies": { "dependencies": {
"classnames": "2.2.5", "classnames": "2.2.5",
"react-transition-group": "2.5.3",
"underscore": "1.9.1" "underscore": "1.9.1"
}, },
"peerDependencies": { "peerDependencies": {

View File

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

View File

@@ -18,6 +18,14 @@ class BootstrapTable extends PropsBaseResolver(Component) {
this.validateProps(); 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 // Exposed APIs
getData = () => { getData = () => {
return this.visibleRows(); return this.visibleRows();
@@ -159,7 +167,13 @@ BootstrapTable.propTypes = {
bgColor: PropTypes.oneOfType([PropTypes.string, PropTypes.func]), bgColor: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
hideSelectColumn: PropTypes.bool, hideSelectColumn: PropTypes.bool,
selectionRenderer: PropTypes.func, 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({ expandRow: PropTypes.shape({
renderer: PropTypes.func, renderer: PropTypes.func,
@@ -192,6 +206,7 @@ BootstrapTable.propTypes = {
onSort: PropTypes.func, onSort: PropTypes.func,
onFilter: PropTypes.func, onFilter: PropTypes.func,
onExternalFilter: PropTypes.func, onExternalFilter: PropTypes.func,
onDataSizeChange: PropTypes.func,
// Inject from toolkit // Inject from toolkit
search: PropTypes.shape({ search: PropTypes.shape({
searchText: PropTypes.string, searchText: PropTypes.string,

View File

@@ -8,7 +8,7 @@ import _ from './utils';
class Cell extends eventDelegater(Component) { class Cell extends eventDelegater(Component) {
constructor(props) { constructor(props) {
super(props); super(props);
this.handleEditingCell = this.handleEditingCell.bind(this); this.createHandleEditingCell = this.createHandleEditingCell.bind(this);
} }
shouldComponentUpdate(nextProps) { shouldComponentUpdate(nextProps) {
@@ -23,7 +23,10 @@ class Cell extends eventDelegater(Component) {
if (shouldUpdate) return true; if (shouldUpdate) return true;
// if (nextProps.formatter)
shouldUpdate = shouldUpdate =
(nextProps.column.formatter ? !_.isEqual(this.props.row, nextProps.row) : false) ||
this.props.column.hidden !== nextProps.column.hidden || this.props.column.hidden !== nextProps.column.hidden ||
this.props.rowIndex !== nextProps.rowIndex || this.props.rowIndex !== nextProps.rowIndex ||
this.props.columnIndex !== nextProps.columnIndex || this.props.columnIndex !== nextProps.columnIndex ||
@@ -40,17 +43,10 @@ class Cell extends eventDelegater(Component) {
return shouldUpdate; return shouldUpdate;
} }
handleEditingCell(e) { createHandleEditingCell = originFunc => (e) => {
const { column, onStart, rowIndex, columnIndex, clickToEdit, dbclickToEdit } = this.props; const { onStart, rowIndex, columnIndex, clickToEdit, dbclickToEdit } = this.props;
const { events } = column; if ((clickToEdit || dbclickToEdit) && _.isFunction(originFunc)) {
if (events) { originFunc(e);
if (clickToEdit) {
const customClick = events.onClick;
if (_.isFunction(customClick)) customClick(e);
} else if (dbclickToEdit) {
const customDbClick = events.onDoubleClick;
if (_.isFunction(customDbClick)) customDbClick(e);
}
} }
if (onStart) { if (onStart) {
onStart(rowIndex, columnIndex); onStart(rowIndex, columnIndex);
@@ -82,9 +78,9 @@ class Cell extends eventDelegater(Component) {
} }
if (clickToEdit && editable) { if (clickToEdit && editable) {
attrs.onClick = this.handleEditingCell; attrs.onClick = this.createHandleEditingCell(attrs.onClick);
} else if (dbclickToEdit && editable) { } else if (dbclickToEdit && editable) {
attrs.onDoubleClick = this.handleEditingCell; attrs.onDoubleClick = this.createHandleEditingCell(attrs.onDoubleClick);
} }
return ( 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 EventEmitter from 'events';
import _ from '../utils'; import _ from '../utils';
import createDataContext from './data-context'; import createDataContext from './data-context';
import createColumnMgtContext from './column-context';
import createSortContext from './sort-context'; import createSortContext from './sort-context';
import SelectionContext from './selection-context'; import SelectionContext from './selection-context';
import RowExpandContext from './row-expand-context'; import RowExpandContext from './row-expand-context';
@@ -22,6 +23,15 @@ const withContext = Base =>
const exposedAPIEmitter = new EventEmitter(); const exposedAPIEmitter = new EventEmitter();
exposedAPIEmitter.on('get.table.data', payload => payload.result = this.table.getData()); 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.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); props.registerExposedAPI(exposedAPIEmitter);
} }
@@ -30,6 +40,13 @@ const withContext = Base =>
dataOperator, this.isRemoteSort, this.handleRemoteSortChange); dataOperator, this.isRemoteSort, this.handleRemoteSortChange);
} }
if (
props.columnToggle ||
props.columns.filter(col => col.hidden).length > 0
) {
this.ColumnManagementContext = createColumnMgtContext();
}
if (props.selectRow) { if (props.selectRow) {
this.SelectionContext = SelectionContext; this.SelectionContext = SelectionContext;
} }
@@ -83,6 +100,7 @@ const withContext = Base =>
searchProps, searchProps,
sortProps, sortProps,
paginationProps, paginationProps,
columnToggleProps
) => ( ) => (
<Base <Base
ref={ n => this.table = n } ref={ n => this.table = n }
@@ -91,11 +109,40 @@ const withContext = Base =>
{ ...filterProps } { ...filterProps }
{ ...searchProps } { ...searchProps }
{ ...paginationProps } { ...paginationProps }
{ ...columnToggleProps }
data={ rootProps.getData(filterProps, searchProps, sortProps, paginationProps) } 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) { renderWithSelectionCtx(base, baseProps) {
return ( return (
rootProps, rootProps,
@@ -164,6 +211,7 @@ const withContext = Base =>
bootstrap4={ this.props.bootstrap4 } bootstrap4={ this.props.bootstrap4 }
isRemotePagination={ this.isRemotePagination } isRemotePagination={ this.isRemotePagination }
remoteEmitter={ this.remoteEmitter } remoteEmitter={ this.remoteEmitter }
onDataSizeChange={ this.props.onDataSizeChange }
> >
<this.PaginationContext.Consumer> <this.PaginationContext.Consumer>
{ {
@@ -256,6 +304,7 @@ const withContext = Base =>
return rootProps => ( return rootProps => (
<this.CellEditContext.Provider <this.CellEditContext.Provider
{ ...baseProps } { ...baseProps }
ref={ n => this.cellEditContext = n }
selectRow={ this.props.selectRow } selectRow={ this.props.selectRow }
cellEdit={ this.props.cellEdit } cellEdit={ this.props.cellEdit }
data={ rootProps.getData() } data={ rootProps.getData() }
@@ -271,6 +320,10 @@ const withContext = Base =>
let base = this.renderBase(); let base = this.renderBase();
if (this.ColumnManagementContext) {
base = this.renderWithColumnManagementCtx(base, baseProps);
}
if (this.SelectionContext) { if (this.SelectionContext) {
base = this.renderWithSelectionCtx(base, baseProps); base = this.renderWithSelectionCtx(base, baseProps);
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,18 +1,37 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { CSSTransition } from 'react-transition-group';
const ExpandRow = ({ children, ...rest }) => ( const ExpandRow = ({ children, expanded, onClosed, ...rest }) => (
<tr className="expanding-row"> <tr>
<td { ...rest }>{ children }</td> <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> </tr>
); );
ExpandRow.propTypes = { ExpandRow.propTypes = {
children: PropTypes.node children: PropTypes.node,
expanded: PropTypes.bool,
onClosed: PropTypes.func
}; };
ExpandRow.defaultProps = { ExpandRow.defaultProps = {
children: null children: null,
expanded: false,
onClosed: null
}; };
export default ExpandRow; export default ExpandRow;

View File

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

View File

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

View File

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

View File

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

View File

@@ -33,92 +33,89 @@ export default class RowPureContent extends React.Component {
let tabIndex = tabIndexStart; let tabIndex = tabIndexStart;
return columns.map((column, index) => { return columns.map((column, index) => {
if (!column.hidden) { const { dataField } = column;
const { dataField } = column; const content = _.get(row, dataField);
const content = _.get(row, dataField); if (rowIndex === editingRowIdx && index === editingColIdx) {
if (rowIndex === editingRowIdx && index === editingColIdx) {
return (
<EditingCellComponent
key={ `${content}-${index}-editing` }
row={ row }
rowIndex={ rowIndex }
column={ column }
columnIndex={ index }
/>
);
}
// render cell
let cellTitle;
let cellStyle = {};
let cellAttrs = {
..._.isFunction(column.attrs)
? column.attrs(content, row, rowIndex, index)
: column.attrs
};
if (column.events) {
const events = Object.assign({}, column.events);
Object.keys(Object.assign({}, column.events)).forEach((key) => {
const originFn = events[key];
events[key] = (...rest) => originFn(...rest, row, rowIndex);
});
cellAttrs = { ...cellAttrs, ...events };
}
const cellClasses = _.isFunction(column.classes)
? column.classes(content, row, rowIndex, index)
: column.classes;
if (column.style) {
cellStyle = _.isFunction(column.style)
? column.style(content, row, rowIndex, index)
: column.style;
cellStyle = Object.assign({}, cellStyle) || {};
}
if (column.title) {
cellTitle = _.isFunction(column.title)
? column.title(content, row, rowIndex, index)
: content;
cellAttrs.title = cellTitle;
}
if (column.align) {
cellStyle.textAlign =
_.isFunction(column.align)
? column.align(content, row, rowIndex, index)
: column.align;
}
if (cellClasses) cellAttrs.className = cellClasses;
if (!_.isEmptyObject(cellStyle)) cellAttrs.style = cellStyle;
let editableCell = _.isDefined(column.editable) ? column.editable : true;
if (column.dataField === keyField || !editable) editableCell = false;
if (_.isFunction(column.editable)) {
editableCell = column.editable(content, row, rowIndex, index);
}
if (tabIndexStart !== -1) {
cellAttrs.tabIndex = tabIndex++;
}
return ( return (
<Cell <EditingCellComponent
key={ `${content}-${index}` } key={ `${content}-${index}-editing` }
row={ row } row={ row }
editable={ editableCell }
rowIndex={ rowIndex } rowIndex={ rowIndex }
columnIndex={ index }
column={ column } column={ column }
onStart={ onStart } columnIndex={ index }
clickToEdit={ clickToEdit }
dbclickToEdit={ dbclickToEdit }
{ ...cellAttrs }
/> />
); );
} }
return false; // render cell
let cellTitle;
let cellStyle = {};
let cellAttrs = {
..._.isFunction(column.attrs)
? column.attrs(content, row, rowIndex, index)
: column.attrs
};
if (column.events) {
const events = Object.assign({}, column.events);
Object.keys(Object.assign({}, column.events)).forEach((key) => {
const originFn = events[key];
events[key] = (...rest) => originFn(...rest, row, rowIndex);
});
cellAttrs = { ...cellAttrs, ...events };
}
const cellClasses = _.isFunction(column.classes)
? column.classes(content, row, rowIndex, index)
: column.classes;
if (column.style) {
cellStyle = _.isFunction(column.style)
? column.style(content, row, rowIndex, index)
: column.style;
cellStyle = Object.assign({}, cellStyle) || {};
}
if (column.title) {
cellTitle = _.isFunction(column.title)
? column.title(content, row, rowIndex, index)
: content;
cellAttrs.title = cellTitle;
}
if (column.align) {
cellStyle.textAlign =
_.isFunction(column.align)
? column.align(content, row, rowIndex, index)
: column.align;
}
if (cellClasses) cellAttrs.className = cellClasses;
if (!_.isEmptyObject(cellStyle)) cellAttrs.style = cellStyle;
let editableCell = _.isDefined(column.editable) ? column.editable : true;
if (column.dataField === keyField || !editable) editableCell = false;
if (_.isFunction(column.editable)) {
editableCell = column.editable(content, row, rowIndex, index);
}
if (tabIndexStart !== -1) {
cellAttrs.tabIndex = tabIndex++;
}
return (
<Cell
key={ `${content}-${index}` }
row={ row }
editable={ editableCell }
rowIndex={ rowIndex }
columnIndex={ index }
column={ column }
onStart={ onStart }
clickToEdit={ clickToEdit }
dbclickToEdit={ dbclickToEdit }
{ ...cellAttrs }
/>
);
}); });
} }
} }

View File

@@ -8,7 +8,8 @@ export default ExtendBase =>
return ( return (
nextProps.editingRowIdx === nextProps.rowIndex || nextProps.editingRowIdx === nextProps.rowIndex ||
(this.props.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; return true;
} }
for (let i = 0; i < this.props.columns.length; i += 1) { 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; 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)); export const getRowByRowId = (data, keyField, id) => data.find(matchRow(keyField, id));

View File

@@ -68,10 +68,6 @@
text-align: center; text-align: center;
} }
tr.expanding-row {
padding: 5px;
}
td.react-bootstrap-table-editing-cell { td.react-bootstrap-table-editing-cell {
.animated { .animated {
animation-fill-mode: both; animation-fill-mode: both;
@@ -161,4 +157,26 @@
animation-name: bounceOut; 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() onClick: sinon.stub()
}; };
}); });
it('should calling custom onClick callback also', () => {
it('should call onStart correctly', () => {
wrapper.find('td').simulate('click'); wrapper.find('td').simulate('click');
expect(onStartCallBack.callCount).toBe(1); expect(onStartCallBack.callCount).toBe(1);
expect(column.events.onClick.callCount).toBe(1);
}); });
}); });
}); });
@@ -164,10 +164,10 @@ describe('Cell', () => {
onDoubleClick: sinon.stub() onDoubleClick: sinon.stub()
}; };
}); });
it('should calling custom onDoubleClick callback also', () => {
it('should call onStart correctly', () => {
wrapper.find('td').simulate('doubleclick'); wrapper.find('td').simulate('doubleclick');
expect(onStartCallBack.callCount).toBe(1); 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('if column.isDummyField is true', () => {
describe('when content is change', () => { describe('when content is change', () => {
const column = { dataField: '', text: 'Product Name', isDummyField: true }; 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