merge 0.1.0 code base

Develop -> Master (Not Version Bump)
This commit is contained in:
Allen 2018-01-22 00:04:09 +08:00 committed by GitHub
commit 3c9cd22d42
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
209 changed files with 27659 additions and 26 deletions

3
.babelrc Normal file
View File

@ -0,0 +1,3 @@
{
"presets": ["react", "es2015", "stage-0"]
}

27
.eslintrc Normal file
View File

@ -0,0 +1,27 @@
{
"extends": "airbnb",
"parser": "babel-eslint",
"env": {
"browser": true,
"jest": true,
"node": true
},
"plugins": [
"react"
],
"rules": {
"comma-dangle": ["error", "never"],
"react/jsx-curly-spacing": [2, "always"],
"react/forbid-prop-types": 0,
"react/jsx-filename-extension": 0,
"react/jsx-space-before-closing": 0,
"react/jsx-tag-spacing": ["error", { "beforeSelfClosing": "always" }],
"import/extensions": 0, // skip import extensions
"import/no-unresolved": [0, { "ignore": ["^react-bootstrap-table"] }], // monorepo setup
"import/prefer-default-export": 0,
"import/no-extraneous-dependencies": 0
},
"globals": {
"jest": false
}
}

25
.gitignore vendored
View File

@ -1 +1,24 @@
node_modules
# node
node_modules
package-lock.json
# testing
coverage
.eslintcache
# misc
.DS_Store
.vscode
# logs
lerna-debug.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# gh-pages
storybook-static
# build
lib
dist

7
.npmignore Normal file
View File

@ -0,0 +1,7 @@
node_modules
.DS_Store
*~
*.sublime-project
*.sublime-workspace
*.idea
*.iml

20
.travis.yml Normal file
View File

@ -0,0 +1,20 @@
language: node_js
node_js:
- "7"
- "6"
cache:
yarn: true
branches:
only:
# skip master branch when it's under development phase
# - master
- develop
before_install:
- curl -o- -L https://yarnpkg.com/install.sh | bash -s
- export PATH="$HOME/.yarn/bin:$PATH"
install: yarn install

