Compare commits

..

50 Commits

Author SHA1 Message Date
AllenFang
096799c403 Publish
- react-bootstrap-table2-example@0.1.2
 - react-bootstrap-table2-filter@0.1.3
 - react-bootstrap-table-next@0.1.3
2018-02-14 16:33:51 +08:00
Allen
6dee718081 2018/02/14 release
2018/02/14 release
2018-02-14 16:30:02 +08:00
Allen
936a82954c fix #196
Support sort event listener
2018-02-10 21:17:00 +08:00
AllenFang
ba24990994 add story for sort event listener 2018-02-10 17:46:38 +08:00
AllenFang
e7ccd47817 implement sort events listener 2018-02-10 17:46:38 +08:00
AllenFang
a0af964d76 fix #195 2018-02-10 17:00:29 +08:00
Allen
865be93ef7 refine caseSensitive for filter (#201) 2018-02-10 16:54:01 +08:00
makenova
65a596a0e9 case insensitive text filter (#190)
* case insensitive text filter

* optional case insensitive filter
2018-02-10 16:17:45 +08:00
Allen
024bba15fa fix #192
Implement number filter
2018-02-10 16:15:37 +08:00
AllenFang
f9217930e7 patch docs for number filter 2018-02-10 16:04:46 +08:00
AllenFang
fc34ea12e6 patch test for number filter 2018-02-10 16:04:46 +08:00
AllenFang
b0f411e934 add number filter stories 2018-02-10 16:04:46 +08:00
AllenFang
28a1077bad implement number filter 2018-02-10 15:43:22 +08:00
AllenFang
ca32eee28e patch rowEvents docs 2018-02-04 21:41:52 +08:00
Allen
7030b54cbd Fix #179
Solves #179
2018-02-04 21:37:10 +08:00
Allen
4d7378e3f1 create LICENSE 2018-02-01 23:41:30 +08:00
AllenFang
88234fead0 Publish
- react-bootstrap-table2-editor@0.1.1
 - react-bootstrap-table2-example@0.1.1
 - react-bootstrap-table2-filter@0.1.2
 - react-bootstrap-table2-overlay@0.1.1
 - react-bootstrap-table2-paginator@0.1.1
 - react-bootstrap-table-next@0.1.2
2018-02-01 23:17:40 +08:00
Allen
dea780519f Merge pull request #188 from react-bootstrap-table/develop
2018/02/02 release
2018-02-01 23:07:20 +08:00
Parth Prajapati
577973a147 Updated storybook example 2018-02-01 06:27:49 +05:30
Parth Prajapati
c4f14e2b69 Added row object to onClick
- attach onClick only if defined
2018-02-01 06:20:50 +05:30
AllenFang
38bb2290dc README 2018-01-31 23:50:02 +08:00
Parth Prajapati
feedcb9f4b Solves #179 2018-01-31 07:43:05 +05:30
AllenFang
8bfbc14bd9 fix #185 2018-01-31 00:01:04 +08:00
Allen
ee4eb8f2c6 Merge pull request #183 from react-bootstrap-table/feat/select-filter
Select filter
2018-01-30 23:53:50 +08:00
AllenFang
8fa6389c81 patch docs 2018-01-30 23:39:18 +08:00
AllenFang
9a354444d0 fix bug for wrap not existing method 2018-01-30 23:25:58 +08:00
AllenFang
2533a63430 patch test for select component 2018-01-30 23:20:47 +08:00
AllenFang
81e0080aa6 add styles for filter modules 2018-01-30 23:20:47 +08:00
AllenFang
094a0682f1 add select filter stories 2018-01-30 23:20:47 +08:00
AllenFang
3f2c6201d9 implement select filter 2018-01-30 23:20:47 +08:00
AllenFang
280c423298 fix #180 2018-01-28 22:09:00 +08:00
AllenFang
fc813e80b6 fix #172 2018-01-28 21:57:30 +08:00
AllenFang
4bb2ae2ba0 fix typo 2018-01-28 21:53:33 +08:00
AllenFang
09fadeb02b CONTRIBUTING.md 2018-01-22 23:09:07 +08:00
AllenFang
283179ebe1 Merge branch 'master' of https://github.com/react-bootstrap-table/react-bootstrap-table2 2018-01-22 00:31:21 +08:00
AllenFang
e83dd1bf07 v0.1.1 2018-01-22 00:30:26 +08:00
Chun-MingChen
760011ac03 update README and migration.md 2018-01-22 00:24:32 +08:00
AllenFang
067a94bea7 v0.1.0 2018-01-22 00:17:24 +08:00
AllenFang
d8ecc6277b README 2018-01-22 00:11:01 +08:00
AllenFang
216befae4b typo 2018-01-22 00:10:30 +08:00
Allen
3c9cd22d42 merge 0.1.0 code base
Develop -> Master (Not Version Bump)
2018-01-22 00:04:09 +08:00
AllenFang
d84b614599 tweak README.md 2018-01-21 23:31:42 +08:00
AllenFang
85f1eba7cb tweak stories 2018-01-21 17:12:07 +08:00
AllenFang
045ca4adb0 fix bug when remote pagination have same filter conds but change pages will cause data doesnt reflect 2018-01-21 17:12:07 +08:00
AllenFang
2263282629 tweak storybook webpack 2018-01-21 16:10:55 +08:00
AllenFang
a2d082babf due to container will always set source data via store.setAllData so that handle the filtered data in the filter wrapper 2018-01-21 15:44:11 +08:00
AllenFang
79d5a51a39 tweak package.json 2018-01-21 14:31:01 +08:00
AllenFang
51e0cc9129 README.md 2018-01-21 14:31:01 +08:00
AllenFang
659f2e2636 upgrade lerna 2018-01-21 14:10:57 +08:00
ChunMing, Chen
badce54b95 Set theme jekyll-theme-cayman 2017-08-19 23:01:09 +08:00
114 changed files with 2769 additions and 148 deletions

View File

@@ -12,6 +12,7 @@ Additionally, asking questions and requesting new features are welcomed via [iss
# Pull Requests # Pull Requests
Check [here](./docs/development.md) for getting started with development. Check [here](./docs/development.md) for getting started with development.
* PR base is `develop` branch
* We recommend filing an [issue](https://github.com/react-bootstrap-table/react-bootstrap-table2/issues) before you implement any new features. * We recommend filing an [issue](https://github.com/react-bootstrap-table/react-bootstrap-table2/issues) before you implement any new features.
* Please ensure that all the test suites have passed before submitting a PR. Besides, always test the actual business logic. * Please ensure that all the test suites have passed before submitting a PR. Besides, always test the actual business logic.
* If your PR is trying to fix a bug, please describe the details as much as you could and tag the bug number with hashtag. * If your PR is trying to fix a bug, please describe the details as much as you could and tag the bug number with hashtag.

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 react-bootstrap-table2
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,12 +1,41 @@
# react-bootstrap-table2 # react-bootstrap-table2
Rebuilt [react-bootstrap-table](https://github.com/AllenFang/react-bootstrap-table) Rebuilt [react-bootstrap-table](https://github.com/AllenFang/react-bootstrap-table)
## Development > `react-bootstrap-table2`'s npm module name is [**`react-bootstrap-table-next`**](https://www.npmjs.com/package/react-bootstrap-table-next) due to some guys already used it
Please check [development guide](./docs/development.md).
`react-bootstrap-table2` separate some functionalities from core modules to other modules like following:
* [`react-bootstrap-table-next`](https://www.npmjs.com/package/react-bootstrap-table-next)
* [`react-bootstrap-table2-filter`](https://www.npmjs.com/package/react-bootstrap-table2-filter)
* [`react-bootstrap-table2-editor`](https://www.npmjs.com/package/react-bootstrap-table2-editor)
* [`react-bootstrap-table2-paginator`](https://www.npmjs.com/package/react-bootstrap-table2-paginator)
* [`react-bootstrap-table2-overlay`](https://www.npmjs.com/package/react-bootstrap-table2-overlay)
This can help your application with less bundled size and also help us have clean design to avoid handling to much logic in kernal module(SRP).
## Migration
If you are the user from legacy [`react-bootstrap-table`](https://github.com/AllenFang/react-bootstrap-table/), please have a look on [this](./docs/migration.md).
## Usage ## Usage
See [getting started](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/getting-started.html). See [getting started](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/getting-started.html).
## Online Demo
See `react-bootstrap-table2` [storybook](https://react-bootstrap-table.github.io/react-bootstrap-table2/storybook/index.html).
## Roadmap ## Roadmap
See [release plans](https://react-bootstrap-table.github.io/react-bootstrap-table2/blog/2018/01/24/release-plan.html). See [release plans](https://react-bootstrap-table.github.io/react-bootstrap-table2/blog/2018/01/24/release-plan.html).
## Development
Please check [development guide](./docs/development.md).
## How should I run storybook example in my local?
```sh
$ git clone https://github.com/react-bootstrap-table/react-bootstrap-table2.git
$ cd react-bootstrap-table2
$ yarn install
$ yarn storybook
$ Go to localhost:6006
```
**Storybook examples: [`packages/react-bootstrap-table2-example/examples`](https://github.com/react-bootstrap-table/react-bootstrap-table2/tree/master/packages/react-bootstrap-table2-example/examples)**

1
_config.yml Normal file
View File

@@ -0,0 +1 @@
theme: jekyll-theme-cayman

View File

@@ -145,7 +145,7 @@ Custom the events on row:
```js ```js
const rowEvents = { const rowEvents = {
onClick: (e) => { onClick: (e, row, rowIndex) => {
.... ....
} }
}; };

View File

@@ -12,6 +12,7 @@ Available properties in a column object:
* [formatExtraData](#formatExtraData) * [formatExtraData](#formatExtraData)
* [sort](#sort) * [sort](#sort)
* [sortFunc](#sortFunc) * [sortFunc](#sortFunc)
* [onSort](#onSort)
* [classes](#classes) * [classes](#classes)
* [style](#style) * [style](#style)
* [title](#title) * [title](#title)
@@ -122,6 +123,19 @@ Enable the column sort via a `true` value given.
``` ```
> The possible value of `order` argument is **`asc`** and **`desc`**. > The possible value of `order` argument is **`asc`** and **`desc`**.
## <a name='sortFunc'>column.onSort - [Function]</a>
`column.onSort` is an event listener for sort change event:
```js
{
// omit...
sort: true,
onSort: (field, order) => {
// ....
}
}
```
## <a name='classes'>column.classes - [String | Function]</a> ## <a name='classes'>column.classes - [String | Function]</a>
It's availabe to have custom class on table column: It's availabe to have custom class on table column:
@@ -542,6 +556,7 @@ Or take a callback function
Configure `column.filter` will able to setup a column level filter on the header column. Currently, `react-bootstrap-table2` support following filters: Configure `column.filter` will able to setup a column level filter on the header column. Currently, `react-bootstrap-table2` support following filters:
* Text(`textFilter`) * Text(`textFilter`)
* Select(`selectFilter`)
We have a quick example to show you how to use `column.filter`: We have a quick example to show you how to use `column.filter`:

118
docs/migration.md Normal file
View File

@@ -0,0 +1,118 @@
# Migration Guide
* Please see the [CHANGELOG](https://react-bootstrap-table.github.io/react-bootstrap-table2/blog/2018/01/24/new-version-0.1.0.html) for `react-bootstrap-table2` first drop.
* Please see the [Roadmap](https://react-bootstrap-table.github.io/react-bootstrap-table2/blog/2018/01/24/release-plan.html) for `react-bootstrap-table2` in 2018/Q1.
* Feel free to see the [offical docs](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/about.html), we list all the basic usage here!!
## Preface
Currently, **I still can't implement all the mainly features in legacy `react-bootstrap-table`**, so please watch our github repo or [blog](https://react-bootstrap-table.github.io/react-bootstrap-table2/blog/) to make sure the legacy features you wanted are already implemented on `react-bootstrap-table2`. Anyway, ask me by open issue is ok.
-----
`react-bootstrap-table2` separate some functionalities from core modules to other modules like following:
* [`react-bootstrap-table-next`](https://www.npmjs.com/package/react-bootstrap-table-next)
* Core table module, include sorting and row selection
* [`react-bootstrap-table2-filter`](https://www.npmjs.com/package/react-bootstrap-table2-filter)
* Column filter Addons
* [`react-bootstrap-table2-editor`](https://www.npmjs.com/package/react-bootstrap-table2-editor)
* Cell Editing Addons
* [`react-bootstrap-table2-paginator`](https://www.npmjs.com/package/react-bootstrap-table2-paginator)
* Pagination Addons
* [`react-bootstrap-table2-overlay`](https://www.npmjs.com/package/react-bootstrap-table2-overlay)
* Overlay/Loading Addons
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 kernal module(SRP). Hence, which means you probably need to install above addons when you need specific features.
## Core Table Migration
There is a big chagne is that there's no `TableHeaderColumn` in the `react-bootstrap-table2`, instead you are supposed to be define the `columns` prop on `BootstrapTable`:
```js
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } />
```
The `text` property is just same as the children for the `TableHeaderColumn`, if you want to custom the header, there's a new property is: [`headerFormatter`](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columnheaderformatter-function).
* [`BootstrapTable` Definitation](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/table-props.html)
* [Column Definitation](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html)
## Table Sort
Please see [Work with table sort](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/basic-sort.html).
- [x] Basic sorting
- [x] Custom sort function
- [x] Default Sort
- [x] Remote mode
- [x] Custom the sorting header
- [x] Sort event listener
- [ ] Custom the sort caret
- [ ] Sort management
- [ ] Multi sort
Due to no `TableHeaderColumn` so that no `dataSort` here, please add [`sort`](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columnsort-bool) property on column definitation.
## Row Selection
Please see [Work with selection](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/basic-row-select.html).
Please see [available selectRow configurations](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/row-select-props.html).
No huge change for row selection, but can not custom the selection column currently. Coming soon!!!
## Column Filter
Please see [Work with column filter](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/basic-filter.html).
Please see [available filter configuration](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/filter-props.html).
- [x] Text Filter
- [x] Custom Text Filter
- [x] Remote Filter
- [ ] Custom Filter Component
- [ ] Regex Filter
- [x] Select Filter
- [x] Custom Select Filter
- [X] Number Filter
- [ ] Date Filter
- [ ] Array Filter
- [ ] Programmatically Filter
Remember to install [`react-bootstrap-table2-filter`](https://www.npmjs.com/package/react-bootstrap-table2-filter) firstly.
Due to no `TableHeaderColumn` so that no `filter` here, please add [`filter`](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columnfilter-object) property on column definitation and [`filter`](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/table-props.html#filter-object) prop on `BootstrapTable`.
## Cell Edit
Please see [Work with cell edit](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/basic-celledit.html).
Please see [available cell edit configurations](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/cell-edit-props.html).
Remember to install [`react-bootstrap-table2-editor`](https://www.npmjs.com/package/react-bootstrap-table2-editor) firstly.
No big changes for cell editing, [`validator`](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columnvalidator-function) will not support the async call(Promise).
## Pagination
Please see [Work with pagination](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/basic-pagination.html).
Please see [available pagination configurations](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/pagination-props.html).
Remember to install [`react-bootstrap-table2-paginator`](https://www.npmjs.com/package/react-bootstrap-table2-paginator) firstly.
No big changes for pagination, but still can't custom the pagination list, button and sizePerPage dropdown.
## Remote
> It's totally different in `react-bootstrap-table2`. Please [see](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/basic-remote.html).

View File

@@ -24,6 +24,7 @@ const JS_SKIPS = `+(${TEST}|${LIB}|${DIST}|${NODE_MODULES})`;
const STYLE_PKGS = [ const STYLE_PKGS = [
'react-bootstrap-table2', 'react-bootstrap-table2',
'react-bootstrap-table2-filter',
'react-bootstrap-table2-paginator' 'react-bootstrap-table2-paginator'
].reduce((pkg, curr) => `${curr}|${pkg}`, ''); ].reduce((pkg, curr) => `${curr}|${pkg}`, '');

View File

@@ -1,6 +1,7 @@
{ {
"name": "react-bootstrap-table2", "name": "react-bootstrap-table2",
"version": "0.0.1", "version": "0.0.1",
"private": true,
"description": "Rebuilt for react-bootstrap-table", "description": "Rebuilt for react-bootstrap-table",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
@@ -20,11 +21,18 @@
"url": "git+https://github.com/react-bootstrap-table/react-bootstrap-table2.git" "url": "git+https://github.com/react-bootstrap-table/react-bootstrap-table2.git"
}, },
"author": "AllenFang", "author": "AllenFang",
"contributors": [{ "contributors": [
"name": "Chun-MingChen", {
"email": "nick830314@gmail.com", "name": "Allen Fang",
"url": "https://github.com/Chun-MingChen" "email": "ayu780129@hotmail.com",
}], "url": "https://github.com/AllenFang"
},
{
"name": "Chun-MingChen",
"email": "nick830314@gmail.com",
"url": "https://github.com/Chun-MingChen"
}
],
"license": "MIT", "license": "MIT",
"bugs": { "bugs": {
"url": "https://github.com/react-bootstrap-table/react-bootstrap-table2/issues" "url": "https://github.com/react-bootstrap-table/react-bootstrap-table2/issues"
@@ -60,7 +68,7 @@
"jest": "20.0.4", "jest": "20.0.4",
"jsdom": "11.2.0", "jsdom": "11.2.0",
"jsdom-global": "3.0.2", "jsdom-global": "3.0.2",
"lerna": "2.0.0", "lerna": "2.8.0",
"node-sass": "4.5.3", "node-sass": "4.5.3",
"react-test-renderer": "16.0.0", "react-test-renderer": "16.0.0",
"sass-loader": "6.0.6", "sass-loader": "6.0.6",

View File

@@ -4,6 +4,8 @@
**[Live Demo For Cell Edit](https://react-bootstrap-table.github.io/react-bootstrap-table2/storybook/index.html?selectedKind=Cell%20Editing)** **[Live Demo For Cell Edit](https://react-bootstrap-table.github.io/react-bootstrap-table2/storybook/index.html?selectedKind=Cell%20Editing)**
**[API&Props Definitation](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/cell-edit-props.html)**
----- -----
## Install ## Install

View File

@@ -1,6 +1,6 @@
{ {
"name": "react-bootstrap-table2-editor", "name": "react-bootstrap-table2-editor",
"version": "0.0.3", "version": "0.1.1",
"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": {
@@ -28,6 +28,11 @@
], ],
"author": "AllenFang", "author": "AllenFang",
"contributors": [ "contributors": [
{
"name": "Allen Fang",
"email": "ayu780129@hotmail.com",
"url": "https://github.com/AllenFang"
},
{ {
"name": "Chun-MingChen", "name": "Chun-MingChen",
"email": "nick830314@gmail.com", "email": "nick830314@gmail.com",

View File

@@ -1,3 +1,4 @@
{ {
"presets": ["react", "es2015", "stage-0", ["env", {"modules": false} ]] "presets": ["react", "es2015", "stage-0", ["env", {"modules": false} ]],
"plugins": ["transform-class-properties"]
} }

View File

@@ -1,12 +1,13 @@
const path = require('path'); const path = require('path');
const sourcePath = path.join(__dirname, '../../react-bootstrap-table2'); const sourcePath = path.join(__dirname, '../../react-bootstrap-table2/index.js');
const paginationSourcePath = path.join(__dirname, '../../react-bootstrap-table2-paginator'); const paginationSourcePath = path.join(__dirname, '../../react-bootstrap-table2-paginator/index.js');
const overlaySourcePath = path.join(__dirname, '../../react-bootstrap-table2-overlay'); const overlaySourcePath = path.join(__dirname, '../../react-bootstrap-table2-overlay/index.js');
const filterSourcePath = path.join(__dirname, '../../react-bootstrap-table2-filter'); const filterSourcePath = path.join(__dirname, '../../react-bootstrap-table2-filter/index.js');
const editorSourcePath = path.join(__dirname, '../../react-bootstrap-table2-editor'); const editorSourcePath = path.join(__dirname, '../../react-bootstrap-table2-editor/index.js');
const sourceStylePath = path.join(__dirname, '../../react-bootstrap-table2/style'); 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 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');
@@ -33,15 +34,14 @@ const loaders = [{
}, { }, {
test: /\.js?$/, test: /\.js?$/,
use: ['babel-loader'], use: ['babel-loader'],
exclude: /node_modules/, exclude: /node_modules/
include: [sourcePath, paginationSourcePath, overlaySourcePath, filterSourcePath, editorSourcePath, storyPath]
}, { }, {
test: /\.css$/, test: /\.css$/,
use: ['style-loader', 'css-loader'], use: ['style-loader', 'css-loader'],
}, { }, {
test: /\.scss$/, test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader'], use: ['style-loader', 'css-loader', 'sass-loader'],
include: [storyPath, sourceStylePath, paginationStylePath], include: [storyPath, sourceStylePath, paginationStylePath, filterStylePath],
}, { }, {
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

@@ -18,6 +18,9 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
// omit...
<BootstrapTable <BootstrapTable
keyField="id" keyField="id"
data={ products } data={ products }

View File

@@ -18,6 +18,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'

View File

@@ -18,6 +18,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'

View File

@@ -15,9 +15,12 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
// omit...
<BootstrapTable keyField='id' data={ [] } columns={ columns } noDataIndication="Table is Empty" /> <BootstrapTable keyField='id' data={ [] } columns={ columns } noDataIndication="Table is Empty" />
// Following is more customizable example // Following is a more flexible example
function indication() { function indication() {
// return something here // return something here

View File

@@ -18,6 +18,9 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
// omit...
<BootstrapTable <BootstrapTable
keyField="id" keyField="id"
data={ products } data={ products }

View File

@@ -19,8 +19,9 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor'; import cellEditFactory from 'react-bootstrap-table2-editor';
// ...
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'

View File

@@ -23,8 +23,9 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor'; import cellEditFactory from 'react-bootstrap-table2-editor';
// ...
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'

View File

@@ -21,8 +21,9 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor'; import cellEditFactory from 'react-bootstrap-table2-editor';
// ...
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'

View File

@@ -27,8 +27,9 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor'; import cellEditFactory from 'react-bootstrap-table2-editor';
// ...
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'

View File

@@ -34,8 +34,9 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor'; import cellEditFactory from 'react-bootstrap-table2-editor';
// ...
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'

View File

@@ -21,8 +21,9 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor'; import cellEditFactory from 'react-bootstrap-table2-editor';
// ...
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'
@@ -45,6 +46,7 @@ const columns = [{
export default () => ( export default () => (
<div> <div>
<h3>Only Product Price is bigger than 2101 is editable</h3>
<BootstrapTable <BootstrapTable
keyField="id" keyField="id"
data={ products } data={ products }

View File

@@ -20,8 +20,9 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor'; import cellEditFactory from 'react-bootstrap-table2-editor';
// ...
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'
@@ -43,6 +44,7 @@ const columns = [{
export default () => ( export default () => (
<div> <div>
<h3>Click to edit cell</h3>
<BootstrapTable <BootstrapTable
keyField="id" keyField="id"
data={ products } data={ products }

View File

@@ -20,8 +20,9 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor'; import cellEditFactory from 'react-bootstrap-table2-editor';
// ...
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'
@@ -48,6 +49,7 @@ const columns = [{
export default () => ( export default () => (
<div> <div>
<h3>Product Name is non editable</h3>
<BootstrapTable <BootstrapTable
keyField="id" keyField="id"
data={ products } data={ products }

View File

@@ -19,8 +19,9 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor'; import cellEditFactory from 'react-bootstrap-table2-editor';
// ...
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'
@@ -42,6 +43,7 @@ const columns = [{
export default () => ( export default () => (
<div> <div>
<h3>Double click to edit cell</h3>
<BootstrapTable <BootstrapTable
keyField="id" keyField="id"
data={ products } data={ products }

View File

@@ -19,8 +19,9 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor'; import cellEditFactory from 'react-bootstrap-table2-editor';
// ...
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'
@@ -45,6 +46,7 @@ const columns = [{
`; `;
export default () => ( export default () => (
<div> <div>
<h3>Product ID: 0, 3 is non editable</h3>
<BootstrapTable <BootstrapTable
keyField="id" keyField="id"
data={ products } data={ products }

View File

@@ -32,6 +32,7 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter'; import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
const owners = ['Allen', 'Bob', 'Cat']; const owners = ['Allen', 'Bob', 'Cat'];

View File

@@ -0,0 +1,74 @@
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { numberFilter, Comparator } from 'react-bootstrap-table2-filter';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator(8);
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price',
filter: numberFilter({
options: [2100, 2103, 2105],
delay: 600,
placeholder: 'custom placeholder',
withoutEmptyComparatorOption: true,
comparators: [Comparator.EQ, Comparator.GT, Comparator.LT],
style: { display: 'inline-grid' },
className: 'custom-numberfilter-class',
comparatorStyle: { backgroundColor: 'antiquewhite' },
comparatorClassName: 'custom-comparator-class',
numberStyle: { backgroundColor: 'cadetblue', margin: '0px' },
numberClassName: 'custom-number-class'
})
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { numberFilter, Comparator } from 'react-bootstrap-table2-filter';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price',
filter: numberFilter({
options: [2100, 2103, 2105],
delay: 600,
placeholder: 'custom placeholder',
withoutEmptyComparatorOption: true,
comparators: [Comparator.EQ, Comparator.GT, Comparator.LT],
style: { display: 'inline-grid' },
className: 'custom-numberfilter-class',
comparatorStyle: { backgroundColor: 'antiquewhite' },
comparatorClassName: 'custom-comparator-class',
numberStyle: { backgroundColor: 'cadetblue', margin: '0px' },
numberClassName: 'custom-number-class'
})
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
`;
export default () => (
<div>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
filter={ filterFactory() }
/>
<Code>{ sourceCode }</Code>
</div>
);

View File

@@ -0,0 +1,80 @@
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { selectFilter } from 'react-bootstrap-table2-filter';
import Code from 'components/common/code-block';
import { productsQualityGenerator } from 'utils/common';
const products = productsQualityGenerator(6);
const selectOptions = {
0: 'good',
1: 'Bad',
2: 'unknown'
};
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'quality',
text: 'Product Quailty',
formatter: cell => selectOptions[cell],
filter: selectFilter({
options: selectOptions,
withoutEmptyOption: true,
style: {
backgroundColor: 'pink'
},
className: 'test-classname',
datamycustomattr: 'datamycustomattr'
})
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { 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'
}, {
dataField: 'quality',
text: 'Product Quailty',
formatter: cell => selectOptions[cell],
filter: selectFilter({
options: selectOptions,
withoutEmptyOption: true,
style: {
backgroundColor: 'pink'
},
className: 'test-classname',
datamycustomattr: 'datamycustomattr'
})
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
`;
export default () => (
<div>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
filter={ filterFactory() }
/>
<Code>{ sourceCode }</Code>
</div>
);

View File

@@ -29,6 +29,7 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter'; import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
const columns = [{ const columns = [{

View File

@@ -0,0 +1,54 @@
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { numberFilter, Comparator } from 'react-bootstrap-table2-filter';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator(8);
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price',
filter: numberFilter({
defaultValue: { number: 2103, comparator: Comparator.GT }
})
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { numberFilter, Comparator } from 'react-bootstrap-table2-filter';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price',
filter: numberFilter({
defaultValue: { number: 2103, comparator: Comparator.GT }
})
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
`;
export default () => (
<div>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
filter={ filterFactory() }
/>
<Code>{ sourceCode }</Code>
</div>
);

View File

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

View File

@@ -0,0 +1,70 @@
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { selectFilter } from 'react-bootstrap-table2-filter';
import Code from 'components/common/code-block';
import { productsQualityGenerator } from 'utils/common';
const products = productsQualityGenerator(6);
const selectOptions = {
0: 'good',
1: 'Bad',
2: 'unknown'
};
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'quality',
text: 'Product Quailty',
formatter: cell => selectOptions[cell],
filter: selectFilter({
options: selectOptions,
defaultValue: 2
})
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { 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'
}, {
dataField: 'quality',
text: 'Product Quailty',
formatter: cell => selectOptions[cell],
filter: selectFilter({
options: selectOptions,
defaultValue: 2
})
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
`;
export default () => (
<div>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
filter={ filterFactory() }
/>
<Code>{ sourceCode }</Code>
</div>
);

View File

@@ -0,0 +1,69 @@
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { selectFilter, Comparator } from 'react-bootstrap-table2-filter';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator(6);
const selectOptions = {
'03': '03',
'04': '04',
'01': '01'
};
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price',
filter: selectFilter({
options: selectOptions,
comparator: Comparator.LIKE // default is Comparator.EQ
})
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { selectFilter } from 'react-bootstrap-table2-filter';
const selectOptions = {
'03': '03',
'04': '04',
'01': '01'
};
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price',
filter: selectFilter({
options: selectOptions,
comparator: Comparator.LIKE // default is Comparator.EQ
})
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
`;
export default () => (
<div>
<h3>Select Filter with LIKE Comparator</h3>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
filter={ filterFactory() }
/>
<Code>{ sourceCode }</Code>
</div>
);

View File

@@ -0,0 +1,68 @@
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { selectFilter } from 'react-bootstrap-table2-filter';
import Code from 'components/common/code-block';
import { productsQualityGenerator } from 'utils/common';
const products = productsQualityGenerator(6);
const selectOptions = {
0: 'good',
1: 'Bad',
2: 'unknown'
};
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'quality',
text: 'Product Quailty',
formatter: cell => selectOptions[cell],
filter: selectFilter({
options: selectOptions
})
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { 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'
}, {
dataField: 'quality',
text: 'Product Quailty',
formatter: cell => selectOptions[cell],
filter: selectFilter({
options: selectOptions
})
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
`;
export default () => (
<div>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
filter={ filterFactory() }
/>
<Code>{ sourceCode }</Code>
</div>
);

View File

@@ -0,0 +1,51 @@
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator(8);
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name',
filter: textFilter({ caseSensitive: true })
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name',
filter: textFilter({ caseSensitive: true })
}, {
dataField: 'price',
text: 'Product Price'
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
`;
export default () => (
<div>
<h3>Product Name is case sensitive</h3>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
filter={ filterFactory() }
/>
<Code>{ sourceCode }</Code>
</div>
);

View File

@@ -22,6 +22,7 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter'; import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
const columns = [{ const columns = [{

View File

@@ -22,6 +22,7 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { textFilter, Comparator } from 'react-bootstrap-table2-filter'; import filterFactory, { textFilter, Comparator } from 'react-bootstrap-table2-filter';
const columns = [{ const columns = [{

View File

@@ -20,6 +20,7 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter'; import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
const columns = [{ const columns = [{

View File

@@ -24,6 +24,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID', text: 'Product ID',

View File

@@ -21,6 +21,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID', text: 'Product ID',
@@ -39,6 +41,7 @@ const columns = [{
export default () => ( export default () => (
<div> <div>
<h3>Try to hover on Product Name header column</h3>
<BootstrapTable keyField="id" data={ products } columns={ columns } /> <BootstrapTable keyField="id" data={ products } columns={ columns } />
<Code>{ sourceCode }</Code> <Code>{ sourceCode }</Code>
</div> </div>

View File

@@ -24,6 +24,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID', text: 'Product ID',

View File

@@ -23,6 +23,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID', text: 'Product ID',

View File

@@ -31,6 +31,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
function priceFormatter(cell, row) { function priceFormatter(cell, row) {
if (row.onSale) { if (row.onSale) {
return ( return (

View File

@@ -34,6 +34,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
function rankFormatter(cell, row, rowIndex, formatExtraData) { function rankFormatter(cell, row, rowIndex, formatExtraData) {
return ( return (
<i className={ formatExtraData[cell] } /> <i className={ formatExtraData[cell] } />

View File

@@ -20,6 +20,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID', text: 'Product ID',

View File

@@ -33,6 +33,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID', text: 'Product ID',

View File

@@ -39,6 +39,7 @@ const columns = [{
export default () => ( export default () => (
<div> <div>
<h3>Try to hover on any Product Name cells</h3>
<BootstrapTable keyField="id" data={ products } columns={ columns } /> <BootstrapTable keyField="id" data={ products } columns={ columns } />
<Code>{ sourceCode }</Code> <Code>{ sourceCode }</Code>
</div> </div>

View File

@@ -32,6 +32,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'User ID' text: 'User ID'

View File

@@ -21,6 +21,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID', text: 'Product ID',

View File

@@ -21,6 +21,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID', text: 'Product ID',

View File

@@ -24,6 +24,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'

View File

@@ -23,6 +23,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID', text: 'Product ID',

View File

@@ -41,6 +41,7 @@ const defaultSorted = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter'; import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
// ... // ...
function priceFormatter(column, colIndex, { sortElement, filterElement }) { function priceFormatter(column, colIndex, { sortElement, filterElement }) {

View File

@@ -26,6 +26,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
function priceFormatter(column, colIndex) { function priceFormatter(column, colIndex) {
return ( return (
<h5><strong>$$ { column.text } $$</strong></h5> <h5><strong>$$ { column.text } $$</strong></h5>

View File

@@ -32,6 +32,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'

View File

@@ -21,6 +21,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID', text: 'Product ID',

View File

@@ -22,7 +22,7 @@ const columns = [{
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next'; import BootstrapTable from 'react-bootstrap-table-next';
import paginationFactory from 'react-bootstrap-table2-paginator'; import paginationFactory from 'react-bootstrap-table2-paginator';
// ...
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'

View File

@@ -23,7 +23,7 @@ const columns = [{
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next'; import BootstrapTable from 'react-bootstrap-table-next';
import paginationFactory from 'react-bootstrap-table2-paginator'; import paginationFactory from 'react-bootstrap-table2-paginator';
// ...
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'

View File

@@ -19,8 +19,10 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor'; import cellEditFactory from 'react-bootstrap-table2-editor';
// ... // ...
const RemoteCellEdit = (props) => { const RemoteCellEdit = (props) => {
const cellEdit = { const cellEdit = {
mode: 'click', mode: 'click',
@@ -42,12 +44,6 @@ const RemoteCellEdit = (props) => {
); );
}; };
RemoteCellEdit.propTypes = {
data: PropTypes.array.isRequired,
onTableChange: PropTypes.func.isRequired,
errorMessage: PropTypes.string.isRequired
};
class Container extends React.Component { class Container extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);

View File

@@ -23,6 +23,7 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter'; import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
const columns = [{ const columns = [{
@@ -38,7 +39,61 @@ const columns = [{
filter: textFilter() filter: textFilter()
}]; }];
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } /> const RemoteFilter = props => (
<div>
<BootstrapTable
remote={ { filter: true } }
keyField="id"
data={ props.data }
columns={ columns }
filter={ filterFactory() }
onTableChange={ props.onTableChange }
/>
<Code>{ sourceCode }</Code>
</div>
);
class Container extends React.Component {
constructor(props) {
super(props);
this.state = {
data: products
};
}
handleTableChange = (type, { filters }) => {
setTimeout(() => {
const result = products.filter((row) => {
let valid = true;
for (const dataField in filters) {
const { filterVal, filterType, comparator } = filters[dataField];
if (filterType === 'TEXT') {
if (comparator === Comparator.LIKE) {
valid = row[dataField].toString().indexOf(filterVal) > -1;
} else {
valid = row[dataField] === filterVal;
}
}
if (!valid) break;
}
return valid;
});
this.setState(() => ({
data: result
}));
}, 2000);
}
render() {
return (
<RemoteFilter
data={ this.state.data }
onTableChange={ this.handleTableChange }
/>
);
}
}
`; `;
const RemoteFilter = props => ( const RemoteFilter = props => (

View File

@@ -47,7 +47,7 @@ class Container extends React.Component {
}; };
} }
handleTableChange = ({ page, sizePerPage }) => { handleTableChange = (type, { page, sizePerPage }) => {
const currentIndex = (page - 1) * sizePerPage; const currentIndex = (page - 1) * sizePerPage;
setTimeout(() => { setTimeout(() => {
this.setState(() => ({ this.setState(() => ({

View File

@@ -21,7 +21,7 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter'; import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
@@ -36,7 +36,64 @@ const columns = [{
filter: textFilter() filter: textFilter()
}]; }];
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } /> const RemoteSort = props => (
<div>
<BootstrapTable
remote={ { sort: true } }
keyField="id"
data={ props.data }
columns={ columns }
onTableChange={ props.onTableChange }
/>
<Code>{ sourceCode }</Code>
</div>
);
class Container extends React.Component {
constructor(props) {
super(props);
this.state = {
data: products
};
}
handleTableChange = (type, { sortField, sortOrder, data }) => {
setTimeout(() => {
let result;
if (sortOrder === 'asc') {
result = data.sort((a, b) => {
if (a[sortField] > b[sortField]) {
return 1;
} else if (b[sortField] > a[sortField]) {
return -1;
}
return 0;
});
} else {
result = data.sort((a, b) => {
if (a[sortField] > b[sortField]) {
return -1;
} else if (b[sortField] > a[sortField]) {
return 1;
}
return 0;
});
}
this.setState(() => ({
data: result
}));
}, 2000);
}
render() {
return (
<RemoteSort
data={ this.state.data }
onTableChange={ this.handleTableChange }
/>
);
}
}
`; `;
const RemoteSort = props => ( const RemoteSort = props => (

View File

@@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next'; import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';
@@ -23,11 +24,10 @@ const selectRow = {
clickToEdit: true clickToEdit: true
}; };
const cellEdit = {
mode: 'click'
};
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor';
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'
@@ -50,16 +50,23 @@ const cellEdit = {
}; };
<BootstrapTable <BootstrapTable
keyField='id' keyField="id"
data={ products } data={ products }
columns={ columns } columns={ columns }
selectRow={ selectRow } selectRow={ selectRow }
cellEdit={ cellEditFactory({ mode: 'click' }) }
/> />
`; `;
export default () => ( export default () => (
<div> <div>
<BootstrapTable keyField="id" data={ products } columns={ columns } selectRow={ selectRow } cellEdit={ cellEdit } /> <BootstrapTable
keyField="id"
data={ products }
columns={ columns }
selectRow={ selectRow }
cellEdit={ cellEditFactory({ mode: 'click' }) }
/>
<Code>{ sourceCode }</Code> <Code>{ sourceCode }</Code>
</div> </div>
); );

View File

@@ -23,6 +23,8 @@ const selectRow = {
}; };
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'

View File

@@ -25,6 +25,8 @@ const selectRow = {
}; };
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'

View File

@@ -23,6 +23,8 @@ const selectRow = {
}; };
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'

View File

@@ -24,6 +24,8 @@ const selectRow = {
}; };
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'

View File

@@ -31,6 +31,8 @@ const selectRow2 = {
}; };
const sourceCode1 = `\ const sourceCode1 = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'

View File

@@ -32,6 +32,8 @@ const selectRow2 = {
}; };
const sourceCode1 = `\ const sourceCode1 = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'

View File

@@ -34,6 +34,8 @@ const selectRow = {
}; };
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'

View File

@@ -34,6 +34,8 @@ const selectRow2 = {
}; };
const sourceCode1 = `\ const sourceCode1 = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'

View File

@@ -23,6 +23,8 @@ const selectRow = {
}; };
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'

View File

@@ -20,6 +20,8 @@ const columns = [{
const rowClasses1 = 'custom-row-class'; const rowClasses1 = 'custom-row-class';
const sourceCode1 = `\ const sourceCode1 = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'

View File

@@ -1,5 +1,5 @@
/* eslint no-unused-vars: 0 */ /* eslint no-unused-vars: 0 */
/* eslint no-console: 0 */ /* eslint no-alert: 0 */
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next'; import BootstrapTable from 'react-bootstrap-table-next';
@@ -20,12 +20,14 @@ const columns = [{
}]; }];
const rowEvents = { const rowEvents = {
onClick: (e) => { onClick: (e, row, rowIndex) => {
console.log('click on row'); alert(`clicked on row with index: ${rowIndex}`);
} }
}; };
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'
@@ -38,16 +40,17 @@ const columns = [{
}]; }];
const rowEvents = { const rowEvents = {
onClick: (e) => { onClick: (e, row, rowIndex) => {
console.log('click on row'); alert(\`clicked on row with index: \${rowIndex}\`);
} }
}; };
<BootstrapTable keyField='id' data={ products } columns={ columns } rowStyle={ rowStyle } /> <BootstrapTable keyField='id' data={ products } columns={ columns } rowEvents={ rowEvents } />
`; `;
export default () => ( export default () => (
<div> <div>
<h3>Try to click on any rows</h3>
<BootstrapTable keyField="id" data={ products } columns={ columns } rowEvents={ rowEvents } /> <BootstrapTable keyField="id" data={ products } columns={ columns } rowEvents={ rowEvents } />
<Code>{ sourceCode }</Code> <Code>{ sourceCode }</Code>
</div> </div>

View File

@@ -20,6 +20,8 @@ const columns = [{
const rowStyle1 = { backgroundColor: '#c8e6c9' }; const rowStyle1 = { backgroundColor: '#c8e6c9' };
const sourceCode1 = `\ const sourceCode1 = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID' text: 'Product ID'

View File

@@ -29,6 +29,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID', text: 'Product ID',
@@ -54,6 +56,7 @@ const columns = [{
export default () => ( export default () => (
<div> <div>
<h3>Product ID sorting is reverted</h3>
<BootstrapTable keyField="id" data={ products } columns={ columns } /> <BootstrapTable keyField="id" data={ products } columns={ columns } />
<Code>{ sourceCode }</Code> <Code>{ sourceCode }</Code>
</div> </div>

View File

@@ -27,6 +27,8 @@ const defaultSorted = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID', text: 'Product ID',

View File

@@ -20,6 +20,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID', text: 'Product ID',

View File

@@ -31,6 +31,8 @@ const columns = [{
}]; }];
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const headerSortingClasses = (column, sortOrder, isLastSorting, colIndex) => ( const headerSortingClasses = (column, sortOrder, isLastSorting, colIndex) => (
sortOrder === 'asc' ? 'demo-sorting-asc' : 'demo-sorting-desc' sortOrder === 'asc' ? 'demo-sorting-asc' : 'demo-sorting-desc'
); );

View File

@@ -26,6 +26,8 @@ const columns = [{
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const headerSortingStyle = { backgroundColor: '#c8e6c9' }; const headerSortingStyle = { backgroundColor: '#c8e6c9' };
const columns = [{ const columns = [{

View File

@@ -0,0 +1,58 @@
/* eslint no-console: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID',
sort: true
}, {
dataField: 'name',
text: 'Product Name',
sort: true,
onSort: (field, order) => {
console.log(`Sort Field: ${field}, Sort Order: ${order}`);
}
}, {
dataField: 'price',
text: 'Product Price'
}];
const defaultSorted = [{
dataField: 'name',
order: 'desc'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{
dataField: 'id',
text: 'Product ID',
sort: true
}, {
dataField: 'name',
text: 'Product Name',
sort: true,
onSort: (field, order) => {
console.log(....);
}
}, {
dataField: 'price',
text: 'Product Price'
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } />
`;
export default () => (
<div>
<BootstrapTable keyField="id" data={ products } columns={ columns } defaultSorted={ defaultSorted } />
<Code>{ sourceCode }</Code>
</div>
);

View File

@@ -1,6 +1,6 @@
{ {
"name": "react-bootstrap-table2-example", "name": "react-bootstrap-table2-example",
"version": "0.0.3", "version": "0.1.2",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"private": true, "private": true,
@@ -23,6 +23,7 @@
"devDependencies": { "devDependencies": {
"@storybook/addon-console": "^1.0.0", "@storybook/addon-console": "^1.0.0",
"@storybook/react": "^3.2.8", "@storybook/react": "^3.2.8",
"babel-plugin-transform-class-properties": "6.24.1",
"babel-preset-env": "^1.6.1", "babel-preset-env": "^1.6.1",
"react-redux": "^5.0.6", "react-redux": "^5.0.6",
"redux": "^3.7.2", "redux": "^3.7.2",

View File

@@ -20,6 +20,13 @@ export const productsGenerator = (quantity = 5, callback) => {
); );
}; };
export const productsQualityGenerator = (quantity = 5) =>
Array.from({ length: quantity }, (value, index) => ({
id: index,
name: `Item name ${index}`,
quality: index % 3
}));
export const jobsGenerator = (quantity = 5) => export const jobsGenerator = (quantity = 5) =>
Array.from({ length: quantity }, (value, index) => ({ Array.from({ length: quantity }, (value, index) => ({
id: index, id: index,

View File

@@ -37,8 +37,16 @@ import HeaderColumnAttrsTable from 'examples/header-columns/column-attrs-table';
import TextFilter from 'examples/column-filter/text-filter'; import TextFilter from 'examples/column-filter/text-filter';
import TextFilterWithDefaultValue from 'examples/column-filter/text-filter-default-value'; import TextFilterWithDefaultValue from 'examples/column-filter/text-filter-default-value';
import TextFilterComparator from 'examples/column-filter/text-filter-eq-comparator'; import TextFilterComparator from 'examples/column-filter/text-filter-eq-comparator';
import TextFilterCaseSensitive from 'examples/column-filter/text-filter-caseSensitive';
import CustomTextFilter from 'examples/column-filter/custom-text-filter'; import CustomTextFilter from 'examples/column-filter/custom-text-filter';
import CustomFilterValue from 'examples/column-filter/custom-filter-value'; import CustomFilterValue from 'examples/column-filter/custom-filter-value';
import SelectFilter from 'examples/column-filter/select-filter';
import SelectFilterWithDefaultValue from 'examples/column-filter/select-filter-default-value';
import SelectFilterComparator from 'examples/column-filter/select-filter-like-comparator';
import CustomSelectFilter from 'examples/column-filter/custom-select-filter';
import NumberFilter from 'examples/column-filter/number-filter';
import NumberFilterWithDefaultValue from 'examples/column-filter/number-filter-default-value';
import CustomNumberFilter from 'examples/column-filter/custom-number-filter';
// work on rows // work on rows
import RowStyleTable from 'examples/rows/row-style'; import RowStyleTable from 'examples/rows/row-style';
@@ -48,6 +56,7 @@ import RowEventTable from 'examples/rows/row-event';
// table sort // table sort
import EnableSortTable from 'examples/sort/enable-sort-table'; import EnableSortTable from 'examples/sort/enable-sort-table';
import DefaultSortTable from 'examples/sort/default-sort-table'; import DefaultSortTable from 'examples/sort/default-sort-table';
import SortEvents from 'examples/sort/sort-events';
import CustomSortTable from 'examples/sort/custom-sort-table'; import CustomSortTable from 'examples/sort/custom-sort-table';
import HeaderSortingClassesTable from 'examples/sort/header-sorting-classes'; import HeaderSortingClassesTable from 'examples/sort/header-sorting-classes';
import HeaderSortingStyleTable from 'examples/sort/header-sorting-style'; import HeaderSortingStyleTable from 'examples/sort/header-sorting-style';
@@ -96,8 +105,9 @@ import RemoteAll from 'examples/remote/remote-all';
import 'bootstrap/dist/css/bootstrap.min.css'; import 'bootstrap/dist/css/bootstrap.min.css';
import 'stories/stylesheet/tomorrow.min.css'; import 'stories/stylesheet/tomorrow.min.css';
import 'stories/stylesheet/storybook.scss'; 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 { action } from '@storybook/addon-actions'; // import { action } from '@storybook/addon-actions';
@@ -138,8 +148,16 @@ storiesOf('Column Filter', module)
.add('Text Filter', () => <TextFilter />) .add('Text Filter', () => <TextFilter />)
.add('Text Filter with Default Value', () => <TextFilterWithDefaultValue />) .add('Text Filter with Default Value', () => <TextFilterWithDefaultValue />)
.add('Text Filter with Comparator', () => <TextFilterComparator />) .add('Text Filter with Comparator', () => <TextFilterComparator />)
.add('Custom Text Filter', () => <CustomTextFilter />) .add('Text Filter with Case Sensitive', () => <TextFilterCaseSensitive />)
// add another filter type example right here. // add another filter type example right here.
.add('Select Filter', () => <SelectFilter />)
.add('Select Filter with Default Value', () => <SelectFilterWithDefaultValue />)
.add('Select Filter with Comparator', () => <SelectFilterComparator />)
.add('Number Filter', () => <NumberFilter />)
.add('Number Filter with Default Value', () => <NumberFilterWithDefaultValue />)
.add('Custom Text Filter', () => <CustomTextFilter />)
.add('Custom Select Filter', () => <CustomSelectFilter />)
.add('Custom Number Filter', () => <CustomNumberFilter />)
.add('Custom Filter Value', () => <CustomFilterValue />); .add('Custom Filter Value', () => <CustomFilterValue />);
storiesOf('Work on Rows', module) storiesOf('Work on Rows', module)
@@ -150,6 +168,7 @@ storiesOf('Work on Rows', module)
storiesOf('Sort Table', module) storiesOf('Sort Table', module)
.add('Enable Sort', () => <EnableSortTable />) .add('Enable Sort', () => <EnableSortTable />)
.add('Default Sort Table', () => <DefaultSortTable />) .add('Default Sort Table', () => <DefaultSortTable />)
.add('Sort Events', () => <SortEvents />)
.add('Custom Sort Fuction', () => <CustomSortTable />) .add('Custom Sort Fuction', () => <CustomSortTable />)
.add('Custom Classes on Sorting Header Column', () => <HeaderSortingClassesTable />) .add('Custom Classes on Sorting Header Column', () => <HeaderSortingClassesTable />)
.add('Custom Style on Sorting Header Column', () => <HeaderSortingStyleTable />); .add('Custom Style on Sorting Header Column', () => <HeaderSortingStyleTable />);

View File

@@ -4,6 +4,8 @@
**[Live Demo For Column Filter](https://github.com/react-bootstrap-table/react-bootstrap-table2/blob/gh-pages-src/storybook/index.html?selectedKind=Column%20Filter)** **[Live Demo For Column Filter](https://github.com/react-bootstrap-table/react-bootstrap-table2/blob/gh-pages-src/storybook/index.html?selectedKind=Column%20Filter)**
**[API&Props Definitation](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/filter-props.html)**
----- -----
## Install ## Install
@@ -15,8 +17,20 @@ $ npm install react-bootstrap-table2-filter --save
You can get all types of filters via import and these filters are a factory function to create a individual filter instance. Currently, we support following filters: You can get all types of filters via import and these filters are a factory function to create a individual filter instance. Currently, we support following filters:
* TextFilter * TextFilter
* SelectFilter
* NumberFilter
* **Coming soon!** * **Coming soon!**
## Add CSS
```js
// es5
require('react-bootstrap-table2-filter/dist/react-bootstrap-table2-filter.min.css');
// es6
import 'react-bootstrap-table2-filter/dist/react-bootstrap-table2-filter.min.css';
```
## Text Filter ## Text Filter
Following is a quick demo for enable the column filter on **Product Price** column!! Following is a quick demo for enable the column filter on **Product Price** column!!
@@ -45,9 +59,94 @@ const priceFilter = textFilter({
className: 'my-custom-text-filter', // custom classname on input className: 'my-custom-text-filter', // custom classname on input
defaultValue: 'test', // default filtering value defaultValue: 'test', // default filtering value
comparator: Comparator.EQ, // default is Comparator.LIKE comparator: Comparator.EQ, // default is Comparator.LIKE
caseSensitive: true, // default is false, and true will only work when comparator is LIKE
style: { ... }, // your custom styles on input style: { ... }, // your custom styles on input
delay: 1000 // how long will trigger filtering after user typing, default is 500 ms delay: 1000 // how long will trigger filtering after user typing, default is 500 ms
}); });
// omit... // omit...
``` ```
## Select Filter
A quick example:
```js
import filterFactory, { selectFilter } from 'react-bootstrap-table2-filter';
// omit...
const selectOptions = {
0: 'good',
1: 'Bad',
2: 'unknown'
};
const columns = [
..., {
dataField: 'quality',
text: 'Product Quailty',
formatter: cell => selectOptions[cell],
filter: selectFilter({
options: selectOptions
})
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
```
Following is an example for custom select filter:
```js
import filterFactory, { selectFilter, Comparator } from 'react-bootstrap-table2-filter';
// omit...
const qualityFilter = selectFilter({
options: selectOptions,
placeholder: 'My Custom PlaceHolder', // custom the input placeholder
className: 'my-custom-text-filter', // custom classname on input
defaultValue: '2', // default filtering value
comparator: Comparator.LIKE, // default is Comparator.EQ
style: { ... }, // your custom styles on input
withoutEmptyOption: true // hide the default select option
});
// omit...
```
## Number Filter
```js
import filterFactory, { numberFilter } from 'react-bootstrap-table2-filter';
const columns = [..., {
dataField: 'price',
text: 'Product Price',
filter: numberFilter()
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
```
Numner filter is same as other filter, you can custom the number filter via `numberFilter` factory function:
```js
import filterFactory, { selectFilter, Comparator } from 'react-bootstrap-table2-filter';
// omit...
const numberFilter = numberFilter({
options: [2100, 2103, 2105], // if options defined, will render number select instead of number input
delay: 600, // how long will trigger filtering after user typing, default is 500 ms
placeholder: 'custom placeholder', // placeholder for number input
withoutEmptyComparatorOption: true, // dont render empty option for comparator
withoutEmptyNumberOption: true, // dont render empty option for numner select if it is defined
comparators: [Comparator.EQ, Comparator.GT, Comparator.LT], // Custom the comparators
style: { display: 'inline-grid' }, // custom the style on number filter
className: 'custom-numberfilter-class', // custom the class on number filter
comparatorStyle: { backgroundColor: 'antiquewhite' }, // custom the style on comparator select
comparatorClassName: 'custom-comparator-class', // custom the class on comparator select
numberStyle: { backgroundColor: 'cadetblue', margin: '0px' }, // custom the style on number input/select
numberClassName: 'custom-number-class', // custom the class on ber input/select
defaultValue: { number: 2103, comparator: Comparator.GT } // default value
})
// omit...
```

View File

@@ -1,4 +1,6 @@
import TextFilter from './src/components/text'; import TextFilter from './src/components/text';
import SelectFilter from './src/components/select';
import NumberFilter from './src/components/number';
import wrapperFactory from './src/wrapper'; import wrapperFactory from './src/wrapper';
import * as Comparison from './src/comparison'; import * as Comparison from './src/comparison';
@@ -13,3 +15,13 @@ export const textFilter = (props = {}) => ({
Filter: TextFilter, Filter: TextFilter,
props props
}); });
export const selectFilter = (props = {}) => ({
Filter: SelectFilter,
props
});
export const numberFilter = (props = {}) => ({
Filter: NumberFilter,
props
});

View File

@@ -1,6 +1,6 @@
{ {
"name": "react-bootstrap-table2-filter", "name": "react-bootstrap-table2-filter",
"version": "0.0.3", "version": "0.1.3",
"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": {
@@ -25,6 +25,11 @@
], ],
"author": "AllenFang", "author": "AllenFang",
"contributors": [ "contributors": [
{
"name": "Allen Fang",
"email": "ayu780129@hotmail.com",
"url": "https://github.com/AllenFang"
},
{ {
"name": "Chun-MingChen", "name": "Chun-MingChen",
"email": "nick830314@gmail.com", "email": "nick830314@gmail.com",

View File

@@ -1,2 +1,7 @@
export const LIKE = 'LIKE'; export const LIKE = 'LIKE';
export const EQ = '='; export const EQ = '=';
export const NE = '!=';
export const GT = '>';
export const GE = '>=';
export const LT = '<';
export const LE = '<=';

View File

@@ -0,0 +1,249 @@
/* eslint no-return-assign: 0 */
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import * as Comparator from '../comparison';
import { FILTER_TYPE, FILTER_DELAY } from '../const';
const legalComparators = [
Comparator.EQ,
Comparator.NE,
Comparator.GT,
Comparator.GE,
Comparator.LT,
Comparator.LE
];
class NumberFilter extends Component {
constructor(props) {
super(props);
this.comparators = props.comparators || legalComparators;
this.timeout = null;
let isSelected = props.defaultValue !== undefined && props.defaultValue.number !== undefined;
if (props.options && isSelected) {
isSelected = props.options.indexOf(props.defaultValue.number) > -1;
}
this.state = { isSelected };
this.onChangeNumber = this.onChangeNumber.bind(this);
this.onChangeNumberSet = this.onChangeNumberSet.bind(this);
this.onChangeComparator = this.onChangeComparator.bind(this);
}
componentDidMount() {
const { column, onFilter } = this.props;
const comparator = this.numberFilterComparator.value;
const number = this.numberFilter.value;
if (comparator && number) {
onFilter(column, { number, comparator }, FILTER_TYPE.NUMBER);
}
}
componentWillUnmount() {
clearTimeout(this.timeout);
}
onChangeNumber(e) {
const { delay, column, onFilter } = this.props;
const comparator = this.numberFilterComparator.value;
if (comparator === '') {
return;
}
if (this.timeout) {
clearTimeout(this.timeout);
}
const filterValue = e.target.value;
this.timeout = setTimeout(() => {
onFilter(column, { number: filterValue, comparator }, FILTER_TYPE.NUMBER);
}, delay);
}
onChangeNumberSet(e) {
const { column, onFilter } = this.props;
const comparator = this.numberFilterComparator.value;
const { value } = e.target;
this.setState(() => ({ isSelected: (value !== '') }));
// if (comparator === '') {
// return;
// }
onFilter(column, { number: value, comparator }, FILTER_TYPE.NUMBER);
}
onChangeComparator(e) {
const { column, onFilter } = this.props;
const value = this.numberFilter.value;
const comparator = e.target.value;
// if (value === '') {
// return;
// }
onFilter(column, { number: value, comparator }, FILTER_TYPE.NUMBER);
}
getComparatorOptions() {
const optionTags = [];
const { withoutEmptyComparatorOption } = this.props;
if (!withoutEmptyComparatorOption) {
optionTags.push(<option key="-1" />);
}
for (let i = 0; i < this.comparators.length; i += 1) {
optionTags.push(
<option key={ i } value={ this.comparators[i] }>
{ this.comparators[i] }
</option>
);
}
return optionTags;
}
getNumberOptions() {
const optionTags = [];
const { options, column, withoutEmptyNumberOption } = this.props;
if (!withoutEmptyNumberOption) {
optionTags.push(
<option key="-1" value="">
{ this.props.placeholder || `Select ${column.text}...` }
</option>
);
}
for (let i = 0; i < options.length; i += 1) {
optionTags.push(<option key={ i } value={ options[i] }>{ options[i] }</option>);
}
return optionTags;
}
applyFilter(filterObj) {
const { column, onFilter } = this.props;
const { number, comparator } = filterObj;
this.setState(() => ({ isSelected: (number !== '') }));
this.numberFilterComparator.value = comparator;
this.numberFilter.value = number;
onFilter(column, { number, comparator }, FILTER_TYPE.NUMBER);
}
cleanFiltered() {
const { column, onFilter, defaultValue } = this.props;
const value = defaultValue ? defaultValue.number : '';
const comparator = defaultValue ? defaultValue.comparator : '';
this.setState(() => ({ isSelected: (value !== '') }));
this.numberFilterComparator.value = comparator;
this.numberFilter.value = value;
onFilter(column, { number: value, comparator }, FILTER_TYPE.NUMBER);
}
render() {
const { isSelected } = this.state;
const {
defaultValue,
column,
options,
style,
className,
numberStyle,
numberClassName,
comparatorStyle,
comparatorClassName,
placeholder
} = this.props;
const selectClass = `
select-filter
number-filter-input
form-control
${numberClassName}
${!isSelected ? 'placeholder-selected' : ''}
`;
return (
<div className={ `filter number-filter ${className}` } style={ style }>
<select
ref={ n => this.numberFilterComparator = n }
style={ comparatorStyle }
className={ `number-filter-comparator form-control ${comparatorClassName}` }
onChange={ this.onChangeComparator }
defaultValue={ defaultValue ? defaultValue.comparator : '' }
>
{ this.getComparatorOptions() }
</select>
{
options ?
<select
ref={ n => this.numberFilter = n }
style={ numberStyle }
className={ selectClass }
onChange={ this.onChangeNumberSet }
defaultValue={ defaultValue ? defaultValue.number : '' }
>
{ this.getNumberOptions() }
</select> :
<input
ref={ n => this.numberFilter = n }
type="number"
style={ numberStyle }
className={ `number-filter-input form-control ${numberClassName}` }
placeholder={ placeholder || `Enter ${column.text}...` }
onChange={ this.onChangeNumber }
defaultValue={ defaultValue ? defaultValue.number : '' }
/>
}
</div>
);
}
}
NumberFilter.propTypes = {
onFilter: PropTypes.func.isRequired,
column: PropTypes.object.isRequired,
options: PropTypes.arrayOf(PropTypes.number),
defaultValue: PropTypes.shape({
number: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
comparator: PropTypes.oneOf([...legalComparators, ''])
}),
delay: PropTypes.number,
/* eslint consistent-return: 0 */
comparators: (props, propName) => {
if (!props[propName]) {
return;
}
for (let i = 0; i < props[propName].length; i += 1) {
let comparatorIsValid = false;
for (let j = 0; j < legalComparators.length; j += 1) {
if (legalComparators[j] === props[propName][i] || props[propName][i] === '') {
comparatorIsValid = true;
break;
}
}
if (!comparatorIsValid) {
return new Error(`Number comparator provided is not supported.
Use only ${legalComparators}`);
}
}
},
placeholder: PropTypes.string,
withoutEmptyComparatorOption: PropTypes.bool,
withoutEmptyNumberOption: PropTypes.bool,
style: PropTypes.object,
className: PropTypes.string,
comparatorStyle: PropTypes.object,
comparatorClassName: PropTypes.string,
numberStyle: PropTypes.object,
numberClassName: PropTypes.string
};
NumberFilter.defaultProps = {
delay: FILTER_DELAY,
options: undefined,
defaultValue: {
number: undefined,
comparator: ''
},
withoutEmptyComparatorOption: false,
withoutEmptyNumberOption: false,
comparators: legalComparators,
placeholder: undefined,
style: undefined,
className: '',
comparatorStyle: undefined,
comparatorClassName: '',
numberStyle: undefined,
numberClassName: ''
};
export default NumberFilter;

View File

@@ -0,0 +1,135 @@
/* eslint react/require-default-props: 0 */
/* eslint no-return-assign: 0 */
/* eslint react/no-unused-prop-types: 0 */
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { LIKE, EQ } from '../comparison';
import { FILTER_TYPE } from '../const';
function optionsEquals(currOpts, prevOpts) {
const keys = Object.keys(currOpts);
for (let i = 0; i < keys.length; i += 1) {
if (currOpts[keys[i]] !== prevOpts[keys[i]]) {
return false;
}
}
return Object.keys(currOpts).length === Object.keys(prevOpts).length;
}
class SelectFilter extends Component {
constructor(props) {
super(props);
this.filter = this.filter.bind(this);
const isSelected = props.options[props.defaultValue] !== undefined;
this.state = { isSelected };
}
componentDidMount() {
const value = this.selectInput.value;
if (value && value !== '') {
this.props.onFilter(this.props.column, value, FILTER_TYPE.SELECT);
}
}
componentDidUpdate(prevProps) {
let needFilter = false;
if (this.props.defaultValue !== prevProps.defaultValue) {
needFilter = true;
} else if (!optionsEquals(this.props.options, prevProps.options)) {
needFilter = true;
}
if (needFilter) {
const value = this.selectInput.value;
if (value) {
this.props.onFilter(this.props.column, value, FILTER_TYPE.SELECT);
}
}
}
getOptions() {
const optionTags = [];
const { options, placeholder, column, withoutEmptyOption } = this.props;
if (!withoutEmptyOption) {
optionTags.push((
<option key="-1" value="">{ placeholder || `Select ${column.text}...` }</option>
));
}
Object.keys(options).forEach(key =>
optionTags.push(<option key={ key } value={ key }>{ options[key] }</option>)
);
return optionTags;
}
cleanFiltered() {
const value = (this.props.defaultValue !== undefined) ? this.props.defaultValue : '';
this.setState(() => ({ isSelected: value !== '' }));
this.selectInput.value = value;
this.props.onFilter(this.props.column, value, FILTER_TYPE.SELECT);
}
applyFilter(value) {
this.selectInput.value = value;
this.setState(() => ({ isSelected: value !== '' }));
this.props.onFilter(this.props.column, value, FILTER_TYPE.SELECT);
}
filter(e) {
const { value } = e.target;
this.setState(() => ({ isSelected: value !== '' }));
this.props.onFilter(this.props.column, value, FILTER_TYPE.SELECT);
}
render() {
const {
style,
className,
defaultValue,
onFilter,
column,
options,
comparator,
withoutEmptyOption,
caseSensitive,
...rest
} = this.props;
const selectClass =
`filter select-filter form-control ${className} ${this.state.isSelected ? '' : 'placeholder-selected'}`;
return (
<select
{ ...rest }
ref={ n => this.selectInput = n }
style={ style }
className={ selectClass }
onChange={ this.filter }
defaultValue={ defaultValue !== undefined ? defaultValue : '' }
>
{ this.getOptions() }
</select>
);
}
}
SelectFilter.propTypes = {
onFilter: PropTypes.func.isRequired,
column: PropTypes.object.isRequired,
options: PropTypes.object.isRequired,
comparator: PropTypes.oneOf([LIKE, EQ]),
placeholder: PropTypes.string,
style: PropTypes.object,
className: PropTypes.string,
withoutEmptyOption: PropTypes.bool,
defaultValue: PropTypes.any,
caseSensitive: PropTypes.bool
};
SelectFilter.defaultProps = {
defaultValue: '',
className: '',
withoutEmptyOption: false,
comparator: EQ,
caseSensitive: true
};
export default SelectFilter;

View File

@@ -69,7 +69,16 @@ class TextFilter extends Component {
} }
render() { render() {
const { placeholder, column: { text }, style, className, onFilter, ...rest } = this.props; const {
placeholder,
column: { text },
style,
className,
onFilter,
caseSensitive,
defaultValue,
...rest
} = this.props;
// 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 <input
@@ -95,12 +104,14 @@ TextFilter.propTypes = {
delay: PropTypes.number, delay: PropTypes.number,
placeholder: PropTypes.string, placeholder: PropTypes.string,
style: PropTypes.object, style: PropTypes.object,
className: PropTypes.string className: PropTypes.string,
caseSensitive: PropTypes.bool
}; };
TextFilter.defaultProps = { TextFilter.defaultProps = {
delay: FILTER_DELAY, delay: FILTER_DELAY,
defaultValue: '' defaultValue: '',
caseSensitive: false
}; };

View File

@@ -1,5 +1,7 @@
export const FILTER_TYPE = { export const FILTER_TYPE = {
TEXT: 'TEXT' TEXT: 'TEXT',
SELECT: 'SELECT',
NUMBER: 'NUMBER'
}; };
export const FILTER_DELAY = 500; export const FILTER_DELAY = 500;

View File

@@ -1,10 +1,12 @@
/* eslint eqeqeq: 0 */
/* eslint no-console: 0 */
import { FILTER_TYPE } from './const'; import { FILTER_TYPE } from './const';
import { LIKE, EQ } from './comparison'; import { LIKE, EQ, NE, GT, GE, LT, LE } from './comparison';
export const filterByText = _ => ( export const filterByText = _ => (
data, data,
dataField, dataField,
{ filterVal, comparator = LIKE }, { filterVal = '', comparator = LIKE, caseSensitive },
customFilterValue customFilterValue
) => ) =>
data.filter((row) => { data.filter((row) => {
@@ -16,15 +18,81 @@ export const filterByText = _ => (
if (comparator === EQ) { if (comparator === EQ) {
return cellStr === filterVal; return cellStr === filterVal;
} }
return cellStr.indexOf(filterVal) > -1; if (caseSensitive) {
return cellStr.includes(filterVal);
}
return cellStr.toLocaleUpperCase().includes(filterVal.toLocaleUpperCase());
});
export const filterByNumber = _ => (
data,
dataField,
{ filterVal: { comparator, number } },
customFilterValue
) =>
data.filter((row) => {
if (number === '' || !comparator) return true;
let valid = true;
let cell = _.get(row, dataField);
if (customFilterValue) {
cell = customFilterValue(cell, row);
}
switch (comparator) {
case EQ: {
if (cell != number) {
valid = false;
}
break;
}
case GT: {
if (cell <= number) {
valid = false;
}
break;
}
case GE: {
if (cell < number) {
valid = false;
}
break;
}
case LT: {
if (cell >= number) {
valid = false;
}
break;
}
case LE: {
if (cell > number) {
valid = false;
}
break;
}
case NE: {
if (cell == number) {
valid = false;
}
break;
}
default: {
console.error('Number comparator provided is not supported');
break;
}
}
return valid;
}); });
export const filterFactory = _ => (filterType) => { export const filterFactory = _ => (filterType) => {
let filterFn; let filterFn;
switch (filterType) { switch (filterType) {
case FILTER_TYPE.TEXT: case FILTER_TYPE.TEXT:
case FILTER_TYPE.SELECT:
filterFn = filterByText(_); filterFn = filterByText(_);
break; break;
case FILTER_TYPE.NUMBER:
filterFn = filterByNumber(_);
break;
default: default:
filterFn = filterByText(_); filterFn = filterByText(_);
} }

View File

@@ -3,7 +3,8 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { filters } from './filter'; import { filters } from './filter';
import { LIKE } from './comparison'; import { LIKE, EQ } from './comparison';
import { FILTER_TYPE } from './const';
export default (Base, { export default (Base, {
_, _,
@@ -23,11 +24,14 @@ export default (Base, {
componentWillReceiveProps({ isDataChanged, store, columns }) { componentWillReceiveProps({ isDataChanged, store, columns }) {
// consider to use lodash.isEqual // consider to use lodash.isEqual
if (JSON.stringify(this.state.currFilters) !== JSON.stringify(store.filters)) { const isRemoteFilter = this.isRemoteFiltering() || this.isRemotePagination();
if (isRemoteFilter ||
JSON.stringify(this.state.currFilters) !== JSON.stringify(store.filters)) {
// I think this condition only isRemoteFilter is enough
store.filteredData = store.getAllData();
this.setState(() => ({ isDataChanged: true, currFilters: store.filters })); this.setState(() => ({ isDataChanged: true, currFilters: store.filters }));
} else if (isDataChanged) { } else if (isDataChanged) {
if (!(this.isRemoteFiltering() || this.isRemotePagination()) && if (!isRemoteFilter && Object.keys(this.state.currFilters).length > 0) {
Object.keys(this.state.currFilters).length > 0) {
store.filteredData = filters(store, columns, _)(this.state.currFilters); store.filteredData = filters(store, columns, _)(this.state.currFilters);
} }
this.setState(() => ({ isDataChanged })); this.setState(() => ({ isDataChanged }));
@@ -44,8 +48,12 @@ export default (Base, {
if (!_.isDefined(filterVal) || filterVal === '') { if (!_.isDefined(filterVal) || filterVal === '') {
delete currFilters[dataField]; delete currFilters[dataField];
} else { } else {
const { comparator = LIKE } = filter.props; // select default comparator is EQ, others are LIKE
currFilters[dataField] = { filterVal, filterType, comparator }; const {
comparator = (filterType === FILTER_TYPE.SELECT ? EQ : LIKE),
caseSensitive = false
} = filter.props;
currFilters[dataField] = { filterVal, filterType, comparator, caseSensitive };
} }
store.filters = currFilters; store.filters = currFilters;

View File

@@ -0,0 +1,31 @@
.react-bootstrap-table > table > thead > tr > th .filter {
font-weight: normal;
}
.react-bootstrap-table > table > thead > tr > th .select-filter option[value=''],
.react-bootstrap-table > table > thead > tr > th .select-filter.placeholder-selected,
.react-bootstrap-table > table > thead > tr > th .filter::-webkit-input-placeholder,
.react-bootstrap-table > table > thead > tr > th .number-filter-input::-webkit-input-placeholder {
color: lightgrey;
font-style: italic;
}
.react-bootstrap-table > table > thead > tr > th .select-filter.placeholder-selected option:not([value='']) {
color: initial;
font-style: initial;
}
.react-bootstrap-table > table > thead > tr > th .number-filter {
display: flex;
}
.react-bootstrap-table > table > thead > tr > th .number-filter-input {
margin-left: 5px;
float: left;
width: calc(100% - 67px - 5px);
}
.react-bootstrap-table > table > thead > tr > th .number-filter-comparator {
width: 67px;
float: left;
}

View File

@@ -0,0 +1,310 @@
import 'jsdom-global/register';
import React from 'react';
import sinon from 'sinon';
import { mount } from 'enzyme';
import NumberFilter from '../../src/components/number';
import { FILTER_TYPE } from '../../src/const';
import * as Comparator from '../../src/comparison';
describe('Number Filter', () => {
let wrapper;
const onFilter = sinon.stub();
const column = {
dataField: 'price',
text: 'Product Price'
};
afterEach(() => {
onFilter.reset();
});
describe('initialization', () => {
beforeEach(() => {
wrapper = mount(
<NumberFilter onFilter={ onFilter } column={ column } />
);
});
it('should have correct state', () => {
expect(wrapper.state().isSelected).toBeFalsy();
});
it('should rendering component successfully', () => {
expect(wrapper).toHaveLength(1);
expect(wrapper.find('select')).toHaveLength(1);
expect(wrapper.find('input[type="number"]')).toHaveLength(1);
expect(wrapper.find('.number-filter')).toHaveLength(1);
});
it('should rendering comparator options correctly', () => {
const select = wrapper.find('select');
expect(select.find('option')).toHaveLength(wrapper.prop('comparators').length + 1);
});
});
describe('when withoutEmptyComparatorOption prop is true', () => {
beforeEach(() => {
wrapper = mount(
<NumberFilter onFilter={ onFilter } column={ column } withoutEmptyComparatorOption />
);
});
it('should rendering comparator options correctly', () => {
const select = wrapper.find('select');
expect(select.find('option')).toHaveLength(wrapper.prop('comparators').length);
});
});
describe('when defaultValue.number props is defined', () => {
const number = 203;
beforeEach(() => {
wrapper = mount(
<NumberFilter onFilter={ onFilter } column={ column } defaultValue={ { number } } />
);
});
it('should rendering input successfully', () => {
expect(wrapper).toHaveLength(1);
const input = wrapper.find('input[type="number"]');
expect(input).toHaveLength(1);
expect(input.props().defaultValue).toEqual(number);
});
});
describe('when defaultValue.comparator props is defined', () => {
const comparator = Comparator.EQ;
beforeEach(() => {
wrapper = mount(
<NumberFilter onFilter={ onFilter } column={ column } defaultValue={ { comparator } } />
);
});
it('should rendering comparator select successfully', () => {
expect(wrapper).toHaveLength(1);
const select = wrapper.find('.number-filter-comparator');
expect(select).toHaveLength(1);
expect(select.props().defaultValue).toEqual(comparator);
});
});
describe('when defaultValue.number and defaultValue.comparator props is defined', () => {
const number = 203;
const comparator = Comparator.EQ;
beforeEach(() => {
wrapper = mount(
<NumberFilter
onFilter={ onFilter }
column={ column }
defaultValue={ { number, comparator } }
/>
);
});
it('should have correct state', () => {
expect(wrapper.state().isSelected).toBeTruthy();
});
it('should calling onFilter on componentDidMount', () => {
expect(onFilter.calledOnce).toBeTruthy();
expect(onFilter.calledWith(
column, { number: `${number}`, comparator }, FILTER_TYPE.NUMBER)).toBeTruthy();
});
});
describe('when options props is defined', () => {
const options = [2100, 2103, 2105];
beforeEach(() => {
wrapper = mount(
<NumberFilter
onFilter={ onFilter }
column={ column }
options={ options }
/>
);
});
it('should rendering number options instead of number input', () => {
expect(wrapper).toHaveLength(1);
const select = wrapper.find('.select-filter.placeholder-selected');
expect(select).toHaveLength(1);
expect(select.find('option')).toHaveLength(options.length + 1);
});
describe('when withoutEmptyNumberOption props is defined', () => {
beforeEach(() => {
wrapper = mount(
<NumberFilter
onFilter={ onFilter }
column={ column }
options={ options }
withoutEmptyNumberOption
/>
);
});
it('should rendering number options instead of number input', () => {
const select = wrapper.find('.select-filter.placeholder-selected');
expect(select).toHaveLength(1);
expect(select.find('option')).toHaveLength(options.length);
});
});
describe('when defaultValue.number props is defined', () => {
const number = 203;
beforeEach(() => {
wrapper = mount(
<NumberFilter
onFilter={ onFilter }
column={ column }
defaultValue={ { number } }
options={ options }
/>
);
});
it('should rendering number options successfully', () => {
const select = wrapper.find('.select-filter.placeholder-selected');
expect(select).toHaveLength(1);
expect(select.props().defaultValue).toEqual(number);
});
});
describe('when defaultValue.number and defaultValue.comparator props is defined', () => {
const number = options[1];
const comparator = Comparator.EQ;
beforeEach(() => {
wrapper = mount(
<NumberFilter
onFilter={ onFilter }
column={ column }
defaultValue={ { number, comparator } }
options={ options }
/>
);
});
it('should rendering number options successfully', () => {
let select = wrapper.find('.placeholder-selected');
expect(select).toHaveLength(0);
select = wrapper.find('.select-filter');
expect(select).toHaveLength(1);
});
});
});
describe('when style props is defined', () => {
const style = { backgroundColor: 'red' };
beforeEach(() => {
wrapper = mount(
<NumberFilter
onFilter={ onFilter }
column={ column }
style={ style }
/>
);
});
it('should rendering component successfully', () => {
expect(wrapper).toHaveLength(1);
expect(wrapper.find('.number-filter').prop('style')).toEqual(style);
});
});
describe('when numberStyle props is defined', () => {
const numberStyle = { backgroundColor: 'red' };
beforeEach(() => {
wrapper = mount(
<NumberFilter
onFilter={ onFilter }
column={ column }
numberStyle={ numberStyle }
/>
);
});
it('should rendering component successfully', () => {
expect(wrapper).toHaveLength(1);
expect(wrapper.find('.number-filter-input').prop('style')).toEqual(numberStyle);
});
});
describe('when comparatorStyle props is defined', () => {
const comparatorStyle = { backgroundColor: 'red' };
beforeEach(() => {
wrapper = mount(
<NumberFilter
onFilter={ onFilter }
column={ column }
comparatorStyle={ comparatorStyle }
/>
);
});
it('should rendering component successfully', () => {
expect(wrapper).toHaveLength(1);
expect(wrapper.find('select').prop('style')).toEqual(comparatorStyle);
});
});
describe('when className props is defined', () => {
const className = 'test';
beforeEach(() => {
wrapper = mount(
<NumberFilter
onFilter={ onFilter }
column={ column }
className={ className }
/>
);
});
it('should rendering component successfully', () => {
expect(wrapper).toHaveLength(1);
expect(wrapper.hasClass(className)).toBeTruthy();
});
});
describe('when numberClassName props is defined', () => {
const className = 'test';
beforeEach(() => {
wrapper = mount(
<NumberFilter
onFilter={ onFilter }
column={ column }
numberClassName={ className }
/>
);
});
it('should rendering component successfully', () => {
expect(wrapper).toHaveLength(1);
expect(wrapper.find('.number-filter-input').prop('className').indexOf(className) > -1).toBeTruthy();
});
});
describe('when comparatorClassName props is defined', () => {
const className = 'test';
beforeEach(() => {
wrapper = mount(
<NumberFilter
onFilter={ onFilter }
column={ column }
comparatorClassName={ className }
/>
);
});
it('should rendering component successfully', () => {
expect(wrapper).toHaveLength(1);
expect(wrapper.find('select').prop('className').indexOf(className) > -1).toBeTruthy();
});
});
});

View File

@@ -0,0 +1,296 @@
import 'jsdom-global/register';
import React from 'react';
import sinon from 'sinon';
import { mount } from 'enzyme';
import SelectFilter from '../../src/components/select';
import { FILTER_TYPE } from '../../src/const';
describe('Select Filter', () => {
let wrapper;
let instance;
const onFilter = sinon.stub();
const column = {
dataField: 'quality',
text: 'Product Quality'
};
const options = {
0: 'Bad',
1: 'Good',
2: 'Unknow'
};
afterEach(() => {
onFilter.reset();
});
describe('initialization', () => {
beforeEach(() => {
wrapper = mount(
<SelectFilter onFilter={ onFilter } column={ column } options={ options } />
);
instance = wrapper.instance();
});
it('should have correct state', () => {
expect(instance.state.isSelected).toBeFalsy();
});
it('should rendering component successfully', () => {
expect(wrapper).toHaveLength(1);
expect(wrapper.find('select')).toHaveLength(1);
expect(wrapper.find('.select-filter')).toHaveLength(1);
expect(wrapper.find('.placeholder-selected')).toHaveLength(1);
});
it('should rendering select options correctly', () => {
const select = wrapper.find('select');
expect(select.find('option')).toHaveLength(Object.keys(options).length + 1);
expect(select.childAt(0).text()).toEqual(`Select ${column.text}...`);
Object.keys(options).forEach((key, i) => {
expect(select.childAt(i + 1).prop('value')).toEqual(key);
expect(select.childAt(i + 1).text()).toEqual(options[key]);
});
});
});
describe('when defaultValue is defined', () => {
let defaultValue;
describe('and it is valid', () => {
beforeEach(() => {
defaultValue = '0';
wrapper = mount(
<SelectFilter
onFilter={ onFilter }
column={ column }
options={ options }
defaultValue={ defaultValue }
/>
);
instance = wrapper.instance();
});
it('should have correct state', () => {
expect(instance.state.isSelected).toBeTruthy();
});
it('should rendering component successfully', () => {
expect(wrapper).toHaveLength(1);
expect(wrapper.find('.placeholder-selected')).toHaveLength(0);
});
it('should calling onFilter on componentDidMount', () => {
expect(onFilter.calledOnce).toBeTruthy();
expect(onFilter.calledWith(column, defaultValue, FILTER_TYPE.SELECT)).toBeTruthy();
});
});
});
describe('when placeholder is defined', () => {
const placeholder = 'test';
beforeEach(() => {
wrapper = mount(
<SelectFilter
onFilter={ onFilter }
column={ column }
options={ options }
placeholder={ placeholder }
/>
);
instance = wrapper.instance();
});
it('should rendering component successfully', () => {
expect(wrapper).toHaveLength(1);
const select = wrapper.find('select');
expect(select.childAt(0).text()).toEqual(placeholder);
});
});
describe('when style is defined', () => {
const style = { backgroundColor: 'red' };
beforeEach(() => {
wrapper = mount(
<SelectFilter
onFilter={ onFilter }
column={ column }
options={ options }
style={ style }
/>
);
});
it('should rendering component successfully', () => {
expect(wrapper).toHaveLength(1);
expect(wrapper.find('select').prop('style')).toEqual(style);
});
});
describe('when withoutEmptyOption is defined', () => {
beforeEach(() => {
wrapper = mount(
<SelectFilter
onFilter={ onFilter }
column={ column }
options={ options }
withoutEmptyOption
/>
);
});
it('should rendering select without default empty option', () => {
const select = wrapper.find('select');
expect(select.find('option')).toHaveLength(Object.keys(options).length);
});
});
describe('componentDidUpdate', () => {
let prevProps;
describe('when props.defaultValue is diff from prevProps.defaultValue', () => {
beforeEach(() => {
wrapper = mount(
<SelectFilter
onFilter={ onFilter }
column={ column }
options={ options }
defaultValue="0"
/>
);
prevProps = {
column,
options,
defaultValue: '1'
};
instance = wrapper.instance();
instance.componentDidUpdate(prevProps);
});
it('should update', () => {
expect(onFilter.callCount).toBe(2);
expect(onFilter.calledWith(
column, instance.props.defaultValue, FILTER_TYPE.SELECT)).toBeTruthy();
});
});
describe('when props.options is diff from prevProps.options', () => {
beforeEach(() => {
wrapper = mount(
<SelectFilter
onFilter={ onFilter }
column={ column }
options={ {
...options,
3: 'Best'
} }
defaultValue="1"
/>
);
prevProps = {
column,
options
};
instance = wrapper.instance();
instance.componentDidUpdate(prevProps);
});
it('should update', () => {
expect(onFilter.callCount).toBe(2);
expect(onFilter.calledWith(
column, instance.props.defaultValue, FILTER_TYPE.SELECT)).toBeTruthy();
});
});
});
describe('cleanFiltered', () => {
describe('when props.defaultValue is defined', () => {
const defaultValue = '0';
beforeEach(() => {
wrapper = mount(
<SelectFilter
onFilter={ onFilter }
column={ column }
options={ options }
defaultValue={ defaultValue }
/>
);
instance = wrapper.instance();
instance.cleanFiltered();
});
it('should setting state correctly', () => {
expect(instance.state.isSelected).toBeTruthy();
});
it('should calling onFilter correctly', () => {
expect(onFilter.callCount).toBe(2);
expect(onFilter.calledWith(column, defaultValue, FILTER_TYPE.SELECT)).toBeTruthy();
});
});
describe('when props.defaultValue is not defined', () => {
beforeEach(() => {
wrapper = mount(
<SelectFilter
onFilter={ onFilter }
column={ column }
options={ options }
/>
);
instance = wrapper.instance();
instance.cleanFiltered();
});
it('should setting state correctly', () => {
expect(instance.state.isSelected).toBeFalsy();
});
it('should calling onFilter correctly', () => {
expect(onFilter.callCount).toBe(1);
});
});
});
describe('applyFilter', () => {
const value = '2';
beforeEach(() => {
wrapper = mount(
<SelectFilter onFilter={ onFilter } column={ column } options={ options } />
);
instance = wrapper.instance();
instance.applyFilter(value);
});
it('should setting state correctly', () => {
expect(instance.state.isSelected).toBeTruthy();
});
it('should calling onFilter correctly', () => {
expect(onFilter.callCount).toBe(1);
expect(onFilter.calledWith(column, value, FILTER_TYPE.SELECT)).toBeTruthy();
});
});
describe('filter', () => {
const event = { target: { value: 'tester' } };
beforeEach(() => {
wrapper = mount(
<SelectFilter onFilter={ onFilter } column={ column } options={ options } />
);
instance = wrapper.instance();
instance.filter(event);
});
it('should setting state correctly', () => {
expect(instance.state.isSelected).toBeTruthy();
});
it('should calling onFilter correctly', () => {
expect(onFilter.callCount).toBe(1);
expect(onFilter.calledWith(column, event.target.value, FILTER_TYPE.SELECT)).toBeTruthy();
});
});
});

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