22
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,22 @@
# Contributing
# Issues
Before opening an issue, please make sure your problem or request doesn't exist. When opening an issue, please provide the following information if possible:
* Example code or repo (please keep it simple and minimal)
* Steps to reproduce.
* `react-bootstrap-table2` version.
Additionally, asking questions and requesting new features are welcomed via [issue tracker](https://github.com/react-bootstrap-table/react-bootstrap-table2/issues).
# Pull Requests
Check [here](./docs/development.md) for getting started with development.
* 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.
* 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.
# For the members of react-bootstrap-table2 org
* Please convert the ticket to issue when the ticket has moved from `Backlog` to `Ready`.
* Please update the docs if any API, feature or component props was changed or added. The code and docs should always be in sync.
* Please add a story example if any new feature was implemented.

View File

@ -1,25 +1,46 @@
# react-bootstrap-table2
Rebuilt [react-bootstrap-table](https://github.com/AllenFang/react-bootstrap-table)
## The problems/features I want to solve
* Performance
* Fully compatiable with bootstrap 3 and 4(`react-bootstrap-table@4.0.0` already done)
* Clean Code and Testing
* Decrease the size of bundled file
* **Split module/functionality from core module, make core module more lightweight**
* Use [`storybook`](https://github.com/storybooks/storybook) to build examples
* Support the aggregation(summary) view
* Support the table footer
* Support column/row span on header and body
* Support sticky header
* Support table section([react-bootstrap-table#721](https://github.com/AllenFang/react-bootstrap-table/pull/721))
* Handle events well
* Fix unalign issues
* Make **stateless** table more easy to use(`react-bootstrap-table` alread have `remote` mode but have some bugs)
* Customizable table
* Support the nested data([react-bootstrap-table#50](https://github.com/AllenFang/react-bootstrap-table/issues/50◊))
* Consider to support column resize
* Consider to make animation on `react-bootstrap-table2` more easy
> `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 ;(
## The feature may lost on react-bootstrap-table
* Have a great chance that I don't support the vertical scrollbar on table
`react-bootstrap-table2` separate some functionalities from core modules to other modules like following:
* [`react-bootstrap-table2-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-z-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 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
See [getting started](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/getting-started.html).
## Online Demo
See `react-bootstrap-table2` [storybook](https://react-bootstrap-table.github.io/react-bootstrap-table2/storybook/index.html).
## Roadmap
See [release plans](https://react-bootstrap-table.github.io/react-bootstrap-table2/blog/2018/01/24/release-plan.html).
## Development
Please check [development guide](./docs/development.md).
## 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)**

277
docs/README.md Normal file
View File

@ -0,0 +1,277 @@
# Documentation
## BootstrapTable Props
#### Required
* [keyField (**required**)](#keyField)
* [data (**required**)](#data)
* [columns (**required**)](#columns)
#### Optional
* [remote](#remote)
* [loading](#loading)
* [caption](#caption)
* [striped](#striped)
* [bordered](#bordered)
* [hover](#hover)
* [condensed](#condensed)
* [cellEdit](#cellEdit)
* [selectRow](#selectRow)
* [rowStyle](#rowStyle)
* [rowClasses](#rowClasses)
* [rowEvents](#rowEvents)
* [defaultSorted](#defaultSorted)
* [pagination](#pagination)
* [filter](#filter)
* [onTableChange](#onTableChange)
### <a name='keyField'>keyField(**required**) - [String]</a>
Tells `react-bootstrap-table2` which column is unique.
### <a name='data'>data(**required**) - [Array]</a>
Provides data for your table. It accepts a single Array object.
### <a name='columns'>columns(**required**) - [Object]</a>
Accepts a single Array object, please see [columns definition](./columns.md) for more detail.
### <a name='remote'>remote - [Bool | Object]</a>
Default is `false`, if enable`remote`, you are suppose to handle all the table change events, like: pagination, insert, filtering etc.
This is a chance that you can connect to your remote server or database to manipulate your data.
For flexibility reason, you can control what functionality should be handled on remote via a object return:
```js
remote={ {
filter: true,
pagination: true,
filter: true,
sort: true,
cellEdit: true
} }
```
In above case, only column filter will be handled on remote.
> Note: when remote is enable, you are suppose to give [`onTableChange`](#onTableChange) prop on `BootstrapTable`
> It's the only way to communicate to your remote server and update table states.
A special case for remote pagination:
```js
remote={ { pagination: true, filter: false, sort: false } }
```
There is a apecial case for remote pagination, even you only specified the paignation need to handle as remote, `react-bootstrap-table2` will handle all the table changes(filter, sort etc) as remote mode, because `react-bootstrap-table2` only know the data of current page, but filtering, searching or sort need to work on overall datas.
### <a name='loading'>loading - [Bool]</a>
Telling if table is loading or not, for example: waiting data loading, filtering etc. It's **only** valid when [`remote`](#remote) is enabled.
When `loading` is `true`, `react-bootstrap-table2` will attend to render a overlay on table via [`overlay`](#overlay) prop, if [`overlay`](#overlay) prop is not given, `react-bootstrap-table2` will ignore the overlay rendering.
### <a name='overlay'>overlay - [Function]</a>
`overlay` accept a factory funtion which should returning a higher order component. By default, `react-bootstrap-table2-overlay` can be a good option for you:
```sh
$ npm install react-bootstrap-table2-overlay
```
```js
import overlayFactory from 'react-bootstrap-table2-overlay';
<BootstrapTable
data={ data }
columns={ columns }
loading={ true } //only loading is true, react-bootstrap-table will render overlay
overlay={ overlayFactory() }
/>
```
Actually, `react-bootstrap-table-overlay` is depends on [`react-loading-overlay`](https://github.com/derrickpelletier/react-loading-overlay) and `overlayFactory` just a factory function and you can pass any props which available for `react-loading-overlay`:
```js
overlay={ overlayFactory({ spinner: true, background: 'rgba(192,192,192,0.3)' }) }
```
### <a name='caption'>caption - [String | Node]</a>
Same as HTML [caption tag](https://www.w3schools.com/TAgs/tag_caption.asp), you can set it as String or a React JSX.
### <a name='striped'>striped - [Bool]</a>
Same as bootstrap `.table-striped` class for adding zebra-stripes to a table.
### <a name='bordered'>bordered - [Bool]</a>
Same as bootstrap `.table-bordered` class for adding borders to a table and table cells.
### <a name='hover'>hover - [Bool]</a>
Same as bootstrap `.table-hover` class for adding mouse hover effect (grey background color) on table rows.
### <a name='condensed'>condensed - [Bool]</a>
Same as bootstrap `.table-condensed` class for making a table more compact by cutting cell padding in half.
### <a name='cellEdit'>cellEdit - [Object]</a>
Makes table cells editable, please see [cellEdit definition](./cell-edit.md) for more detail.
### <a name='selectRow'>selectRow - [Object]</a>
Makes table rows selectable, please see [selectRow definition](./row-selection.md) for more detail.
### <a name='rowStyle'>rowStyle = [Object | Function]</a>
Custom the style of table rows:
```js
<BootstrapTable data={ data } columns={ columns } rowStyle={ { backgroundColor: 'red' } } />
```
This prop also accept a callback function for flexible to custom row style:
```js
const rowStyle = (row, rowIndex) => {
return { ... };
};
<BootstrapTable data={ data } columns={ columns } rowStyle={ rowStyle } />
```
### <a name='rowClasses'>rowClasses = [String | Function]</a>
Custom the style of table rows:
```js
<BootstrapTable data={ data } columns={ columns } rowClasses="custom-row-class" />
```
This prop also accept a callback function for flexible to custom row style:
```js
const rowClasses = (row, rowIndex) => {
return 'custom-row-class';
};
<BootstrapTable data={ data } columns={ columns } rowClasses={ rowClasses } />
```
### <a name='rowEvents'>rowEvents - [Object]</a>
Custom the events on row:
```js
const rowEvents = {
onClick: (e) => {
....
}
};
<BootstrapTable data={ data } columns={ columns } rowEvents={ rowEvents } />
```
### <a name='defaultSorted'>defaultSorted - [Array]</a>
`defaultSorted` accept an object array which allow you to define the default sort columns when first render.
```js
const defaultSorted = [{
dataField: 'name', // if dataField is not match to any column you defined, it will be ignored.
order: 'desc' // desc or asc
}];
```
### <a name='pagination'>pagination - [Object]</a>
`pagination` allow user to render a pagination panel on the bottom of table. But pagination funcitonality is separated from core of `react-bootstrap-table2` so that you are suppose to install `react-bootstrap-table2-paginator` additionaly.
```sh
$ npm install react-bootstrap-table2-paginator --save
```
After installation of `react-bootstrap-table2-paginator`, you can enable pagination on `react-bootstrap-table2` easily:
```js
import paginator from 'react-bootstrap-table2-paginator';
// omit...
<BootstrapTable data={ data } columns={ columns } pagination={ paginator() } />
```
`paginator` is a function actually and allow to pass some pagination options, following we list all the available options:
```js
paginator({
page, // Specify the current page. It's necessary when remote is enabled
sizePerPage, // Specify the size per page. It's necessary when remote is enabled
totalSize, // Total data size. It's necessary when remote is enabled
pageStartIndex: 0, // first page will be 0, default is 1
paginationSize: 3, // the pagination bar size, default is 5
sizePerPageList: [ {
text: '5', value: 5
}, {
text: '10', value: 10
}, {
text: 'All', value: products.length
} ], // A numeric array is also available: [5, 10]. the purpose of above example is custom the text
withFirstAndLast: false, // hide the going to first and last page button
alwaysShowAllBtns: true, // always show the next and previous page button
firstPageText: 'First', // the text of first page button
prePageText: 'Prev', // the text of previous page button
nextPageText: 'Next', // the text of next page button
lastPageText: 'Last', // the text of last page button
nextPageTitle: 'Go to next', // the title of next page button
prePageTitle: 'Go to previous', // the title of previous page button
firstPageTitle: 'Go to first', // the title of first page button
lastPageTitle: 'Go to last', // the title of last page button
hideSizePerPage: true, // hide the size per page dorpdown
hidePageListOnlyOnePage: true, // hide pagination bar when only one page, default is false
onPageChange: (page, sizePerPage) => {}, // callback function when page was changing
onSizePerPageChange: (sizePerPage, page) => {}, // callback function when page size was changing
})
```
### <a name='filter'>filter - [Object]</a>
`filter` allow user to filter data by column. However, filter funcitonality is separated from core of `react-bootstrap-table2` so that you are suppose to install `react-bootstrap-table2-filter` firstly.
```sh
$ npm install react-bootstrap-table2-filter --save
```
After installation of `react-bootstrap-table2-filter`, you can configure filter on `react-bootstrap-table2` easily:
```js
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
// omit...
const columns = [ {
dataField: 'id',
text: 'Production ID'
}, {
dataField: 'name',
text: 'Production Name',
filter: textFilter() // apply text filter
}, {
dataField: 'price',
text: 'Production Price'
} ];
<BootstrapTable data={ data } columns={ columns } filter={ filterFactory() } />
```
### <a name='onTableChange'>onTableChange - [Function]</a>
This callback function will be called when [`remote`](#remote) enabled only.
```js
const onTableChange = (type, newState) => {
// handle any data change here
}
<BootstrapTable data={ data } columns={ columns } onTableChange={ onTableChange } />
```
There's only two arguments will be passed to `onTableChange`: `type` and `newState`:
`type` is tell you what kind of functionality to trigger this table's change: available values at the below:
* `filter`
* `pagination`
* `sort`
* `cellEdit`
Following is a shape of `newState`
```js
{
page, // newest page
sizePerPage, // newest sizePerPage
sortField, // newest sort field
sortOrder, // newest sort order
filters, // an object which have current filter status per column
data, // when you enable remote sort, you may need to base on data to sort if data is filtered/searched
cellEdit: { // You can only see this prop when type is cellEdit
rowId,
dataField,
newValue
}
}
```

74
docs/cell-edit.md Normal file
View File

@ -0,0 +1,74 @@
# Cell Editing
Before start to use cell edit, please remember to install `react-bootstrap-table2-editor`
```sh
$ npm install react-bootstrap-table2-editor --save
```
# Properties on cellEdit prop
* [mode (**required**)](#mode)
* [blurToSave](#blurToSave)
* [nonEditableRows](#nonEditableRows)
* [timeToCloseMessage](#timeToCloseMessage)
* [beforeSaveCell](#beforeSaveCell)
* [afterSaveCell](#afterSaveCell)
* [errorMessage](#errorMessage)
* [onErrorMessageDisappear](#onErrorMessageDisappear)
## <a name='cellEdit'>cellEdit - [Object]</a>
Assign a valid `cellEdit` object can enable the cell editing on the cell. The default usage is click/dbclick to trigger cell editing and press `ENTER` to save cell or press `ESC` to cancel editing.
> Note: The `keyField` column can't be edited
Following is the shape of `cellEdit` object:
```js
{
mode: 'click',
blurToSave: true,
timeToCloseMessage: 2500,
errorMessage: '',
beforeSaveCell: (oldValue, newValue, row, column) => { ... },
afterSaveCell: (oldValue, newValue, row, column) => { ... },
onErrorMessageDisappear: () => { ... },
nonEditableRows: () => { ... }
}
```
### <a name='mode'>cellEdit.mode - [String]</a>
`cellEdit.mode` possible value is `click` and `dbclick`. **It's required value** that tell `react-bootstrap-table2` how to trigger the cell editing.
### <a name='blurToSave'>cellEdit.blurToSave - [Bool]</a>
Default is `false`, enable it will be able to save the cell automatically when blur from the cell editor.
### <a name='nonEditableRows'>cellEdit.nonEditableRows - [Function]</a>
`cellEdit.nonEditableRows` accept a callback function and expect return an array which used to restrict all the columns of some rows as non-editable. So the each item in return array should be rowkey(`keyField`)
### <a name='timeToCloseMessage'>cellEdit.timeToCloseMessage - [Function]</a>
If a [`column.validator`](./columns.md#validator) defined and the new value is invalid, `react-bootstrap-table2` will popup a alert at the bottom of editor. `cellEdit.timeToCloseMessage` is a chance to let you decide how long the alert should be stay. Default is 3000 millisecond.
### <a name='beforeSaveCell'>cellEdit.beforeSaveCell - [Function]</a>
This callback function will be called before triggering cell update.
```js
const cellEdit = {
// omit...
beforeSaveCell: (oldValue, newValue, row, column) => { ... }
}
```
### <a name='afterSaveCell'>cellEdit.afterSaveCell - [Function]</a>
This callback function will be called after updating cell.
```js
const cellEdit = {
// omit...
afterSaveCell: (oldValue, newValue, row, column) => { ... }
};
```
### <a name='errorMessage'>cellEdit.errorMessage - [String]</a>
This prop is not often used. Only used when you want to keep the error message in your application state and also handle the cell editing on remote mode.
### <a name='onErrorMessageDisappear'>cellEdit.onErrorMessageDisappear - [Function]</a>
This callback function will be called when error message discard so that you can sync the newest error message to your state if you have.

580
docs/columns.md Normal file
View File

@ -0,0 +1,580 @@
# Definition of columns props on BootstrapTable
Available properties in a column object:
#### Required
* [dataField (**required**)](#dataField)
* [text (**required**)](#text)
#### Optional
* [hidden](#hidden)
* [formatter](#formatter)
* [formatExtraData](#formatExtraData)
* [sort](#sort)
* [sortFunc](#sortFunc)
* [classes](#classes)
* [style](#style)
* [title](#title)
* [events](#events)
* [align](#align)
* [attrs](#attrs)
* [headerFormatter](#headerFormatter)
* [headerClasses](#headerClasses)
* [headerStyle](#headerStyle)
* [headerTitle](#headerTitle)
* [headerEvents](#headerEvents)
* [headerAlign](#headerAlign)
* [headerAttrs](#headerAttrs)
* [headerSortingClasses](#headerSortingClasses)
* [headerSortingStyle](#headerSortingStyle)
* [editable](#editable)
* [validator](#validator)
* [editCellStyle](#editCellStyle)
* [editCellClasses](#editCellClasses)
* [filter](#filter)
* [filterValue](#filterValue)
Following is a most simplest and basic usage:
```js
const rows = [ { id: 1, name: '...', price: '102' } ];
const columns = [ {
dataField: 'id',
text: 'Production ID'
}, {
dataField: 'name',
text: 'Production Name'
}, {
dataField: 'price',
text: 'Production Price'
}
];
```
Let's introduce the definition of column object
## <a name='dataField'>column.dataField (**required**) - [String]</a>
Use `dataField` to specify what field should be apply on this column. If your raw data is nested, for example:
```js
const row = {
id: 'A001',
address: {
postal: '1234-12335',
city: 'Chicago'
}
}
```
You can use `dataField` with dot(`.`) to describe nested object:
```js
dataField: 'address.postal'
dataField: 'address.city'
```
## <a name='text'>column.text (**required**) - [String]</a>
`text` will be the column text in header column by default, if your header is not only text or you want to customize the header column, please check [`column.headerFormatter`](#headerFormatter)
## <a name='hidden'>column.hidden - [Bool]</a>
`hidden` allow you to hide column when `true` given.
## <a name='formatter'>column.formatter - [Function]</a>
`formatter` allow you to customize the table column and only accept a callback function which take four arguments and a JSX/String are expected for return.
* `cell`
* `row`
* `rowIndex`
* [`formatExtraData`](#formatExtraData)
## <a name='headerFormatter'>column.headerFormatter - [Function]</a>
`headerFormatter` allow you to customize the header column and only accept a callback function which take three arguments and a JSX/String are expected for return.
* `column`: current column object itself
* `colIndex`: index of current column
* `components`: an object which contain all of other react element, like sort caret or filter etc.
The third argument: `components` have following specified properties:
```js
{
sortElement, // sort caret element, it will not be undefined when you enable sort on this column
filterElement // filter element, it will not be undefined when you enable column.filter on this column
}
```
## <a name='formatExtraData'>column.formatExtraData - [Any]</a>
It's only used for [`column.formatter`](#formatter), you can define any value for it and will be passed as fourth argument for [`column.formatter`](#formatter) callback function.
## <a name='sort'>column.sort - [Bool]</a>
Enable the column sort via a `true` value given.
## <a name='sortFunc'>column.sortFunc - [Function]</a>
`column.sortFunc` only work when `column.sort` is enable. `sortFunc` allow you to define your sorting algorithm. This callback function accept four arguments:
```js
{
// omit...
sort: true,
sortFunc: (a, b, order, dataField) => {
if (order === 'asc') return a - b;
else return b - a;
}
}
```
> The possible value of `order` argument is **`asc`** and **`desc`**.
## <a name='classes'>column.classes - [String | Function]</a>
It's availabe to have custom class on table column:
```js
{
// omit...
classes: 'id-custom-cell'
}
```
In addition, `classes` also accept a callback function which have more power to custom the css class on each columns. This callback function take **4** arguments and a `String` is expected to return::
```js
{
classes: function callback(cell, row, rowIndex, colIndex) { ... }
}
```
**Parameters**
* `cell`: The value of current cell.
* `row`: The value of `row` being processed in the `BootstrapTable`.
* `rowIndex`: The index of the current `row` being processed in the `BootstrapTable`.
* `colIndex`: The index of the current `column` being processed in `BootstrapTable`.
**Return value**
A new `String` will be the result as element class.
## <a name='headerClasses'>column.headerClasses - [String | Function]</a>
It's similar to [`column.classes`](#classes), `headerClasses` is availabe to have customized class on table header column:
```js
{
// omit...
headerClasses: 'id-custom-cell'
}
```
Furthermore, it also accept a callback function which takes 2 arguments and a `String` is expect to return:
```js
{
headerClasses: function callback(column, colIndex) { ... }
}
```
**Parameters**
* `column`: The value of current column.
* `colIndex`: The index of the current `column` being processed in `BootstrapTable`.
**Return value**
A new `String` will be the result of element headerClasses.
## <a name='style'>column.style - [Object | Function]</a>
It's availabe to have custom style on table column:
```js
{
// omit...
style: { backgroundColor: 'green' }
}
```
In addition, similar to [`column.classes`](#classes), `style` also accept a callback function which have more power to customize the `inline style` on each columns. This callback function takes **4** arguments and an `Object` is expect to return:
```js
{
style: function callback(cell, row, rowIndex, colIndex) { ... }
}
```
**Parameters**
* `cell`: The value of current cell.
* `row`: The value of `row` being processed in the `BootstrapTable`.
* `rowIndex`: The index of the current `row` being processed in the `BootstrapTable`.
* `colIndex`: The index of the current `column` being processed in `BootstrapTable`.
**Return value**
A new `Object` will be the result of element style.
## <a name='headerStyle'>column.headerStyle - [Object | Function]</a>
It's availabe to have customized inline-style on table header column:
```js
{
// omit...
headerStyle: { backgroundColor: 'green' }
}
```
Moreover, it also accept a callback function which takes **2** arguments and an `Object` is expect to return:
```js
{
headerStyle: function callback(column, colIndex) { ... }
}
```
**Parameters**
* `column`: The value of current column.
* `colIndex`: The index of the current `column` being processed in `BootstrapTable`.
**Return value**
A new `Object` will be the result of element headerStyle.
## <a name='title'>column.title - [Bool | Function]</a>
`react-bootstrap-table2` is disable [`HTML title`](https://www.w3schools.com/tags/tag_title.asp) as default. You can assign `title` as `true` to enable the HTML title on table column and take `cell content` as default value. Additionally, you could customize title via a callback. It takes **4** arguments and a `String` is expect to return:
```js
{
// omit...
title: function callback(cell, row, rowIndex, colIndex) { ... }
// return custom title here
}
```
**Parameters**
* `cell`: The value of current cell.
* `row`: The value of `row` being processed in the `BootstrapTable`.
* `rowIndex`: The index of the current `row` being processed in the `BootstrapTable`.
* `colIndex`: The index of the current `column` being processed in `BootstrapTable`.
**Return value**
A new `String` will be the result of element title.
## <a name='headerTitle'>column.headerTitle - [Bool | Function]</a>
`headerTitle` is only for the title on header column, default is disable. The usage almost same as [`column.title`](#title),
```js
{
// omit...
headerTitle: true
}
```
It's also availabe to custom via a callback function:
```js
{
headerTitle: function callback(column, colIndex) { ... }
}
```
**Parameters**
* `column`: The value of current column.
* `colIndex`: The index of the current `column` being processed in `BootstrapTable`.
**Return value**
A new `String` will be the result of element headerTitle.
## <a name='align'>column.align - [String | Function]</a>
You can configure the [CSS text-align](https://www.w3schools.com/cssref/pr_text_text-align.asp) for table column by `align` property.
Besides, `align` also accept a callback function for dynamically setting text align. It takes **4** arguments and a `String` is expect to return:
```js
{
// omit...
align: function callback(cell, row, rowIndex, colIndex) { ... }
}
```
**Parameters**
* `cell`: The value of current cell.
* `row`: The value of `row` being processed in the `BootstrapTable`.
* `rowIndex`: The index of the current `row` being processed in the `BootstrapTable`.
* `colIndex`: The index of the current `column` being processed in `BootstrapTable`.
**Return value**
A new `String` will be the result of element text alignment.
## <a name='headerAlign'>column.headerAlign - [String | Function]</a>
It's almost same as [`column.align`](#align), but it's for the [CSS text-align](https://www.w3schools.com/cssref/pr_text_text-align.asp) on header column.
```js
{
// omit...
headerAlign: 'center'
}
```
Also, you can custom the align by a callback function:
```js
{
// omit...
headerAlign: (column, colIndex) => {
// column is an object and perform itself
// return custom title here
}
}
```
**Parameters**
* `column`: The value of current column.
* `colIndex`: The index of the current `column` being processed in `BootstrapTable`.
**Return value**
A new `String` will be the result of element headerAlign.
## <a name='events'>column.events - [Object]</a>
You can assign any [HTML Event](https://www.w3schools.com/tags/ref_eventattributes.asp) on table column via event property:
```js
{
// omit...
events: {
onClick: e => { ... }
}
}
```
## <a name='headerEvents'>column.headerEvents - [Object]</a>
`headerEvents` same as [`column.events`](#events) but this is for header column.
```js
{
// omit...
headerEvents: {
onClick: e => { ... }
}
}
```
## <a name='attrs'>column.attrs - [Object | Function]</a>
Via `attrs` property, You can customize table column [HTML attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes) which allow user to configure the elements or adjust their behavior.
```js
{
// omit...
attrs: {
title: 'bar',
'data-test': 'foo'
}
}
```
Not only `Object`, `callback function` is also acceptable. It takes `4` arguments and an `Object` is expect to return:
```js
{
attrs: function callback(cell, row, rowIndex, colIndex) { ... }
}
```
**Parameters**
* `cell`: The value of current cell.
* `row`: The value of `row` being processed in the `BootstrapTable`.
* `rowIndex`: The index of the current `row` being processed in the `BootstrapTable`.
* `colIndex`: The index of the current `column` being processed in `BootstrapTable`.
**Return value**
A new `Object` will be the result of element HTML attributes.
> Caution:
> If `column.classes`, `column.style`, `column.title`, `column.hidden` or `column.align` was given at the same time, property `attrs` has lower priorty and it will be overwrited.
```js
{
// omit...
title: true, // get higher priority
attrs: { title: 'test' }
}
```
## <a name='headerAttrs'>column.headerAttrs - [Object | Function]</a>
`headerAttrs` is similiar to [`column.attrs`](#attrs) but it works for header column.
```js
{
// omit...
headerAttrs: {
title: 'bar',
'data-test': 'foo'
}
}
```
Additionally, customize the header attributes by a **2** arguments callback function:
```js
{
// omit...
headerAttrs: (column, colIndex) => ({
// return customized HTML attribute here
})
}
```
**Parameters**
* `column`: The value of current column.
* `colIndex`: The index of the current `column` being processed in `BootstrapTable`.
**Return value**
A new `Object` will be the result of element headerAttrs.
> Caution:
> Same as [column.attrs](#attrs), it has lower priority and will be
> overwrited when other props related to HTML attributes were given.
### <a name='headerSortingClasses'>headerSortingClasses - [String | Function]</a>
`headerSortingClasses` allows to customize `class` for header cell when this column is sorting.
```js
const headerSortingClasses = 'demo-sorting';
```
Furthermore, it also accepts a callback which takes **4** arguments and `String` is expected to return:
```js
const headerSortingClasses = (column, sortOrder, isLastSorting, colIndex) => { ... }
```
* `column`: The value of current column.
* `sortOrder`: The order of current sorting
* `isLastSorting`: Is the last one of sorted columns.
* `colIndex`: The index of the current column being processed in BootstrapTable.
### <a name='headerSortingStyle'>headerSortingStyle - [Object | Function]</a>
It's similiar to [headerSortingClasses](#headerSortingClasses). It allows to customize the style of header cell when this column is sorting. A style `Object` and `callback` are acceptable. `callback` takes **4** arguments and an `Object` is expected to return:
```js
const sortingHeaderStyle = {
backgroundColor: 'red'
};
```
## <a name='editable'>column.editable - [Bool | Function]</a>
`column.editable` default is true, means every column is editable if you configure [`cellEdit`](./README.md#cellEdit). But you can disable some columns editable via setting `false`.
If a callback function given, you can control the editable level as cell level:
```js
{
// omit...
editable: (cell, row, rowIndex, colIndex) => {
// return true or false;
}
}
```
## <a name='validator'>column.validator - [Function]</a>
`column.validator` used for validate the data when cell on updating. it's should accept a callback function with following argument:
`newValue`, `row` and `column`:
```js
{
// omit...
validator: (newValue, row, column) => {
return ...;
}
}
```
The return value can be a bool or an object. If your valiation is pass, return `true` explicitly. If your valiation is invalid, return following object instead:
```js
{
valid: false,
message: 'SOME_REASON_HERE'
}
```
## <a name='editCellStyle'>column.editCellStyle - [Object | Function]</a>
You can use `column.editCellStyle` to custom the style of `<td>` when cell editing. It like most of customizable functionality, it also accept a callback function with following params:
**Parameters**
* `cell`: The value of current cell.
* `row`: The object of `row` being processed in the `BootstrapTable`.
* `rowIndex`: The index of the current `row` being processed in the `BootstrapTable`.
* `colIndex`: The index of the current `column` being processed in `BootstrapTable`.
```js
{
editCellStyle: { ... }
}
```
Or take a callback function
```js
{
editCellStyle: (cell, row, rowIndex, colIndex) => {
// it is suppose to return an object
}
}
```
## <a name='editCellClasses'>column.editCellClasses - [String | Function]</a>
You can use `column.editCellClasses` to add custom class on `<td>` when cell editing. It's same as [`column.editCellStyle`](#editCellStyle) which also accept a callback function to able to custom your class more flexible. Following is the arguments of this callback function: `cell`, `row`, `rowIndex`, `colIndex`.
```js
{
editCellClasses: 'custom-class'
}
```
Or take a callback function
```js
{
editCellClasses: (cell, row, rowIndex, colIndex) => {
// it is suppose to return a string
}
}
```
## <a name='filter'>column.filter - [Object]</a>
Configure `column.filter` will able to setup a column level filter on the header column. Currently, `react-bootstrap-table2` support following filters:
* Text(`textFilter`)
We have a quick example to show you how to use `column.filter`:
```
import { textFilter } from 'react-bootstrap-table2-filter';
// omit...
{
dataField: 'price',
text: 'Product Price',
filter: textFilter()
}
```
For some reason of simple customization, `react-bootstrap-table2` allow you to pass some props to filter factory function. Please check [here](https://github.com/react-bootstrap-table/react-bootstrap-table2/tree/master/packages/react-bootstrap-table2-filter/README.md) for more detail tutorial.
## <a name='filterValue'>column.filterValue - [Function]</a>
Sometimes, if the cell/column value that you don't want to filter on them, you can define `filterValue` to return a actual value you wanna be filterd:
**Parameters**
* `cell`: The value of current cell.
* `row`: The value of current row.
**Return value**
A final `String` value you want to be filtered.
```js
// omit...
{
dataField: 'price',
text: 'Product Price',
filter: textFilter(),
filterValue: (cell, row) => owners[cell]
}
```

28
docs/development.md Normal file
View File

@ -0,0 +1,28 @@
## Development Guide
### Setup
```bash
$ git clone https://github.com/react-bootstrap-table/react-bootstrap-table2.git
$ cd react-bootstrap-table
$ npm install
$ lerna bootstrap # ./node_modules/.bin/lerna bootstrap
```
### Development
```bash
$ npm run storybook
```
### Launch StoryBook
We use [storybook](https://storybook.js.org/) to list our examples and it also has hot reload from source code. Sometimes, it is also a good entry point to development.
```bash
$ cd packages/react-bootstrap-table2-example
$ npm run storybook
```
### Testing
```bash
$ npm test
$ npm run test:watch # for watch mode
$ npm run test:coverage # generate coverage report
```

116
docs/migration.md Normal file
View File

@ -0,0 +1,116 @@
# 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-table2-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
- [ ] 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
- [ ] Select Filter
- [ ] 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).

183
docs/row-selection.md Normal file
View File

@ -0,0 +1,183 @@
# Row selection
`react-bootstrap-table2` supports the row selection feature. By passing prop `selectRow` to enable row selection. When you enable this feature, `react-bootstrap-table2` will append a new selection column at first.
## Required
* [mode (**required**)](#mode)
## Optional
* [style](#style)
* [classes)](#classes)
* [bgColor](#bgColor)
* [nonSelectable)](#nonSelectable)
* [clickToSelect)](#clickToSelect)
* [clickToEdit](#clickToEdit)
* [onSelect](#onSelect)
* [onSelectAll](#onSelectAll)
* [hideSelectColumn](#hideSelectColumn)
### <a name="mode">selectRow.mode - [String]</a>
Specifying the selection way for `single(radio)` or `multiple(checkbox)`. If `radio` was assigned, there will be a radio button in the selection column; otherwise, the `checkbox` instead.
#### values
* **radio**
* **checkbox**
#### examples
```js
const selectRow = {
mode: 'radio' // single row selection
};
<BootstrapTable
keyField='id'
data={ products }
columns={ columns }
selectRow={ selectRowProp }
/>
```
```js
const selectRow = {
mode: 'checkbox' // multiple row selection
};
<BootstrapTable
keyField='id'
data={ products }
columns={ columns }
selectRow={ selectRowProp }
/>
```
### <a name='style'>selectRow.style - [Object | Function]</a>
`selectRow.style` allow you to have custom style on selected rows:
```js
const selectRow = {
mode: 'checkbox',
style: { background: 'red' }
};
```
If you wanna more flexible customization, `selectRow.style` also accept a function:
```js
const selectRow = {
mode: 'checkbox',
style: (row, rowIndex) => { return ...; }
};
```
### <a name='classes'>selectRow.classes - [String | Function]</a>
`selectRow.classes` allow you to add css class on selected rows:
```js
const selectRow = {
mode: 'checkbox',
classes: 'custom-class'
};
```
If you wanna more flexible customization, `selectRow.classes` also accept a function:
```js
const selectRow = {
mode: 'checkbox',
classes: (row, rowIndex) => { return ...; }
};
```
### <a name='bgColor'>selectRow.bgColor - [String | Function]</a>
The backgroud color when row is selected
```js
const selectRow = {
mode: 'checkbox',
bgColor: 'red'
};
```
There's also a more good way to custom it:
```js
const selectRow = {
mode: 'checkbox',
bgColor: (row, rowIndex) => {
return ....; // return a color code
}
};
```
### <a name='nonSelectable'>selectRow.nonSelectable - [Array]</a>
This prop allow you to restrict some rows which can not be selected by user. `selectRow.nonSelectable` accept an rowkeys array.
```js
const selectRow = {
mode: 'checkbox',
nonSelectable: [1, 3 ,5]
};
```
### <a name='clickToSelect'>selectRow.clickToSelect - [Bool]</a>
Allow user to select row by clicking on the row.
```js
const selectRow = {
mode: 'checkbox',
clickToSelect: true
};
```
> Note: When you also enable [cellEdit](./cell-edit.md), the `selectRow.clickToSelect` will deactivate the functionality of cell editing
> If you want to click on row to select row and edit cell simultaneously, you are suppose to enable [`selectRow.clickToEdit`](#clickToEdit)
### <a name='clickToEdit'>selectRow.clickToEdit - [Bool]</a>
Able to click to edit cell and select row
```js
const selectRow = {
mode: 'checkbox',
clickToSelect: true
clickToEdit: true
};
```
### <a name='onSelect'>selectRow.onSelect - [Function]</a>
This callback function will be called when a row is select/unselect and pass following three arguments:
`row`, `isSelect` and `rowIndex`.
```js
const selectRow = {
mode: 'checkbox',
onSelect: (row, isSelect, rowIndex) => {
// ...
}
};
```
### <a name='onSelectAll'>selectRow.onSelectAll - [Function]</a>
This callback function will be called when select/unselect all and it only work when you configure [`selectRow.mode`](#mode) as `checkbox`.
```js
const selectRow = {
mode: 'checkbox',
onSelectAll: (isSelect, results) => {
// ...
}
};
```
### <a name='hideSelectColumn'>selectRow.hideSelectColumn - [Bool]</a>
Default is `false`, if you don't want to have a selection column, give this prop as `true`
```js
const selectRow = {
mode: 'radio',
hideSelectColumn: true,
clickToSelect: true,
bgColor: 'red'
};
```

8
enzyme-setup.js Normal file
View File

@ -0,0 +1,8 @@
import Adapter from 'enzyme-adapter-react-16';
import { configure } from 'enzyme';
const configureEnzyme = () => {
configure({ adapter: new Adapter() });
};
configureEnzyme();

84
gulpfile.babel.js Normal file
View File

@ -0,0 +1,84 @@
import gulp from 'gulp';
import babel from 'gulp-babel';
import sass from 'gulp-sass';
import cleanCSS from 'gulp-clean-css';
import cleanDir from 'gulp-clean';
import rename from 'gulp-rename';
import shell from 'gulp-shell';
const LIB = 'lib';
const DIST = 'dist';
const TEST = 'test';
const PKG_PATH = './packages';
const NODE_MODULES = 'node_modules';
const JS_PKGS = [
'react-bootstrap-table2',
'react-bootstrap-table2-editor',
'react-bootstrap-table2-filter',
'react-bootstrap-table2-overlay',
'react-bootstrap-table2-paginator'
].reduce((pkg, curr) => `${curr}|${pkg}`, '');
const JS_SKIPS = `+(${TEST}|${LIB}|${DIST}|${NODE_MODULES})`;
const STYLE_PKGS = [
'react-bootstrap-table2',
'react-bootstrap-table2-paginator'
].reduce((pkg, curr) => `${curr}|${pkg}`, '');
const STYLE_SKIPS = `+(${NODE_MODULES})`;
function clean() {
return gulp
.src(`./packages/+(${JS_PKGS})/+(${LIB}|${DIST})`, { allowEmpty: true })
.pipe(cleanDir());
}
function scripts() {
return gulp
.src([
`./packages/+(${JS_PKGS})/**/*.js`,
`!packages/+(${JS_PKGS})/${JS_SKIPS}/**/*.js`
])
.pipe(babel())
.pipe(rename((path) => {
if (path.dirname.indexOf('src') > -1) {
path.dirname = path.dirname.replace('src', `${LIB}/src`);
} else {
path.dirname += `/${LIB}`;
}
}))
.pipe(gulp.dest(PKG_PATH));
}
function styles() {
return gulp
.src([
`./packages/+(${STYLE_PKGS})/style/**/*.scss`,
`!packages/+(${STYLE_PKGS})/${STYLE_SKIPS}/**/*.scss`
])
.pipe(sass().on('error', sass.logError))
.pipe(rename((path) => {
path.dirname = path.dirname.replace('style', DIST);
}))
.pipe(gulp.dest(PKG_PATH))
.pipe(cleanCSS({ compatibility: 'ie8' }))
.pipe(rename((path) => {
path.extname = '.min.css';
}))
.pipe(gulp.dest(PKG_PATH));
}
function umd() {
return gulp.src('./webpack.prod.config.babel.js')
.pipe(shell(['webpack --config <%= file.path %>']));
}
const buildJS = gulp.parallel(umd, scripts);
const buildCSS = styles;
const build = gulp.series(clean, gulp.parallel(buildJS, buildCSS));
gulp.task('prod', build);
gulp.task('default', build);

7
lerna.json Normal file
View File

@ -0,0 +1,7 @@
{
"lerna": "2.0.0",
"packages": [
"packages/*"
],
"version": "independent"
}

View File

@ -1,19 +1,104 @@
{
"name": "react-bootstrap-table2",
"version": "0.0.1",
"private": true,
"description": "Rebuilt for react-bootstrap-table",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"postinstall": "lerna bootstrap",
"build": "./node_modules/.bin/gulp prod",
"lint": "eslint ./packages --ext .js --ext .jsx --ignore-path .gitignore",
"pretest": "yarn lint --cache",
"test": "jest",
"test:coverage": "jest --coverage",
"test:watch": "jest --watch",
"storybook": "cd ./packages/react-bootstrap-table2-example && yarn storybook",
"gh-pages:clean": "cd ./packages/react-bootstrap-table2-example && yarn gh-pages:clean",
"gh-pages:build": "cd ./packages/react-bootstrap-table2-example && yarn gh-pages:build"
},
"repository": {
"type": "git",
"url": "git+https://github.com/react-bootstrap-table/react-bootstrap-table2.git"
},
"author": "",
"license": "ISC",
"author": "AllenFang",
"contributors": [
{
"name": "Allen Fang",
"email": "ayu780129@hotmail.com",
"url": "https://github.com/AllenFang"
},
{
"name": "Chun-MingChen",
"email": "nick830314@gmail.com",
"url": "https://github.com/Chun-MingChen"
}
],
"license": "MIT",
"bugs": {
"url": "https://github.com/react-bootstrap-table/react-bootstrap-table2/issues"
},
"homepage": "https://github.com/react-bootstrap-table/react-bootstrap-table2#readme"
"homepage": "https://github.com/react-bootstrap-table/react-bootstrap-table2#readme",
"devDependencies": {
"babel-cli": "6.26.0",
"babel-core": "6.25.0",
"babel-eslint": "7.2.3",
"babel-jest": "20.0.3",
"babel-loader": "7.1.1",
"babel-preset-es2015": "6.24.1",
"babel-preset-react": "6.24.1",
"babel-preset-stage-0": "6.24.1",
"babel-register": "6.24.1",
"css-loader": "0.28.1",
"enzyme": "3.1.1",
"enzyme-adapter-react-16": "1.0.4",
"eslint": "4.5.0",
"eslint-config-airbnb": "15.1.0",
"eslint-loader": "1.9.0",
"eslint-plugin-import": "2.7.0",
"eslint-plugin-jsx-a11y": "5.1.1",
"eslint-plugin-react": "7.2.1",
"gulp": "4.0.0",
"gulp-babel": "7.0.0",
"gulp-clean": "0.4.0",
"gulp-clean-css": "3.9.2",
"gulp-rename": "^1.2.2",
"gulp-sass": "3.1.0",
"gulp-shell": "0.6.5",
"html-webpack-plugin": "2.30.1",
"jest": "20.0.4",
"jsdom": "11.2.0",
"jsdom-global": "3.0.2",
"lerna": "2.8.0",
"node-sass": "4.5.3",
"react-test-renderer": "16.0.0",
"sass-loader": "6.0.6",
"sinon": "3.2.1",
"style-loader": "0.17.0",
"webpack": "3.5.4",
"webpack-dev-server": "2.7.1"
},
"dependencies": {
"classnames": "2.2.5",
"prop-types": "15.5.10",
"react": "16.0.0",
"react-dom": "16.0.0"
},
"jest": {
"collectCoverageFrom": [
"packages/**/*.js"
],
"roots": [
"<rootDir>/packages"
],
"setupFiles": [
"<rootDir>/enzyme-setup.js"
],
"modulePaths": [
"<rootDir>/packages/react-bootstrap-table2"
],
"testEnvironment": "node",
"testMatch": [
"**/test/**/*.test.js"
]
}
}

View File

@ -0,0 +1,61 @@
# react-bootstrap-table2-editor
`react-bootstrap-table2` separate the cell edit code base to [`react-bootstrap-table2-editor`](https://github.com/react-bootstrap-table/react-bootstrap-table2/tree/develop/packages/react-bootstrap-table2-editor), so there's a little bit different when you use cell edit than `react-bootstrap-table`. In the following, we are going to show you how to enable the cell edit
**[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
```sh
$ npm install react-bootstrap-table2-editor --save
```
## How
We have [two ways](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/cell-edit-props.html#celleditmode-string) to trigger a editable cell as editing cell:
* click
* dbclick
That's look into how we enable the cell edit on tabe:
```js
import cellEditFactory from 'react-bootstrap-table2-editor';
// omit
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
cellEdit={ cellEditFactory({ mode: 'click' }) }
/>
```
How user save their new editings? We offer two ways:
* Press ENTER(**default**)
* Blur from current editing cell(Need to enable the [cellEdit.blurToSave](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/cell-edit-props.html#celleditblurtosave-bool))
## Editable Cell
`react-bootstrap-table2` support you to configure the cell editable on three level:
* Row Level ([cellEdit.nonEditableRows](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/cell-edit-props.html#celleditnoneditablerows-function))
* Column Level (Configure [column.editable](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columneditable-bool-function) as bool value)
* Cell Level (Configure [column.editable](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columneditable-bool-function) as a callback function)
## Customize Style/Class
Currently, we only support the editing cell style/class customization, in the future, we will offer more customizations.
### Editing Cell
* Customize the editing cell style via [column.editCellStyle](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columneditcellstyle-object-function)
* Customize the editing cell classname via [column.editCellClasses](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columneditcellclasses-string-function)
## Validation
[`column.validator`](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/column-props.html#columnvalidator-function) will help you to work on it!

View File

@ -0,0 +1,16 @@
import wrapperFactory from './src/wrapper';
import editingCellFactory from './src/editing-cell';
import {
CLICK_TO_CELL_EDIT,
DBCLICK_TO_CELL_EDIT,
DELAY_FOR_DBCLICK
} from './src/const';
export default (options = {}) => ({
wrapperFactory,
editingCellFactory,
CLICK_TO_CELL_EDIT,
DBCLICK_TO_CELL_EDIT,
DELAY_FOR_DBCLICK,
options
});

View File

@ -0,0 +1,47 @@
{
"name": "react-bootstrap-table2-editor",
"version": "0.0.3",
"description": "it's the editor addon for react-bootstrap-table2",
"main": "./lib/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/react-bootstrap-table/react-bootstrap-table2.git"
},
"keywords": [
"react",
"bootstrap",
"table",
"grid",
"react-bootstrap-table-addons",
"react-component"
],
"files": [
"lib/",
"dist/"
],
"tags": [
"react"
],
"author": "AllenFang",
"contributors": [
{
"name": "Allen Fang",
"email": "ayu780129@hotmail.com",
"url": "https://github.com/AllenFang"
},
{
"name": "Chun-MingChen",
"email": "nick830314@gmail.com",
"url": "https://github.com/Chun-MingChen"
}
],
"peerDependencies": {
"prop-types": "^15.0.0",
"react": "^16.0.0",
"react-dom": "^16.0.0"
}
}

View File

@ -0,0 +1,4 @@
export const TIME_TO_CLOSE_MESSAGE = 3000;
export const DELAY_FOR_DBCLICK = 200;
export const CLICK_TO_CELL_EDIT = 'click';
export const DBCLICK_TO_CELL_EDIT = 'dbclick';

View File

@ -0,0 +1,153 @@
/* eslint react/prop-types: 0 */
/* eslint no-return-assign: 0 */
/* eslint class-methods-use-this: 0 */
/* eslint jsx-a11y/no-noninteractive-element-interactions: 0 */
import React, { Component } from 'react';
import cs from 'classnames';
import PropTypes from 'prop-types';
import TextEditor from './text-editor';
import EditorIndicator from './editor-indicator';
import { TIME_TO_CLOSE_MESSAGE } from './const';
export default _ =>
class EditingCell extends Component {
static propTypes = {
row: PropTypes.object.isRequired,
column: PropTypes.object.isRequired,
onUpdate: PropTypes.func.isRequired,
onEscape: PropTypes.func.isRequired,
timeToCloseMessage: PropTypes.number,
className: PropTypes.string,
style: PropTypes.object
}
static defaultProps = {
timeToCloseMessage: TIME_TO_CLOSE_MESSAGE,
className: null,
style: {}
}
constructor(props) {
super(props);
this.indicatorTimer = null;
this.clearTimer = this.clearTimer.bind(this);
this.handleBlur = this.handleBlur.bind(this);
this.handleClick = this.handleClick.bind(this);
this.handleKeyDown = this.handleKeyDown.bind(this);
this.beforeComplete = this.beforeComplete.bind(this);
this.state = {
invalidMessage: null
};
}
componentWillReceiveProps({ message }) {
if (_.isDefined(message)) {
this.createTimer();
this.setState(() => ({
invalidMessage: message
}));
}
}
componentWillUnmount() {
this.clearTimer();
}
clearTimer() {
if (this.indicatorTimer) {
clearTimeout(this.indicatorTimer);
}
}
createTimer() {
this.clearTimer();
const { timeToCloseMessage, onErrorMessageDisappear } = this.props;
this.indicatorTimer = _.sleep(() => {
this.setState(() => ({
invalidMessage: null
}));
if (_.isFunction(onErrorMessageDisappear)) onErrorMessageDisappear();
}, timeToCloseMessage);
}
beforeComplete(row, column, newValue) {
const { onUpdate } = this.props;
if (_.isFunction(column.validator)) {
const validateForm = column.validator(newValue, row, column);
if (_.isObject(validateForm) && !validateForm.valid) {
this.setState(() => ({
invalidMessage: validateForm.message
}));
this.createTimer();
return;
}
}
onUpdate(row, column, newValue);
}
handleBlur() {
const { onEscape, blurToSave, row, column } = this.props;
if (blurToSave) {
const value = this.editor.text.value;
if (!_.isDefined(value)) {
// TODO: for other custom or embed editor
}
this.beforeComplete(row, column, value);
} else {
onEscape();
}
}
handleKeyDown(e) {
const { onEscape, row, column } = this.props;
if (e.keyCode === 27) { // ESC
onEscape();
} else if (e.keyCode === 13) { // ENTER
const value = e.currentTarget.value;
if (!_.isDefined(value)) {
// TODO: for other custom or embed editor
}
this.beforeComplete(row, column, value);
}
}
handleClick(e) {
if (e.target.tagName !== 'TD') {
// To avoid the row selection event be triggered,
// When user define selectRow.clickToSelect and selectRow.clickToEdit
// We shouldn't trigger selection event even if user click on the cell editor(input)
e.stopPropagation();
}
}
render() {
const { invalidMessage } = this.state;
const { row, column, className, style } = this.props;
const { dataField } = column;
const value = _.get(row, dataField);
const editorAttrs = {
onKeyDown: this.handleKeyDown,
onBlur: this.handleBlur
};
const hasError = _.isDefined(invalidMessage);
const editorClass = hasError ? cs('animated', 'shake') : null;
return (
<td
className={ cs('react-bootstrap-table-editing-cell', className) }
style={ style }
onClick={ this.handleClick }
>
<TextEditor
ref={ node => this.editor = node }
defaultValue={ value }
className={ editorClass }
{ ...editorAttrs }
/>
{ hasError ? <EditorIndicator invalidMessage={ invalidMessage } /> : null }
</td>
);
}
};

View File

@ -0,0 +1,19 @@
/* eslint no-return-assign: 0 */
import React from 'react';
import PropTypes from 'prop-types';
const EditorIndicator = ({ invalidMessage }) =>
(
<div className="alert alert-danger fade in">
<strong>{ invalidMessage }</strong>
</div>
);
EditorIndicator.propTypes = {
invalidMessage: PropTypes.string
};
EditorIndicator.defaultProps = {
invalidMessage: null
};
export default EditorIndicator;

View File

@ -0,0 +1,40 @@
/* eslint no-return-assign: 0 */
import React, { Component } from 'react';
import cs from 'classnames';
import PropTypes from 'prop-types';
class TextEditor extends Component {
componentDidMount() {
const { defaultValue } = this.props;
this.text.value = defaultValue;
this.text.focus();
}
render() {
const { defaultValue, className, ...rest } = this.props;
const editorClass = cs('form-control editor edit-text', className);
return (
<input
ref={ node => this.text = node }
type="text"
className={ editorClass }
{ ...rest }
/>
);
}
}
TextEditor.propTypes = {
className: PropTypes.oneOfType([
PropTypes.string,
PropTypes.object
]),
defaultValue: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number
]).isRequired
};
TextEditor.defaultProps = {
className: null
};
export default TextEditor;

View File

@ -0,0 +1,135 @@
/* eslint react/prop-types: 0 */
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { CLICK_TO_CELL_EDIT, DBCLICK_TO_CELL_EDIT } from './const';
export default (
Base,
{ _, remoteResolver }
) => {
let EditingCell;
return class CellEditWrapper extends remoteResolver(Component) {
static propTypes = {
options: PropTypes.shape({
mode: PropTypes.oneOf([CLICK_TO_CELL_EDIT, DBCLICK_TO_CELL_EDIT]).isRequired,
onErrorMessageDisappear: PropTypes.func,
blurToSave: PropTypes.bool,
beforeSaveCell: PropTypes.func,
afterSaveCell: PropTypes.func,
nonEditableRows: PropTypes.func,
timeToCloseMessage: PropTypes.number,
errorMessage: PropTypes.string
})
}
constructor(props) {
super(props);
EditingCell = props.cellEdit.editingCellFactory(_);
this.startEditing = this.startEditing.bind(this);
this.escapeEditing = this.escapeEditing.bind(this);
this.completeEditing = this.completeEditing.bind(this);
this.handleCellUpdate = this.handleCellUpdate.bind(this);
this.state = {
ridx: null,
cidx: null,
message: null,
isDataChanged: false
};
}
componentWillReceiveProps(nextProps) {
if (nextProps.cellEdit && this.isRemoteCellEdit()) {
if (nextProps.cellEdit.options.errorMessage) {
this.setState(() => ({
isDataChanged: false,
message: nextProps.cellEdit.options.errorMessage
}));
} else {
this.setState(() => ({
isDataChanged: true
}));
this.escapeEditing();
}
} else {
this.setState(() => ({
isDataChanged: false
}));
}
}
handleCellUpdate(row, column, newValue) {
const { keyField, cellEdit, store } = this.props;
const { beforeSaveCell, afterSaveCell } = cellEdit.options;
const oldValue = _.get(row, column.dataField);
const rowId = _.get(row, keyField);
if (_.isFunction(beforeSaveCell)) beforeSaveCell(oldValue, newValue, row, column);
if (this.isRemoteCellEdit()) {
this.handleCellChange(rowId, column.dataField, newValue);
} else {
store.edit(rowId, column.dataField, newValue);
if (_.isFunction(afterSaveCell)) afterSaveCell(oldValue, newValue, row, column);
this.completeEditing();
}
}
completeEditing() {
this.setState(() => ({
ridx: null,
cidx: null,
message: null,
isDataChanged: true
}));
}
startEditing(ridx, cidx) {
const editing = () => {
this.setState(() => ({
ridx,
cidx,
isDataChanged: false
}));
};
const { selectRow } = this.props;
if (!selectRow || (selectRow.clickToEdit || !selectRow.clickToSelect)) editing();
}
escapeEditing() {
this.setState(() => ({
ridx: null,
cidx: null
}));
}
render() {
const { isDataChanged, ...stateRest } = this.state;
const {
cellEdit: {
options: { nonEditableRows, errorMessage, ...optionsRest },
editingCellFactory,
...cellEditRest
}
} = this.props;
const newCellEdit = {
...optionsRest,
...cellEditRest,
...stateRest,
EditingCell,
nonEditableRows: _.isDefined(nonEditableRows) ? nonEditableRows() : [],
onStart: this.startEditing,
onEscape: this.escapeEditing,
onUpdate: this.handleCellUpdate
};
return (
<Base
{ ...this.props }
data={ this.props.store.data }
isDataChanged={ isDataChanged }
cellEdit={ newCellEdit }
/>
);
}
};
};

View File

@ -0,0 +1,234 @@
/* eslint react/prop-types: 0 */
import 'jsdom-global/register';
import React from 'react';
import sinon from 'sinon';
import { shallow, mount } from 'enzyme';
import _ from 'react-bootstrap-table-next/src/utils';
import editingCellFactory from '../src/editing-cell';
import TextEditor from '../src/text-editor';
import EditorIndicator from '../src/editor-indicator';
const EditingCell = editingCellFactory(_);
const TableRowWrapper = props => (
<table>
<tbody>
<tr>{ props.children }</tr>
</tbody>
</table>
);
describe('EditingCell', () => {
let wrapper;
let onUpdate;
let onEscape;
const row = {
id: 1,
name: 'A'
};
let column = {
dataField: 'id',
text: 'ID'
};
beforeEach(() => {
onEscape = sinon.stub();
onUpdate = sinon.stub();
wrapper = shallow(
<EditingCell
row={ row }
column={ column }
onUpdate={ onUpdate }
onEscape={ onEscape }
/>
);
});
it('should render default editor successfully', () => {
expect(wrapper.length).toBe(1);
expect(wrapper.find('td').length).toBe(1);
expect(wrapper.find(TextEditor).length).toBe(1);
expect(wrapper.state().invalidMessage).toBeNull();
});
it('should render TextEditor with correct props', () => {
const textEditor = wrapper.find(TextEditor);
expect(textEditor.props().defaultValue).toEqual(row[column.dataField]);
expect(textEditor.props().onKeyDown).toBeDefined();
expect(textEditor.props().onBlur).toBeDefined();
expect(textEditor.props().className).toBeNull();
});
it('should not render EditorIndicator due to state.invalidMessage is null', () => {
const indicator = wrapper.find(EditorIndicator);
expect(indicator.length).toEqual(0);
});
it('when press ENTER on TextEditor should call onUpdate correctly', () => {
const newValue = 'test';
const textEditor = wrapper.find(TextEditor);
textEditor.simulate('keyDown', { keyCode: 13, currentTarget: { value: newValue } });
expect(onUpdate.callCount).toBe(1);
expect(onUpdate.calledWith(row, column, newValue)).toBe(true);
});
it('when press ESC on TextEditor should call onEscape correctly', () => {
const textEditor = wrapper.find(TextEditor);
textEditor.simulate('keyDown', { keyCode: 27 });
expect(onEscape.callCount).toBe(1);
});
it('when blur from TextEditor should call onEscape correctly', () => {
const textEditor = wrapper.find(TextEditor);
textEditor.simulate('blur');
expect(onEscape.callCount).toBe(1);
});
describe('if style prop is defined', () => {
const customStyle = { backgroundColor: 'red' };
beforeEach(() => {
wrapper = shallow(
<EditingCell
row={ row }
column={ column }
onUpdate={ onUpdate }
onEscape={ onEscape }
style={ customStyle }
/>
);
});
it('should render component with style successfully', () => {
expect(wrapper.length).toBe(1);
expect(wrapper.find('td').prop('style')).toEqual(customStyle);
});
});
describe('if className prop is defined', () => {
const className = 'test-class';
beforeEach(() => {
wrapper = shallow(
<EditingCell
row={ row }
column={ column }
onUpdate={ onUpdate }
onEscape={ onEscape }
className={ className }
/>
);
});
it('should render component with style successfully', () => {
expect(wrapper.length).toBe(1);
expect(wrapper.hasClass(className)).toBe(true);
});
});
describe('if blurToSave prop is true', () => {
beforeEach(() => {
wrapper = mount(
<TableRowWrapper>
<EditingCell
row={ row }
column={ column }
onUpdate={ onUpdate }
onEscape={ onEscape }
blurToSave
/>
</TableRowWrapper>
);
});
it('when blur from TextEditor should call onUpdate correctly', () => {
const textEditor = wrapper.find(TextEditor);
textEditor.simulate('blur');
expect(onUpdate.callCount).toBe(1);
expect(onUpdate.calledWith(row, column, `${row[column.dataField]}`)).toBe(true);
});
});
describe('when column.validator is defined', () => {
let newValue;
let validForm;
let validatorCallBack;
describe('and column.validator return an object', () => {
beforeEach(() => {
newValue = 'newValue';
validForm = { valid: false, message: 'Something is invalid' };
validatorCallBack = sinon.stub().returns(validForm);
column = {
dataField: 'id',
text: 'ID',
validator: validatorCallBack
};
wrapper = mount(
<EditingCell
row={ row }
column={ column }
onUpdate={ onUpdate }
onEscape={ onEscape }
/>
);
wrapper.instance().beforeComplete(row, column, newValue);
});
it('should call column.validator successfully', () => {
expect(validatorCallBack.callCount).toBe(1);
expect(validatorCallBack.calledWith(newValue, row, column)).toBe(true);
});
it('should not call onUpdate', () => {
expect(onUpdate.callCount).toBe(0);
});
it('should set indicatorTimer successfully', () => {
expect(wrapper.instance().indicatorTimer).toBeDefined();
});
it('should set invalidMessage state correctly', () => {
expect(wrapper.state().invalidMessage).toEqual(validForm.message);
});
it('should render TextEditor with correct shake and animated class', () => {
const editor = wrapper.find(TextEditor);
expect(editor.html()).toEqual('<input type="text" class="form-control editor edit-text animated shake">');
/* Following is better, but it will not work after upgrade React to 16 and enzyme... */
// expect(editor.length).toEqual(1);
// expect(editor.props().classNames).toEqual('animated shake');
});
/* Following is better, but it will not work after upgrade React to 16 and enzyme... */
xit('should render EditorIndicator correctly', () => {
const indicator = wrapper.find(EditorIndicator);
expect(indicator.length).toEqual(1);
expect(indicator.props().invalidMessage).toEqual(validForm.message);
});
});
describe('and column.validator return true or something', () => {
beforeEach(() => {
newValue = 'newValue';
validForm = true;
validatorCallBack = sinon.stub().returns(validForm);
column = {
dataField: 'id',
text: 'ID',
validator: validatorCallBack
};
wrapper.instance().beforeComplete(row, column, newValue);
});
it('should call column.validator successfully', () => {
expect(validatorCallBack.callCount).toBe(1);
expect(validatorCallBack.calledWith(newValue, row, column)).toBe(true);
});
it('should call onUpdate', () => {
expect(onUpdate.callCount).toBe(1);
});
});
});
});

View File

@ -0,0 +1,42 @@
import 'jsdom-global/register';
import React from 'react';
import { mount } from 'enzyme';
import TextEditor from '../src/text-editor';
describe('TextEditor', () => {
let wrapper;
const value = 'test';
beforeEach(() => {
wrapper = mount(
<TextEditor
defaultValue={ value }
/>
);
});
it('should render TextEditor correctly', () => {
expect(wrapper.length).toBe(1);
expect(wrapper.find('input').length).toBe(1);
expect(wrapper.find('input').prop('type')).toEqual('text');
expect(wrapper.find('.form-control.editor.edit-text').length).toBe(1);
});
describe('when className prop defined', () => {
const className = 'test-class';
beforeEach(() => {
wrapper = mount(
<TextEditor
defaultValue={ value }
className={ className }
/>
);
});
it('should render correct custom classname', () => {
expect(wrapper.length).toBe(1);
expect(wrapper.hasClass(className)).toBeTruthy();
});
});
});

View File

@ -0,0 +1,330 @@
import React from 'react';
import sinon from 'sinon';
import { shallow } from 'enzyme';
import _ from 'react-bootstrap-table-next/src/utils';
import remoteResolver from 'react-bootstrap-table-next/src/props-resolver/remote-resolver';
import Store from 'react-bootstrap-table-next/src/store';
import BootstrapTable from 'react-bootstrap-table-next/src/bootstrap-table';
import cellEditFactory from '..';
import * as Const from '../src/const';
import wrapperFactory from '../src/wrapper';
describe('CellEditWrapper', () => {
let wrapper;
let instance;
const onTableChangeCB = sinon.stub();
const columns = [{
dataField: 'id',
text: 'ID'
}, {
dataField: 'name',
text: 'Name'
}];
const data = [{
id: 1,
name: 'A'
}, {
id: 2,
name: 'B'
}];
const createTableProps = (props = {}) => {
const { cellEdit, ...rest } = props;
const tableProps = {
keyField: 'id',
columns,
data,
_,
store: new Store('id'),
cellEdit: cellEditFactory(cellEdit),
onTableChange: onTableChangeCB,
...rest
};
tableProps.store.data = data;
return tableProps;
};
const CellEditWrapper = wrapperFactory(BootstrapTable, {
_,
remoteResolver
});
const createCellEditWrapper = (props, renderFragment = true) => {
wrapper = shallow(<CellEditWrapper { ...props } />);
instance = wrapper.instance();
if (renderFragment) {
const fragment = instance.render();
wrapper = shallow(<div>{ fragment }</div>);
}
};
afterEach(() => {
onTableChangeCB.reset();
});
beforeEach(() => {
const props = createTableProps({
cellEdit: { mode: Const.CLICK_TO_CELL_EDIT }
});
createCellEditWrapper(props);
});
it('should render CellEditWrapper correctly', () => {
expect(wrapper.length).toBe(1);
expect(wrapper.find(BootstrapTable)).toBeDefined();
});
it('should have correct state', () => {
expect(instance.state.ridx).toBeNull();
expect(instance.state.cidx).toBeNull();
expect(instance.state.message).toBeNull();
expect(instance.state.isDataChanged).toBeFalsy();
});
it('should inject correct props to base component', () => {
const base = wrapper.find(BootstrapTable);
expect(base.props().cellEdit).toBeDefined();
expect(base.props().cellEdit.onStart).toBeDefined();
expect(base.props().cellEdit.onEscape).toBeDefined();
expect(base.props().cellEdit.onUpdate).toBeDefined();
expect(base.props().cellEdit.EditingCell).toBeDefined();
expect(base.props().cellEdit.ridx).toBeNull();
expect(base.props().cellEdit.cidx).toBeNull();
expect(base.props().cellEdit.message).toBeNull();
expect(base.props().isDataChanged).toBe(instance.state.isDataChanged);
});
describe('when receive new cellEdit prop', () => {
const spy = jest.spyOn(CellEditWrapper.prototype, 'escapeEditing');
describe('and cellEdit is not work on remote', () => {
beforeEach(() => {
const props = createTableProps({
cellEdit: { mode: Const.CLICK_TO_CELL_EDIT }
});
createCellEditWrapper(props);
wrapper.setProps({ cellEdit: props.cellEdit });
});
it('should always setting state.isDataChanged as false', () => {
expect(instance.state.isDataChanged).toBeFalsy();
});
});
describe('and cellEdit is work on remote', () => {
let errorMessage;
let props;
beforeEach(() => {
props = createTableProps({
cellEdit: { mode: Const.CLICK_TO_CELL_EDIT },
remote: true
});
});
describe('and cellEdit.errorMessage is defined', () => {
beforeEach(() => {
createCellEditWrapper(props, false);
errorMessage = 'test';
const newCellEdit = {
...props.cellEdit,
options: { ...props.cellEdit.options, errorMessage }
};
wrapper.setProps({ cellEdit: newCellEdit });
});
it('should setting correct state', () => {
expect(instance.state.isDataChanged).toBeFalsy();
expect(instance.state.message).toEqual(errorMessage);
});
});
describe('and cellEdit.errorMessage is undefined', () => {
beforeEach(() => {
errorMessage = null;
createCellEditWrapper(props, false);
const newCellEdit = {
...props.cellEdit,
options: { ...props.cellEdit.options, errorMessage }
};
wrapper.setProps({ cellEdit: newCellEdit });
});
it('should setting correct state', () => {
expect(wrapper.state().isDataChanged).toBeTruthy();
});
it('should escape current editing', () => {
expect(spy).toHaveBeenCalled();
});
});
});
});
describe('call escapeEditing function', () => {
it('should set state correctly', () => {
instance.escapeEditing();
expect(instance.state.ridx).toBeNull();
expect(instance.state.cidx).toBeNull();
});
});
describe('call startEditing function', () => {
const ridx = 1;
const cidx = 3;
it('should set state correctly', () => {
instance.startEditing(ridx, cidx);
expect(instance.state.ridx).toEqual(ridx);
expect(instance.state.cidx).toEqual(cidx);
expect(instance.state.isDataChanged).toBeFalsy();
});
describe('if selectRow.clickToSelect is defined', () => {
beforeEach(() => {
const selectRow = { mode: 'checkbox', clickToSelect: true };
const props = createTableProps({
cellEdit: { mode: Const.CLICK_TO_CELL_EDIT },
selectRow
});
createCellEditWrapper(props);
});
it('should not set state', () => {
instance.startEditing(ridx, cidx);
expect(instance.state.ridx).toBeNull();
expect(instance.state.cidx).toBeDefined();
});
});
describe('if selectRow.clickToSelect and selectRow.clickToEdit is defined', () => {
beforeEach(() => {
const selectRow = { mode: 'checkbox', clickToSelect: true, clickToEdit: true };
const props = createTableProps({
cellEdit: { mode: Const.CLICK_TO_CELL_EDIT },
selectRow
});
createCellEditWrapper(props);
});
it('should set state correctly', () => {
instance.startEditing(ridx, cidx);
expect(instance.state.ridx).toEqual(ridx);
expect(instance.state.cidx).toEqual(cidx);
});
});
});
describe('call completeEditing function', () => {
it('should set state correctly', () => {
instance.completeEditing();
expect(instance.state.ridx).toBeNull();
expect(instance.state.cidx).toBeNull();
expect(instance.state.message).toBeNull();
expect(instance.state.isDataChanged).toBeTruthy();
});
});
describe('call handleCellUpdate function', () => {
let props;
const row = data[0];
const column = columns[1];
const newValue = 'new name';
describe('when cell edit is work on remote', () => {
const spy = jest.spyOn(CellEditWrapper.prototype, 'handleCellChange');
beforeEach(() => {
props = createTableProps({
cellEdit: { mode: Const.CLICK_TO_CELL_EDIT },
remote: true
});
createCellEditWrapper(props);
instance.handleCellUpdate(row, column, newValue);
});
it('should calling handleCellChange correctly', () => {
expect(spy).toHaveBeenCalled();
expect(spy.mock.calls).toHaveLength(1);
expect(spy.mock.calls[0]).toHaveLength(3);
expect(spy.mock.calls[0][0]).toEqual(row.id);
expect(spy.mock.calls[0][1]).toEqual(column.dataField);
expect(spy.mock.calls[0][2]).toEqual(newValue);
});
});
describe('when cell edit is not work on remote', () => {
const spyOnCompleteEditing = jest.spyOn(CellEditWrapper.prototype, 'completeEditing');
const spyOnStoreEdit = jest.spyOn(Store.prototype, 'edit');
beforeEach(() => {
props = createTableProps({
cellEdit: { mode: Const.CLICK_TO_CELL_EDIT }
});
createCellEditWrapper(props);
instance.handleCellUpdate(row, column, newValue);
});
afterEach(() => {
spyOnStoreEdit.mockReset();
spyOnCompleteEditing.mockReset();
});
it('should calling props.store.edit', () => {
expect(spyOnStoreEdit).toHaveBeenCalled();
expect(spyOnStoreEdit.mock.calls).toHaveLength(1);
expect(spyOnStoreEdit.mock.calls[0]).toHaveLength(3);
expect(spyOnStoreEdit.mock.calls[0][0]).toEqual(row.id);
expect(spyOnStoreEdit.mock.calls[0][1]).toEqual(column.dataField);
expect(spyOnStoreEdit.mock.calls[0][2]).toEqual(newValue);
});
it('should calling completeEditing function', () => {
expect(spyOnCompleteEditing).toHaveBeenCalled();
});
describe('if cellEdit.afterSaveCell prop defined', () => {
const aftereSaveCellCallBack = sinon.stub();
beforeEach(() => {
props = createTableProps({
cellEdit: {
mode: Const.CLICK_TO_CELL_EDIT,
afterSaveCell: aftereSaveCellCallBack
}
});
createCellEditWrapper(props);
instance.handleCellUpdate(row, column, newValue);
});
it('should calling cellEdit.afterSaveCell correctly', () => {
expect(aftereSaveCellCallBack.callCount).toBe(1);
expect(aftereSaveCellCallBack.calledWith(
row[column.dataField], newValue, row, column)
).toBe(true);
});
});
});
describe('if cellEdit.beforeSaveCell prop defined', () => {
const beforeSaveCellCallBack = sinon.stub();
beforeEach(() => {
props = createTableProps({
cellEdit: {
mode: Const.CLICK_TO_CELL_EDIT,
beforeSaveCell: beforeSaveCellCallBack
}
});
createCellEditWrapper(props);
instance.handleCellUpdate(row, column, newValue);
});
it('should calling cellEdit.beforeSaveCell correctly', () => {
expect(beforeSaveCellCallBack.callCount).toBe(1);
expect(beforeSaveCellCallBack.calledWith(
row[column.dataField], newValue, row, column)
).toBe(true);
});
});
});
});

View File

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

View File

@ -0,0 +1,5 @@
/* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions */
import '@storybook/addon-actions/register';
import '@storybook/addon-links/register';
import '@storybook/addon-console';

View File

@ -0,0 +1,26 @@
/* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions */
import React from 'react';
import { configure, addDecorator } from '@storybook/react';
import { withConsole } from '@storybook/addon-console';
function loadStories() {
require('stories');
}
const styles = {
margin: '15px',
};
const componentDecorator = (story) => (
<div style={styles}>
{ story() }
</div>
);
// prepend the story name to log messages
addDecorator((storyFn, context) => withConsole()(storyFn)(context));
addDecorator(componentDecorator);
configure(loadStories, module);

View File

@ -0,0 +1,2 @@
<script src="https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js"></script>

View File

@ -0,0 +1,65 @@
const path = require('path');
const sourcePath = path.join(__dirname, '../../react-bootstrap-table2/index.js');
const paginationSourcePath = path.join(__dirname, '../../react-bootstrap-table2-paginator/index.js');
const overlaySourcePath = path.join(__dirname, '../../react-bootstrap-table2-overlay/index.js');
const filterSourcePath = path.join(__dirname, '../../react-bootstrap-table2-filter/index.js');
const editorSourcePath = path.join(__dirname, '../../react-bootstrap-table2-editor/index.js');
const sourceStylePath = path.join(__dirname, '../../react-bootstrap-table2/style');
const paginationStylePath = path.join(__dirname, '../../react-bootstrap-table2-paginator/style');
const storyPath = path.join(__dirname, '../stories');
const examplesPath = path.join(__dirname, '../examples');
const srcPath = path.join(__dirname, '../src');
const aliasPath = {
examples: examplesPath,
stories: storyPath,
src: srcPath,
components: path.join(srcPath, 'components'),
utils: path.join(srcPath, 'utils'),
'react-bootstrap-table-next': sourcePath,
'react-bootstrap-table2-editor': editorSourcePath,
'react-bootstrap-table2-filter': filterSourcePath,
'react-bootstrap-table2-overlay': overlaySourcePath,
'react-bootstrap-table2-paginator': paginationSourcePath,
};
const loaders = [{
enforce: 'pre',
test: /\.js?$/,
exclude: /node_modules/,
include: [examplesPath, storyPath],
loader: 'eslint-loader',
}, {
test: /\.js?$/,
use: ['babel-loader'],
exclude: /node_modules/
}, {
test: /\.css$/,
use: ['style-loader', 'css-loader'],
}, {
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader'],
include: [storyPath, sourceStylePath, paginationStylePath],
}, {
test: /\.(jpg|png|woff|woff2|eot|ttf|svg)$/,
loader: 'url-loader?limit=100000',
}];
// Export a function. Accept the base config as the only param.
module.exports = (storybookBaseConfig, configType) => {
// configType has a value of 'DEVELOPMENT' or 'PRODUCTION'
// You can change the configuration based on that.
// 'PRODUCTION' is used when building the static version of storybook.
// loaders
loaders.forEach(value => {
storybookBaseConfig.module.rules.push(value);
})
// alias
storybookBaseConfig.resolve.alias = aliasPath;
// Return the altered config
return storybookBaseConfig;
};

View File

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

View File

@ -0,0 +1,49 @@
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const CaptionElement = () => <h3 style={{ borderRadius: '0.25em', textAlign: 'center', color: 'purple', border: '1px solid purple', padding: '0.5em' }}>Component as Header</h3>;
<BootstrapTable keyField="id" data={ products } caption="Plain text header" columns={ columns } />
<BootstrapTable keyField="id" data={ products } caption={<CaptionElement />} columns={ columns } />
`;
const Caption = () => <h3 style={ { borderRadius: '0.25em', textAlign: 'center', color: 'purple', border: '1px solid purple', padding: '0.5em' } }>Component as Header</h3>;
export default () => (
<div>
<BootstrapTable keyField="id" data={ products } caption="Plain text header" columns={ columns } />
<BootstrapTable keyField="id" data={ products } caption={ <Caption /> } columns={ columns } />
<Code>{ sourceCode }</Code>
</div>
);

View File

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

View File

@ -0,0 +1,37 @@
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
// omit...
<BootstrapTable keyField='id' data={ [] } columns={ columns } noDataIndication="Table is Empty" />
// Following is a more flexible example
function indication() {
// return something here
}
<BootstrapTable keyField='id' data={ [] } columns={ columns } noDataIndication={ indication } />
`;
export default () => (
<div>
<BootstrapTable keyField="id" data={ [] } columns={ columns } noDataIndication="Table is Empty" />
<Code>{ sourceCode }</Code>
</div>
);

View File

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

View File

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

View File

@ -0,0 +1,61 @@
/* eslint no-unused-vars: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name',
editCellClasses: 'editing-name'
}, {
dataField: 'price',
text: 'Product Price',
editCellClasses: (cell, row, rowIndex, colIndex) =>
(cell > 2101 ? 'editing-price-bigger-than-2101' : 'editing-price-small-than-2101')
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name',
editCellClasses: 'editing-name'
}, {
dataField: 'price',
text: 'Product Price',
editCellClasses: (cell, row, rowIndex, colIndex) =>
(cell > 2101 ? 'editing-price-bigger-than-2101' : 'editing-price-small-than-2101')
}];
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
cellEdit={ cellEditFactory({ mode: 'click' }) }
/>
`;
export default () => (
<div>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
cellEdit={ cellEditFactory({ mode: 'click' }) }
/>
<Code>{ sourceCode }</Code>
</div>
);

View File

@ -0,0 +1,64 @@
/* eslint no-unused-vars: 0 */
/* eslint no-console: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
cellEdit={ cellEditFactory({
mode: 'click',
beforeSaveCell: (oldValue, newValue, row, column) => { console.log('Before Saving Cell!!'); },
afterSaveCell: (oldValue, newValue, row, column) => { console.log('After Saving Cell!!'); }
}) }
/>
`;
export default () => (
<div>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
cellEdit={ cellEditFactory({
mode: 'click',
beforeSaveCell: (oldValue, newValue, row, column) => { console.log('Before Saving Cell!!'); },
afterSaveCell: (oldValue, newValue, row, column) => { console.log('After Saving Cell!!'); }
}) }
/>
<Code>{ sourceCode }</Code>
</div>
);

View File

@ -0,0 +1,69 @@
/* eslint no-unused-vars: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name',
editCellStyle: {
backgroundColor: '#20B2AA'
}
}, {
dataField: 'price',
text: 'Product Price',
editCellStyle: (cell, row, rowIndex, colIndex) => {
const backgroundColor = cell > 2101 ? '#00BFFF' : '#00FFFF';
return { backgroundColor };
}
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name',
editCellStyle: {
backgroundColor: '#20B2AA'
}
}, {
dataField: 'price',
text: 'Product Price',
editCellStyle: (cell, row, rowIndex, colIndex) => {
const backgroundColor = cell > 2101 ? '#00BFFF' : '#00FFFF';
return { backgroundColor };
}
}];
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
cellEdit={ cellEditFactory({ mode: 'click' }) }
/>
`;
export default () => (
<div>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
cellEdit={ cellEditFactory({ mode: 'click' }) }
/>
<Code>{ sourceCode }</Code>
</div>
);

View File

@ -0,0 +1,91 @@
/* eslint no-unused-vars: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price',
validator: (newValue, row, column) => {
if (isNaN(newValue)) {
return {
valid: false,
message: 'Price should be numeric'
};
}
if (newValue < 2000) {
return {
valid: false,
message: 'Price should bigger than 2000'
};
}
return true;
}
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price',
validator: (newValue, row, column) => {
if (isNaN(newValue)) {
return {
valid: false,
message: 'Price should be numeric'
};
}
if (newValue < 2000) {
return {
valid: false,
message: 'Price should bigger than 2000'
};
}
return true;
}
}];
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
cellEdit={ cellEditFactory({
mode: 'click',
blurToSave: true
}) }
/>
`;
export default () => (
<div>
<h3>Product Price should bigger than $2000</h3>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
cellEdit={ cellEditFactory({
mode: 'click',
blurToSave: true
}) }
/>
<Code>{ sourceCode }</Code>
</div>
);

View File

@ -0,0 +1,58 @@
/* eslint no-unused-vars: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price',
editable: (content, row, rowIndex, columnIndex) => content > 2101
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price',
editable: (content, row, rowIndex, columnIndex) => content > 2101
}];
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
cellEdit={ cellEditFactory({ mode: 'click' }) }
/>
`;
export default () => (
<div>
<h3>Only Product Price is bigger than 2101 is editable</h3>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
cellEdit={ cellEditFactory({ mode: 'click' }) }
/>
<Code>{ sourceCode }</Code>
</div>
);

View File

@ -0,0 +1,56 @@
/* eslint react/prefer-stateless-function: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
cellEdit={ cellEditFactory({ mode: 'click' }) }
/>
`;
export default () => (
<div>
<h3>Click to edit cell</h3>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
cellEdit={ cellEditFactory({ mode: 'click' }) }
/>
<Code>{ sourceCode }</Code>
</div>
);

View File

@ -0,0 +1,64 @@
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name',
editable: false
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
// Product Name column can't be edit anymore
editable: false
}, {
dataField: 'price',
text: 'Product Price'
}];
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
cellEdit={ cellEditFactory({
mode: 'click',
blurToSave: true
}) }
/>
`;
export default () => (
<div>
<h3>Product Name is non editable</h3>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
cellEdit={ cellEditFactory({
mode: 'click',
blurToSave: true
}) }
/>
<Code>{ sourceCode }</Code>
</div>
);

View File

@ -0,0 +1,55 @@
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
cellEdit={ cellEditFactory({ mode: 'dbclick' }) }
/>
`;
export default () => (
<div>
<h3>Double click to edit cell</h3>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
cellEdit={ cellEditFactory({ mode: 'dbclick' }) }
/>
<Code>{ sourceCode }</Code>
</div>
);

View File

@ -0,0 +1,62 @@
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
cellEdit={ cellEditFactory({
mode: 'click',
blurToSave: true,
nonEditableRows: () => [0, 3]
}) }
/>
`;
export default () => (
<div>
<h3>Product ID: 0, 3 is non editable</h3>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
cellEdit={ cellEditFactory({
mode: 'click',
blurToSave: true,
nonEditableRows: () => [0, 3]
}) }
/>
<Code>{ sourceCode }</Code>
</div>
);

View File

@ -0,0 +1,75 @@
/* eslint no-unused-vars: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
import Code from 'components/common/code-block';
import { jobsGenerator } from 'utils/common';
const jobs = jobsGenerator(5);
const owners = ['Allen', 'Bob', 'Cat'];
const types = ['Cloud Service', 'Message Service', 'Add Service', 'Edit Service', 'Money'];
const columns = [{
dataField: 'id',
text: 'Job ID'
}, {
dataField: 'name',
text: 'Job Name',
filter: textFilter()
}, {
dataField: 'owner',
text: 'Job Owner',
filter: textFilter(),
formatter: (cell, row) => owners[cell],
filterValue: (cell, row) => owners[cell]
}, {
dataField: 'type',
text: 'Job Type',
filter: textFilter(),
formatter: (cell, row) => types[cell],
filterValue: (cell, row) => types[cell]
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
const owners = ['Allen', 'Bob', 'Cat'];
const types = ['Cloud Service', 'Message Service', 'Add Service', 'Edit Service', 'Money'];
const columns = [{
dataField: 'id',
text: 'Job ID'
}, {
dataField: 'name',
text: 'Job Name',
filter: textFilter()
}, {
dataField: 'owner',
text: 'Job Owner',
filter: textFilter(),
formatter: (cell, row) => owners[cell],
filterValue: (cell, row) => owners[cell]
}, {
dataField: 'type',
text: 'Job Type',
filter: textFilter(),
filterValue: (cell, row) => types[cell]
}];
// shape of job: { id: 0, name: 'Job name 0', owner: 1, type: 3 }
<BootstrapTable keyField='id' data={ jobs } columns={ columns } filter={ filterFactory() } />
`;
export default () => (
<div>
<BootstrapTable
keyField="id"
data={ jobs }
columns={ columns }
filter={ filterFactory() }
/>
<Code>{ sourceCode }</Code>
</div>
);

View File

@ -0,0 +1,69 @@
/* eslint no-console: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator(8);
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name',
filter: textFilter()
}, {
dataField: 'price',
text: 'Product Price',
filter: textFilter({
delay: 1000, // default is 500ms
style: {
backgroundColor: 'yellow'
},
className: 'test-classname',
placeholder: 'Custom PlaceHolder',
onClick: e => console.log(e)
})
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name',
filter: textFilter()
}, {
dataField: 'price',
text: 'Product Price',
filter: textFilter({
delay: 1000, // default is 500ms
style: {
backgroundColor: 'yellow'
},
className: 'test-classname',
placeholder: 'Custom PlaceHolder',
onClick: e => console.log(e)
})
}];
<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,56 @@
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator(8);
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name',
filter: textFilter()
}, {
dataField: 'price',
text: 'Product Price',
filter: textFilter({
defaultValue: '2103'
})
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
const columns = [{
dataField: 'id',
text: 'Product ID',
}, {
dataField: 'name',
text: 'Product Name',
filter: textFilter()
}, {
dataField: 'price',
text: 'Product Price',
filter: textFilter({
defaultValue: '2103'
})
}];
<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,57 @@
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { textFilter, 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',
filter: textFilter({
comparator: Comparator.EQ // default is Comparator.LIKE
})
}, {
dataField: 'price',
text: 'Product Price',
filter: textFilter()
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { textFilter, Comparator } from 'react-bootstrap-table2-filter';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name',
filter: textFilter({
comparator: Comparator.EQ
})
}, {
dataField: 'price',
text: 'Product Price',
filter: textFilter()
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } filter={ filterFactory() } />
`;
export default () => (
<div>
<h3>Product Name filter apply Equal Comparator</h3>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
filter={ filterFactory() }
/>
<Code>{ sourceCode }</Code>
</div>
);

View File

@ -0,0 +1,52 @@
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator(8);
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name',
filter: textFilter()
}, {
dataField: 'price',
text: 'Product Price',
filter: textFilter()
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
const columns = [{
dataField: 'id',
text: 'Product ID',
}, {
dataField: 'name',
text: 'Product Name',
filter: textFilter()
}, {
dataField: 'price',
text: 'Product Price',
filter: textFilter()
}];
<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,53 @@
/* eslint no-unused-vars: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID',
align: 'center'
}, {
dataField: 'name',
text: 'Product Name',
align: (cell, row, rowIndex, colIndex) => {
if (rowIndex % 2 === 0) return 'right';
return 'left';
}
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{
dataField: 'id',
text: 'Product ID',
align: 'center'
}, {
dataField: 'name',
text: 'Product Name',
align: (cell, row, rowIndex, colIndex) => {
if (rowIndex % 2 === 0) return 'right';
return 'left';
}
}, {
dataField: 'price',
text: 'Product Price'
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } />
`;
export default () => (
<div>
<BootstrapTable keyField="id" data={ products } columns={ columns } />
<Code>{ sourceCode }</Code>
</div>
);

View File

@ -0,0 +1,48 @@
/* eslint no-unused-vars: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID',
attrs: { title: 'id column' }
}, {
dataField: 'name',
text: 'Product Name',
attrs: (cell, row, rowIndex, colIndex) => ({ 'data-test': `customized data ${rowIndex}` })
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{
dataField: 'id',
text: 'Product ID',
attrs: { title: 'id column' }
}, {
dataField: 'name',
text: 'Product Name',
attrs: (cell, row, rowIndex, colIndex) => ({ 'data-test': \`customized data \${rowIndex}\` })
}, {
dataField: 'price',
text: 'Product Price'
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } />
`;
export default () => (
<div>
<h3>Try to hover on Product Name header column</h3>
<BootstrapTable keyField="id" data={ products } columns={ columns } />
<Code>{ sourceCode }</Code>
</div>
);

View File

@ -0,0 +1,53 @@
/* eslint no-unused-vars: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID',
classes: 'demo-key-row'
}, {
dataField: 'name',
text: 'Product Name',
classes: (cell, row, rowIndex, colIndex) => {
if (rowIndex % 2 === 0) return 'demo-row-even';
return 'demo-row-odd';
}
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{
dataField: 'id',
text: 'Product ID',
classes: 'demo-key-row'
}, {
dataField: 'name',
text: 'Product Name',
classes: (cell, row, rowIndex, colIndex) => {
if (rowIndex % 2 === 0) return 'demo-row-even';
return 'demo-row-odd';
}
}, {
dataField: 'price',
text: 'Product Price'
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } />
`;
export default () => (
<div>
<BootstrapTable keyField="id" data={ products } columns={ columns } />
<Code>{ sourceCode }</Code>
</div>
);

View File

@ -0,0 +1,51 @@
/* eslint no-unused-vars: 0 */
/* eslint no-alert: 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',
events: {
onClick: () => alert('Click on Product ID field')
}
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{
dataField: 'id',
text: 'Product ID',
events: {
onClick: () => alert('Click on Product ID field')
}
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } />
`;
export default () => (
<div>
<h3>Try to Click on Product ID columns</h3>
<BootstrapTable keyField="id" data={ products } columns={ columns } />
<Code>{ sourceCode }</Code>
</div>
);

View File

@ -0,0 +1,74 @@
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();
function priceFormatter(cell, row) {
if (row.onSale) {
return (
<span><strong style={ { color: 'red' } }>$ { cell } NTD(Sales!!)</strong></span>
);
}
return (
<span>$ { cell } NTD</span>
);
}
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price',
formatter: priceFormatter
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
function priceFormatter(cell, row) {
if (row.onSale) {
return (
<span>
<strong style={ { color: 'red' } }>$ { cell } NTD(Sales!!)</strong>
</span>
);
}
return (
<span>$ { cell } NTD</span>
);
}
const columns = [
// omit...
{
dataField: 'price',
text: 'Product Price',
formatter: priceFormatter
}];
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
/>
`;
export default () => (
<div>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
/>
<Code>{ sourceCode }</Code>
</div>
);

View File

@ -0,0 +1,73 @@
/* 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(5, (value, index) => ({
id: index,
name: `User Name ${index}`,
rank: Math.random() < 0.5 ? 'down' : 'up'
}));
function rankFormatter(cell, row, rowIndex, formatExtraData) {
return (
<i className={ formatExtraData[cell] } />
);
}
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'rank',
text: 'Rank',
formatter: rankFormatter,
formatExtraData: {
up: 'glyphicon glyphicon-chevron-up',
down: 'glyphicon glyphicon-chevron-down'
}
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
function rankFormatter(cell, row, rowIndex, formatExtraData) {
return (
<i className={ formatExtraData[cell] } />
);
}
const columns = [
// omit...
{
dataField: 'rank',
text: 'Rank',
formatter: rankFormatter,
formatExtraData: {
up: 'glyphicon glyphicon-chevron-up',
down: 'glyphicon glyphicon-chevron-down'
}];
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
/>
`;
export default () => (
<div>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
bordered={ false }
/>
<Code>{ sourceCode }</Code>
</div>
);

View File

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

View File

@ -0,0 +1,71 @@
/* eslint no-unused-vars: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID',
style: {
fontWeight: 'bold',
fontSize: '18px'
}
}, {
dataField: 'name',
text: 'Product Name',
style: (cell, row, rowIndex, colIndex) => {
if (rowIndex % 2 === 0) {
return {
backgroundColor: '#81c784'
};
}
return {
backgroundColor: '#c8e6c9'
};
}
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{
dataField: 'id',
text: 'Product ID',
style: {
fontWeight: 'bold',
fontSize: '18px'
}
}, {
dataField: 'name',
text: 'Product Name',
style: (cell, row, rowIndex, colIndex) => {
if (rowIndex % 2 === 0) {
return {
backgroundColor: '#81c784'
};
}
return {
backgroundColor: '#c8e6c9'
};
}
}, {
dataField: 'price',
text: 'Product Price'
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } />
`;
export default () => (
<div>
<BootstrapTable keyField="id" data={ products } columns={ columns } />
<Code>{ sourceCode }</Code>
</div>
);

View File

@ -0,0 +1,46 @@
/* eslint no-unused-vars: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID',
title: true
}, {
dataField: 'name',
text: 'Product Name',
title: (cell, row, rowIndex, colIndex) => `this is custom title for ${cell}`
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
const columns = [{
dataField: 'id',
text: 'Product ID',
title: true
}, {
dataField: 'name',
text: 'Product Name',
title: (cell, row, rowIndex, colIndex) => \`this is custom title for \${cell}\`
}, {
dataField: 'price',
text: 'Product Price'
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } />
`;
export default () => (
<div>
<h3>Try to hover on any Product Name cells</h3>
<BootstrapTable keyField="id" data={ products } columns={ columns } />
<Code>{ sourceCode }</Code>
</div>
);

View File

@ -0,0 +1,62 @@
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(5, (value, index) => ({
id: index,
name: `User Name ${index}`,
phone: 21009831 + index,
address: {
city: 'New York',
postCode: '1111-4512'
}
}));
const columns = [{
dataField: 'id',
text: 'User ID'
}, {
dataField: 'name',
text: 'User Name'
}, {
dataField: 'phone',
text: 'Phone'
}, {
dataField: 'address.city',
text: 'City'
}, {
dataField: 'address.postCode',
text: 'PostCode'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{
dataField: 'id',
text: 'User ID'
}, {
dataField: 'name',
text: 'User Name'
}, {
dataField: 'phone',
text: 'Phone'
}, {
dataField: 'address.city',
text: 'City'
}, {
dataField: 'address.postCode',
text: 'PostCode'
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } />
`;
export default () => (
<div>
<BootstrapTable keyField="id" data={ products } columns={ columns } />
<Code>{ sourceCode }</Code>
</div>
);

View File

@ -0,0 +1,47 @@
/* eslint no-unused-vars: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID',
headerAlign: 'center'
}, {
dataField: 'name',
text: 'Product Name',
headerAlign: (column, colIndex) => 'right'
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{
dataField: 'id',
text: 'Product ID',
headerAlign: 'center'
}, {
dataField: 'name',
text: 'Product Name',
headerAlign: (column, colIndex) => 'right'
}, {
dataField: 'price',
text: 'Product Price'
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } />
`;
export default () => (
<div>
<BootstrapTable keyField="id" data={ products } columns={ columns } />
<Code>{ sourceCode }</Code>
</div>
);

View File

@ -0,0 +1,47 @@
/* eslint no-unused-vars: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID',
headerAttrs: { title: 'ID header column' }
}, {
dataField: 'name',
text: 'Product Name',
headerAttrs: (column, colIndex) => ({ 'data-test': `customized data ${colIndex}` })
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{
dataField: 'id',
text: 'Product ID',
headerAttrs: { title: 'ID header column' }
}, {
dataField: 'name',
text: 'Product Name',
headerAttrs: (column, colIndex) => ({ 'data-test': \`customized data \${colIndex}\` })
}, {
dataField: 'price',
text: 'Product Price'
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } />
`;
export default () => (
<div>
<BootstrapTable keyField="id" data={ products } columns={ columns } />
<Code>{ sourceCode }</Code>
</div>
);

View File

@ -0,0 +1,53 @@
/* eslint no-unused-vars: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name',
headerClasses: 'demo-row-odd'
}, {
dataField: 'price',
text: 'Product Price',
headerClasses: (column, colIndex) => {
if (colIndex % 2 === 0) return 'demo-row-even';
return 'demo-row-odd';
}
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name',
headerClasses: 'demo-row-odd'
}, {
dataField: 'price',
text: 'Product Price',
headerClasses: (column, colIndex) => {
if (colIndex % 2 === 0) return 'demo-row-even';
return 'demo-row-odd';
}
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } />
`;
export default () => (
<div>
<BootstrapTable keyField="id" data={ products } columns={ columns } />
<Code>{ sourceCode }</Code>
</div>
);

View File

@ -0,0 +1,51 @@
/* eslint no-unused-vars: 0 */
/* eslint no-alert: 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',
headerEvents: {
onClick: () => alert('Click on Product ID header column')
}
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{
dataField: 'id',
text: 'Product ID',
events: {
onClick: () => alert('Click on Product ID header column')
}
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } />
`;
export default () => (
<div>
<h3>Try to Click on Product ID header column</h3>
<BootstrapTable keyField="id" data={ products } columns={ columns } />
<Code>{ sourceCode }</Code>
</div>
);

View File

@ -0,0 +1,91 @@
/* eslint no-unused-vars: 0 */
/* eslint react/prefer-stateless-function: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
function priceFormatter(column, colIndex, { sortElement, filterElement }) {
return (
<div style={ { display: 'flex', flexDirection: 'column' } }>
{ filterElement }
{ column.text }
{ sortElement }
</div>
);
}
const columns = [{
dataField: 'id',
text: 'Product ID',
sort: true
}, {
dataField: 'name',
text: 'Product Name',
sort: true
}, {
dataField: 'price',
text: 'Product Price',
sort: true,
filter: textFilter(),
headerFormatter: priceFormatter
}];
const defaultSorted = [{
dataField: 'name',
order: 'desc'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
// ...
function priceFormatter(column, colIndex, { sortElement, filterElement }) {
return (
<div style={ { display: 'flex', flexDirection: 'column' } }>
{ filterElement }
{ column.text }
{ sortElement }
</div>
);
}
const columns = [
// omit...
{
dataField: 'price',
text: 'Product Price',
sort: true,
filter: textFilter(),
headerFormatter: priceFormatter
}];
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
filter={ filterFactory() }
defaultSorted={ defaultSorted }
/>
`;
export default class DefaultSortTable extends React.PureComponent {
render() {
return (
<div>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
filter={ filterFactory() }
defaultSorted={ defaultSorted }
/>
<Code>{ sourceCode }</Code>
</div>
);
}
}

View File

@ -0,0 +1,61 @@
/* eslint no-unused-vars: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
function priceFormatter(column, colIndex) {
return (
<h5><strong>$$ { column.text } $$</strong></h5>
);
}
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price',
headerFormatter: priceFormatter
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
function priceFormatter(column, colIndex) {
return (
<h5><strong>$$ { column.text } $$</strong></h5>
);
}
const columns = [
// omit...
{
dataField: 'price',
text: 'Product Price',
headerFormatter: priceFormatter
}];
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
/>
`;
export default () => (
<div>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
/>
<Code>{ sourceCode }</Code>
</div>
);

View File

@ -0,0 +1,69 @@
/* eslint no-unused-vars: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name',
headerStyle: {
backgroundColor: '#c8e6c9'
}
}, {
dataField: 'price',
text: 'Product Price',
headerStyle: (column, colIndex) => {
if (colIndex % 2 === 0) {
return {
backgroundColor: '#81c784'
};
}
return {
backgroundColor: '#c8e6c9'
};
}
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name',
headerStyle: {
backgroundColor: '#c8e6c9'
}
}, {
dataField: 'price',
text: 'Product Price',
headerStyle: (column, colIndex) => {
if (colIndex % 2 === 0) {
return {
backgroundColor: '#81c784'
};
}
return {
backgroundColor: '#c8e6c9'
};
}
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } />
`;
export default () => (
<div>
<BootstrapTable keyField="id" data={ products } columns={ columns } />
<Code>{ sourceCode }</Code>
</div>
);

View File

@ -0,0 +1,47 @@
/* eslint no-unused-vars: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID',
headerTitle: true
}, {
dataField: 'name',
text: 'Product Name',
headerTitle: (column, colIndex) => `this is custom title for ${column.text}`
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{
dataField: 'id',
text: 'Product ID',
headerTitle: true
}, {
dataField: 'name',
text: 'Product Name',
headerTitle: (column, colIndex) => \`this is custom title for \${column.text}\`
}, {
dataField: 'price',
text: 'Product Price'
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } />
`;
export default () => (
<div>
<BootstrapTable keyField="id" data={ products } columns={ columns } />
<Code>{ sourceCode }</Code>
</div>
);

View File

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

View File

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

View File

@ -0,0 +1,82 @@
/* eslint react/prefer-stateless-function: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import paginationFactory from 'react-bootstrap-table2-paginator';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator(87);
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import paginationFactory from 'react-bootstrap-table2-paginator';
// ...
const options = {
paginationSize: 4,
pageStartIndex: 0,
// alwaysShowAllBtns: true, // Always show next and previous button
// withFirstAndLast: false, // Hide the going to First and Last page button
// hideSizePerPage: true, // Hide the sizePerPage dropdown always
// hidePageListOnlyOnePage: true, // Hide the pagination list when only one page
firstPageText: 'First',
prePageText: 'Back',
nextPageText: 'Next',
lastPageText: 'Last',
nextPageTitle: 'First page',
prePageTitle: 'Pre page',
firstPageTitle: 'Next page',
lastPageTitle: 'Last page',
sizePerPageList: [{
text: '5', value: 5
}, {
text: '10', value: 10
}, {
text: 'All', value: products.length
}] // A numeric array is also available. the purpose of above example is custom the text
};
<BootstrapTable keyField='id' data={ products } columns={ columns } pagination={ paginationFactory(options) } />
`;
const options = {
paginationSize: 4,
pageStartIndex: 0,
// alwaysShowAllBtns: true // Always show next and previous button
// withFirstAndLast: false // Hide the going to First and Last page button
// hideSizePerPage: true, // Hide the sizePerPage dropdown always
// hidePageListOnlyOnePage: true, // Hide the pagination list when only one page
firstPageText: 'First',
prePageText: 'Back',
nextPageText: 'Next',
lastPageText: 'Last',
nextPageTitle: 'First page',
prePageTitle: 'Pre page',
firstPageTitle: 'Next page',
lastPageTitle: 'Last page',
sizePerPageList: [{
text: '5', value: 5
}, {
text: '10', value: 10
}, {
text: 'All', value: products.length
}] // A numeric array is also available. the purpose of above example is custom the text
};
export default () => (
<div>
<BootstrapTable keyField="id" data={ products } columns={ columns } pagination={ paginationFactory(options) } />
<Code>{ sourceCode }</Code>
</div>
);

View File

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

View File

@ -0,0 +1,82 @@
/* eslint react/prefer-stateless-function: 0 */
/* eslint no-console: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import paginationFactory from 'react-bootstrap-table2-paginator';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator(87);
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import paginationFactory from 'react-bootstrap-table2-paginator';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const options = {
onSizePerPageChange: (sizePerPage, page) => {
console.log('Size per page change!!!');
console.log('Newest size per page:' + sizePerPage);
console.log('Newest page:' + page);
},
onPageChange: (page, sizePerPage) => {
console.log('Page change!!!');
console.log('Newest size per page:' + sizePerPage);
console.log('Newest page:' + page);
}
};
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
pagination={ paginationFactory(options) }
/>
`;
const options = {
onSizePerPageChange: (sizePerPage, page) => {
console.log('Size per page change!!!');
console.log(`Newest size per page: ${sizePerPage}`);
console.log(`Newest page: ${page}`);
},
onPageChange: (page, sizePerPage) => {
console.log('Page change!!!');
console.log(`Newest size per page: ${sizePerPage}`);
console.log(`Newest page: ${page}`);
}
};
export default () => (
<div>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
pagination={ paginationFactory(options) }
/>
<Code>{ sourceCode }</Code>
</div>
);

View File

@ -0,0 +1,202 @@
/* eslint guard-for-in: 0 */
/* eslint no-restricted-syntax: 0 */
import React from 'react';
import PropTypes from 'prop-types';
import BootstrapTable from 'react-bootstrap-table-next';
import paginationFactory from 'react-bootstrap-table2-paginator';
import filterFactory, { textFilter, Comparator } from 'react-bootstrap-table2-filter';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator(87);
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name',
filter: textFilter()
}, {
dataField: 'price',
text: 'Product Price',
filter: textFilter()
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import paginationFactory from 'react-bootstrap-table2-paginator';
import filterFactory, { textFilter, Comparator } from 'react-bootstrap-table2-filter';
// ...
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name',
filter: textFilter()
}, {
dataField: 'price',
text: 'Product Price',
filter: textFilter()
}];
const RemoteAll = ({ data, page, sizePerPage, onTableChange, totalSize }) => (
<div>
<BootstrapTable
remote={ { pagination: true } }
keyField="id"
data={ data }
columns={ columns }
filter={ filterFactory() }
pagination={ paginationFactory({ page, sizePerPage, totalSize }) }
onTableChange={ onTableChange }
/>
<Code>{ sourceCode }</Code>
</div>
);
RemoteAll.propTypes = {
data: PropTypes.array.isRequired,
page: PropTypes.number.isRequired,
totalSize: PropTypes.number.isRequired,
sizePerPage: PropTypes.number.isRequired,
onTableChange: PropTypes.func.isRequired
};
class Container extends React.Component {
constructor(props) {
super(props);
this.state = {
page: 1,
data: products.slice(0, 10),
totalSize: products.length,
sizePerPage: 10
};
this.handleTableChange = this.handleTableChange.bind(this);
}
handleTableChange = (type, { page, sizePerPage, filters }) => {
const currentIndex = (page - 1) * sizePerPage;
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(() => ({
page,
data: result.slice(currentIndex, currentIndex + sizePerPage),
totalSize: result.length,
sizePerPage
}));
}, 2000);
}
render() {
const { data, sizePerPage, page } = this.state;
return (
<RemoteAll
data={ data }
page={ page }
sizePerPage={ sizePerPage }
totalSize={ this.state.totalSize }
onTableChange={ this.handleTableChange }
/>
);
}
}
`;
const RemoteAll = ({ data, page, sizePerPage, onTableChange, totalSize }) => (
<div>
<h3>When <code>remote.pagination</code> is enabled, the filtering,
sorting and searching will also change to remote mode automatically</h3>
<BootstrapTable
remote={ { pagination: true } }
keyField="id"
data={ data }
columns={ columns }
filter={ filterFactory() }
pagination={ paginationFactory({ page, sizePerPage, totalSize }) }
onTableChange={ onTableChange }
/>
<Code>{ sourceCode }</Code>
</div>
);
RemoteAll.propTypes = {
data: PropTypes.array.isRequired,
page: PropTypes.number.isRequired,
totalSize: PropTypes.number.isRequired,
sizePerPage: PropTypes.number.isRequired,
onTableChange: PropTypes.func.isRequired
};
class Container extends React.Component {
constructor(props) {
super(props);
this.state = {
page: 1,
data: products.slice(0, 10),
totalSize: products.length,
sizePerPage: 10
};
this.handleTableChange = this.handleTableChange.bind(this);
}
handleTableChange = (type, { page, sizePerPage, filters }) => {
const currentIndex = (page - 1) * sizePerPage;
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(() => ({
page,
data: result.slice(currentIndex, currentIndex + sizePerPage),
totalSize: result.length,
sizePerPage
}));
}, 2000);
}
render() {
const { data, sizePerPage, page } = this.state;
return (
<RemoteAll
data={ data }
page={ page }
sizePerPage={ sizePerPage }
totalSize={ this.state.totalSize }
onTableChange={ this.handleTableChange }
/>
);
}
}
export default Container;

View File

@ -0,0 +1,164 @@
import React from 'react';
import PropTypes from 'prop-types';
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor';
// ...
const RemoteCellEdit = (props) => {
const cellEdit = {
mode: 'click',
errorMessage: props.errorMessage
};
return (
<div>
<BootstrapTable
remote={ { cellEdit: true } }
keyField="id"
data={ props.data }
columns={ columns }
cellEdit={ cellEditFactory(cellEdit) }
onTableChange={ props.onTableChange }
/>
<Code>{ sourceCode }</Code>
</div>
);
};
class Container extends React.Component {
constructor(props) {
super(props);
this.state = {
data: products,
errorMessage: null
};
}
handleTableChange = (type, { data, cellEdit: { rowId, dataField, newValue } }) => {
setTimeout(() => {
if (newValue === 'test' && dataField === 'name') {
this.setState(() => ({
data,
errorMessage: 'Oops, product name shouldn't be "test"'
}));
} else {
const result = data.map((row) => {
if (row.id === rowId) {
const newRow = { ...row };
newRow[dataField] = newValue;
return newRow;
}
return row;
});
this.setState(() => ({
data: result,
errorMessage: null
}));
}
}, 2000);
}
render() {
return (
<RemoteCellEdit
data={ this.state.data }
errorMessage={ this.state.errorMessage }
onTableChange={ this.handleTableChange }
/>
);
}
}
`;
const RemoteCellEdit = (props) => {
const cellEdit = {
mode: 'click',
errorMessage: props.errorMessage
};
return (
<div>
<BootstrapTable
remote={ { cellEdit: true } }
keyField="id"
data={ props.data }
columns={ columns }
cellEdit={ cellEditFactory(cellEdit) }
onTableChange={ props.onTableChange }
/>
<Code>{ sourceCode }</Code>
</div>
);
};
RemoteCellEdit.propTypes = {
data: PropTypes.array.isRequired,
onTableChange: PropTypes.func.isRequired,
errorMessage: PropTypes.string.isRequired
};
class Container extends React.Component {
constructor(props) {
super(props);
this.state = {
data: products,
errorMessage: null
};
}
handleTableChange = (type, { data, cellEdit: { rowId, dataField, newValue } }) => {
setTimeout(() => {
if (newValue === 'test' && dataField === 'name') {
this.setState(() => ({
data,
errorMessage: 'Oops, product name shouldn\'t be "test"'
}));
} else {
const result = data.map((row) => {
if (row.id === rowId) {
const newRow = { ...row };
newRow[dataField] = newValue;
return newRow;
}
return row;
});
this.setState(() => ({
data: result,
errorMessage: null
}));
}
}, 2000);
}
render() {
return (
<RemoteCellEdit
data={ this.state.data }
errorMessage={ this.state.errorMessage }
onTableChange={ this.handleTableChange }
/>
);
}
}
export default Container;

View File

@ -0,0 +1,160 @@
/* eslint guard-for-in: 0 */
/* eslint no-restricted-syntax: 0 */
import React from 'react';
import PropTypes from 'prop-types';
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { textFilter, Comparator } from 'react-bootstrap-table2-filter';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator(17);
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name',
filter: textFilter()
}, {
dataField: 'price',
text: 'Product Price',
filter: textFilter()
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
const columns = [{
dataField: 'id',
text: 'Product ID',
}, {
dataField: 'name',
text: 'Product Name',
filter: textFilter()
}, {
dataField: 'price',
text: 'Product Price',
filter: textFilter()
}];
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 => (
<div>
<BootstrapTable
remote={ { filter: true } }
keyField="id"
data={ props.data }
columns={ columns }
filter={ filterFactory() }
onTableChange={ props.onTableChange }
/>
<Code>{ sourceCode }</Code>
</div>
);
RemoteFilter.propTypes = {
data: PropTypes.array.isRequired,
onTableChange: PropTypes.func.isRequired
};
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 }
/>
);
}
}
export default Container;

View File

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

View File

@ -0,0 +1,163 @@
/* eslint no-restricted-syntax: 0 */
import React from 'react';
import PropTypes from 'prop-types';
import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator(5);
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name',
sort: true
}, {
dataField: 'price',
text: 'Product Price',
sort: true
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{
dataField: 'id',
text: 'Product ID',
}, {
dataField: 'name',
text: 'Product Name',
filter: textFilter()
}, {
dataField: 'price',
text: 'Product Price',
filter: textFilter()
}];
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 => (
<div>
<BootstrapTable
remote={ { sort: true } }
keyField="id"
data={ props.data }
columns={ columns }
onTableChange={ props.onTableChange }
/>
<Code>{ sourceCode }</Code>
</div>
);
RemoteSort.propTypes = {
data: PropTypes.array.isRequired,
onTableChange: PropTypes.func.isRequired
};
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 }
/>
);
}
}
export default Container;

View File

@ -0,0 +1,72 @@
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const selectRow = {
mode: 'checkbox',
clickToSelect: true,
clickToEdit: true
};
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const selectRow = {
mode: 'checkbox',
clickToSelect: true,
clickToEdit: true // Click to edit cell also
};
const cellEdit = {
mode: 'click'
};
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
selectRow={ selectRow }
cellEdit={ cellEditFactory({ mode: 'click' }) }
/>
`;
export default () => (
<div>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
selectRow={ selectRow }
cellEdit={ cellEditFactory({ mode: 'click' }) }
/>
<Code>{ sourceCode }</Code>
</div>
);

View File

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

View File

@ -0,0 +1,61 @@
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const selectRow = {
mode: 'checkbox',
clickToSelect: true,
hideSelectColumn: true,
bgColor: '#00BFFF'
};
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const selectRow = {
mode: 'checkbox',
clickToSelect: true,
hideSelectColumn: true,
bgColor: '#00BFFF'
};
<BootstrapTable
keyField='id'
data={ products }
columns={ columns }
selectRow={ selectRow }
/>
`;
export default () => (
<div>
<BootstrapTable keyField="id" data={ products } columns={ columns } selectRow={ selectRow } />
<Code>{ sourceCode }</Code>
</div>
);

View File

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

View File

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

View File

@ -0,0 +1,94 @@
/* eslint no-unused-vars: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const selectRow1 = {
mode: 'checkbox',
clickToSelect: true,
bgColor: '#00BFFF'
};
const selectRow2 = {
mode: 'checkbox',
clickToSelect: true,
bgColor: (row, rowIndex) => (rowIndex > 1 ? '#00BFFF' : '#00FFFF')
};
const sourceCode1 = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const selectRow = {
mode: 'checkbox',
clickToSelect: true,
bgColor: '#00BFFF'
};
<BootstrapTable
keyField='id'
data={ products }
columns={ columns }
selectRow={ selectRow }
/>
`;
const sourceCode2 = `\
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const selectRow = {
mode: 'checkbox',
clickToSelect: true,
bgColor: (row, rowIndex) => (rowIndex > 1 ? '#00BFFF' : '#00FFFF')
};
<BootstrapTable
keyField='id'
data={ products }
columns={ columns }
selectRow={ selectRow }
/>
`;
export default () => (
<div>
<BootstrapTable keyField="id" data={ products } columns={ columns } selectRow={ selectRow1 } />
<Code>{ sourceCode1 }</Code>
<BootstrapTable keyField="id" data={ products } columns={ columns } selectRow={ selectRow2 } />
<Code>{ sourceCode2 }</Code>
</div>
);

View File

@ -0,0 +1,96 @@
/* eslint no-unused-vars: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const selectRow1 = {
mode: 'checkbox',
clickToSelect: true,
classes: 'selection-row'
};
const selectRow2 = {
mode: 'checkbox',
clickToSelect: true,
classes: (row, rowIndex) =>
(rowIndex > 1 ? 'row-index-bigger-than-2101' : 'row-index-small-than-2101')
};
const sourceCode1 = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const selectRow = {
mode: 'checkbox',
clickToSelect: true,
classes: 'selection-row'
};
<BootstrapTable
keyField='id'
data={ products }
columns={ columns }
selectRow={ selectRow }
/>
`;
const sourceCode2 = `\
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const selectRow = {
mode: 'checkbox',
clickToSelect: true,
classes: (row, rowIndex) =>
(rowIndex > 1 ? 'row-index-bigger-than-2101' : 'row-index-small-than-2101')
};
<BootstrapTable
keyField='id'
data={ products }
columns={ columns }
selectRow={ selectRow }
/>
`;
export default () => (
<div>
<BootstrapTable keyField="id" data={ products } columns={ columns } selectRow={ selectRow1 } />
<Code>{ sourceCode1 }</Code>
<BootstrapTable keyField="id" data={ products } columns={ columns } selectRow={ selectRow2 } />
<Code>{ sourceCode2 }</Code>
</div>
);

View File

@ -0,0 +1,68 @@
/* 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'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const selectRow = {
mode: 'checkbox',
clickToSelect: true,
onSelect: (row, isSelect, rowIndex) => {
console.log(row.id);
console.log(isSelect);
console.log(rowIndex);
},
onSelectAll: (isSelect, rows) => {
console.log(isSelect);
console.log(rows);
}
};
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const selectRow = {
mode: 'checkbox',
clickToSelect: true
};
<BootstrapTable
keyField='id'
data={ products }
columns={ columns }
selectRow={ selectRow }
/>
`;
export default () => (
<div>
<BootstrapTable keyField="id" data={ products } columns={ columns } selectRow={ selectRow } />
<Code>{ sourceCode }</Code>
</div>
);

View File

@ -0,0 +1,100 @@
/* eslint no-unused-vars: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const selectRow1 = {
mode: 'checkbox',
clickToSelect: true,
style: { backgroundColor: '#c8e6c9' }
};
const selectRow2 = {
mode: 'checkbox',
clickToSelect: true,
style: (row, rowIndex) => {
const backgroundColor = rowIndex > 1 ? '#00BFFF' : '#00FFFF';
return { backgroundColor };
}
};
const sourceCode1 = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const selectRow = {
mode: 'checkbox',
clickToSelect: true,
style: { backgroundColor: '#c8e6c9' }
};
<BootstrapTable
keyField='id'
data={ products }
columns={ columns }
selectRow={ selectRow }
/>
`;
const sourceCode2 = `\
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const selectRow = {
mode: 'checkbox',
clickToSelect: true,
style: (row, rowIndex) => {
const backgroundColor = rowIndex > 1 ? '#00BFFF' : '#00FFFF';
return { backgroundColor };
}
};
<BootstrapTable
keyField='id'
data={ products }
columns={ columns }
selectRow={ selectRow }
/>
`;
export default () => (
<div>
<BootstrapTable keyField="id" data={ products } columns={ columns } selectRow={ selectRow1 } />
<Code>{ sourceCode1 }</Code>
<BootstrapTable keyField="id" data={ products } columns={ columns } selectRow={ selectRow2 } />
<Code>{ sourceCode2 }</Code>
</div>
);

View File

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

View File

@ -0,0 +1,83 @@
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const rowClasses1 = 'custom-row-class';
const sourceCode1 = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const rowClasses = 'custom-row-class';
<BootstrapTable keyField='id' data={ products } columns={ columns } rowClasses={ rowClasses } />
`;
const rowClasses2 = (row, rowIndex) => {
let classes = null;
if (rowIndex > 2) {
classes = 'index-bigger-than-two';
}
return classes;
};
const sourceCode2 = `\
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const rowClasses = (row, rowIndex) => {
let classes = null;
if (rowIndex > 2) {
classes = 'index-bigger-than-two';
}
return classes;
};
<BootstrapTable keyField='id' data={ products } columns={ columns } rowClasses={ rowClasses } />
`;
export default () => (
<div>
<BootstrapTable keyField="id" data={ products } columns={ columns } rowClasses={ rowClasses1 } />
<Code>{ sourceCode1 }</Code>
<BootstrapTable keyField="id" data={ products } columns={ columns } rowClasses={ rowClasses2 } />
<Code>{ sourceCode2 }</Code>
</div>
);

View File

@ -0,0 +1,57 @@
/* eslint no-unused-vars: 0 */
/* eslint no-alert: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const rowEvents = {
onClick: (e) => {
alert('click on row');
}
};
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const rowEvents = {
onClick: (e) => {
alert('click on row');
}
};
<BootstrapTable keyField='id' data={ products } columns={ columns } rowEvents={ rowEvents } />
`;
export default () => (
<div>
<h3>Try to click on any rows</h3>
<BootstrapTable keyField="id" data={ products } columns={ columns } rowEvents={ rowEvents } />
<Code>{ sourceCode }</Code>
</div>
);

View File

@ -0,0 +1,95 @@
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const rowStyle1 = { backgroundColor: '#c8e6c9' };
const sourceCode1 = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const rowStyle = { backgroundColor: '#c8e6c9' };
<BootstrapTable keyField='id' data={ products } columns={ columns } rowStyle={ rowStyle } />
`;
const rowStyle2 = (row, rowIndex) => {
const style = {};
if (row.id > 3) {
style.backgroundColor = '#c8e6c9';
} else {
style.backgroundColor = '#00BFFF';
}
if (rowIndex > 2) {
style.fontWeight = 'bold';
style.color = 'white';
}
return style;
};
const sourceCode2 = `\
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const rowStyle2 = (row, rowIndex) => {
const style = {};
if (row.id > 3) {
style.backgroundColor = '#c8e6c9';
} else {
style.backgroundColor = '#00BFFF';
}
if (rowIndex > 2) {
style.fontWeight = 'bold';
style.color = 'white';
}
return style;
};
<BootstrapTable keyField='id' data={ products } columns={ columns } rowStyle={ rowStyle2 } />
`;
export default () => (
<div>
<BootstrapTable keyField="id" data={ products } columns={ columns } rowStyle={ rowStyle1 } />
<Code>{ sourceCode1 }</Code>
<BootstrapTable keyField="id" data={ products } columns={ columns } rowStyle={ rowStyle2 } />
<Code>{ sourceCode2 }</Code>
</div>
);

View File

@ -0,0 +1,63 @@
/* eslint no-unused-vars: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID',
sort: true,
// here, we implement a custom sort which perform a reverse sorting
sortFunc: (a, b, order, dataField) => {
if (order === 'asc') {
return b - a;
}
return a - b; // desc
}
}, {
dataField: 'name',
text: 'Product Name',
sort: true
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [{
dataField: 'id',
text: 'Product ID',
sort: true,
// here, we implement a custom sort which perform a reverse sorting
sortFunc: (a, b, order, dataField) => {
if (order === 'asc') {
return b - a;
}
return a - b; // desc
}
}, {
dataField: 'name',
text: 'Product Name',
sort: true
}, {
dataField: 'price',
text: 'Product Price'
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } />
`;
export default () => (
<div>
<h3>Product ID sorting is reverted</h3>
<BootstrapTable keyField="id" data={ products } columns={ columns } />
<Code>{ sourceCode }</Code>
</div>
);

View File

@ -0,0 +1,71 @@
/* eslint react/prefer-stateless-function: 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
}, {
dataField: 'price',
text: 'Product Price',
sort: true
}];
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
}, {
dataField: 'price',
text: 'Product Price',
sort: true
}];
const defaultSorted = [{
dataField: 'name',
order: 'desc'
}];
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
defaultSorted={ defaultSorted }
/>
`;
class DefaultSortTable extends React.PureComponent {
render() {
return (
<div>
<BootstrapTable keyField="id" data={ products } columns={ columns } defaultSorted={ defaultSorted } />
<Code>{ sourceCode }</Code>
</div>
);
}
}
export default DefaultSortTable;

View File

@ -0,0 +1,46 @@
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
}, {
dataField: 'price',
text: 'Product Price'
}];
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
}, {
dataField: 'price',
text: 'Product Price'
}];
<BootstrapTable keyField='id' data={ products } columns={ columns } />
`;
export default () => (
<div>
<BootstrapTable keyField="id" data={ products } columns={ columns } />
<Code>{ sourceCode }</Code>
</div>
);

View File

@ -0,0 +1,63 @@
/* eslint
no-unused-vars: 0
arrow-body-style: 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 headerSortingClasses = (column, sortOrder, isLastSorting, colIndex) => (
sortOrder === 'asc' ? 'demo-sorting-asc' : 'demo-sorting-desc'
);
const columns = [{
dataField: 'id',
text: 'Product ID',
sort: true,
headerSortingClasses
}, {
dataField: 'name',
text: 'Product Name',
sort: true,
headerSortingClasses
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const headerSortingClasses = (column, sortOrder, isLastSorting, colIndex) => (
sortOrder === 'asc' ? 'demo-sorting-asc' : 'demo-sorting-desc'
);
const columns = [{
dataField: 'id',
text: 'Product ID',
sort: true,
headerSortingClasses
}, {
dataField: 'name',
text: 'Product Name',
sort: true,
headerSortingClasses
}, {
dataField: 'price',
text: 'Product Price'
}];
<BootstrapTable keyField="id" data={ products } columns={ columns } />
`;
export default () => (
<div>
<BootstrapTable keyField="id" data={ products } columns={ columns } />
<Code>{ sourceCode }</Code>
</div>
);

View File

@ -0,0 +1,56 @@
/* eslint no-unused-vars: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const headerSortingStyle = { backgroundColor: '#c8e6c9' };
const columns = [{
dataField: 'id',
text: 'Product ID',
sort: true,
headerSortingStyle
}, {
dataField: 'name',
text: 'Product Name',
sort: true,
headerSortingStyle
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const headerSortingStyle = { backgroundColor: '#c8e6c9' };
const columns = [{
dataField: 'id',
text: 'Product ID',
sort: true,
headerSortingStyle
}, {
dataField: 'name',
text: 'Product Name',
sort: true,
headerSortingStyle
}, {
dataField: 'price',
text: 'Product Price'
}];
<BootstrapTable keyField="id" data={ products } columns={ columns } />
`;
export default () => (
<div>
<BootstrapTable keyField="id" data={ products } columns={ columns } />
<Code>{ sourceCode }</Code>
</div>
);

View File

@ -0,0 +1,40 @@
import React from 'react';
import Typed from 'typed.js';
export default class Welcome extends React.Component {
componentDidMount() {
// type.js config
const options = {
strings: ['It\'s a bootstrap table rebuilt for React.js <span class="love-icon">♥</span>'],
typeSpeed: 50,
backSpeed: 50
};
this.typed = new Typed(this.el, options);
}
componentWillUnmount() {
// Make sure to destroy Typed instance on unmounting to prevent memory leaks
this.typed.destroy();
}
render() {
return (
<div>
<div className="welcome">
<h1 className="welcome-title">react-bootstrap-table2</h1>
<span
className="welcome-sub-title"
ref={ (el) => { this.el = el; } }
/>
</div>
<a href="https://github.com/react-bootstrap-table/react-bootstrap-table2" className="github-corner" aria-label="View source on Github">
<svg width="80" height="80" viewBox="0 0 250 250" style={ { fill: '#009688', color: '#fff', position: 'absolute', top: '0', border: '0', right: '0' } } aria-hidden="true">
<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z" />
<path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style={ { transformOrigin: '130px 106px' } } className="octo-arm" />
<path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" className="octo-body" />
</svg>
</a>
</div>
);
}
}

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