Compare commits

..

14 Commits

Author SHA1 Message Date
AllenFang
e1986e3e38 temp fix 2018-09-16 16:21:39 +08:00
AllenFang
41212fdc55 fixed wrong conflict fixs for #514 2018-09-05 23:20:36 +08:00
AllenFang
dffe588f66 fix cell level performace, remain select all 2018-09-05 23:01:13 +08:00
AllenFang
c3996f3f47 patch tests for refactoring cell edit with consumer 2018-09-04 00:19:54 +08:00
AllenFang
bf6f6087ba add story for dbclick to edit with row selection 2018-09-04 00:19:54 +08:00
AllenFang
c5c5a756cd refactoring cell edit consumer 2018-09-04 00:19:54 +08:00
AllenFang
2da6c8c622 no more expand row props resolver 2018-09-04 00:11:31 +08:00
AllenFang
dee92bd53d patch test for refining expand row consumer 2018-09-04 00:11:31 +08:00
AllenFang
7f7deff37f refine expand row consumer 2018-09-04 00:11:31 +08:00
AllenFang
9d4acaedd1 add story for combine selection and expansion 2018-09-04 00:11:31 +08:00
AllenFang
979189440a upgrade enzyme for new context API 2018-09-04 00:11:31 +08:00
AllenFang
6bf869c8a9 patch tests for refactoring row component with selection 2018-09-04 00:11:31 +08:00
AllenFang
c1de135fc2 patch row event example 2018-09-04 00:11:31 +08:00
AllenFang
e0a9f112e7 refine selection consumer 2018-09-04 00:11:31 +08:00
95 changed files with 867 additions and 2662 deletions

View File

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

View File

@@ -17,7 +17,6 @@
* [hover](#hover) * [hover](#hover)
* [condensed](#condensed) * [condensed](#condensed)
* [id](#id) * [id](#id)
* [tabIndexCell](#tabIndexCell)
* [classes](#classes) * [classes](#classes)
* [wrapperClasses](#wrapperClasses) * [wrapperClasses](#wrapperClasses)
* [headerClasses](#headerClasses) * [headerClasses](#headerClasses)
@@ -113,10 +112,6 @@ Same as bootstrap `.table-condensed` class for making a table more compact by cu
### <a name='id'>id - [String]</a> ### <a name='id'>id - [String]</a>
Customize id on `table` element. Customize id on `table` element.
### <a name='tabIndexCell'>tabIndexCell - [Bool]</a>
Enable the `tabIndex` attribute on `<td>` element.
### <a name='classes'>classes - [String]</a> ### <a name='classes'>classes - [String]</a>
Customize class on `table` element. Customize class on `table` element.

View File

@@ -10,7 +10,6 @@ $ npm install react-bootstrap-table2-editor --save
* [blurToSave](#blurToSave) * [blurToSave](#blurToSave)
* [nonEditableRows](#nonEditableRows) * [nonEditableRows](#nonEditableRows)
* [timeToCloseMessage](#timeToCloseMessage) * [timeToCloseMessage](#timeToCloseMessage)
* [autoSelectText](#autoSelectText)
* [beforeSaveCell](#beforeSaveCell) * [beforeSaveCell](#beforeSaveCell)
* [afterSaveCell](#afterSaveCell) * [afterSaveCell](#afterSaveCell)
* [errorMessage](#errorMessage) * [errorMessage](#errorMessage)
@@ -44,11 +43,6 @@ Default is `false`, enable it will be able to save the cell automatically when b
### <a name='nonEditableRows'>cellEdit.nonEditableRows - [Function]</a> ### <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`) `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='autoSelectText'>cellEdit.autoSelectText - [Bool]</a>
Default is false, when enable it, `react-bootstrap-table2` will help you to select the text in the text input automatically when editing.
> NOTE: This props only work for `text` and `textarea`.
### <a name='timeToCloseMessage'>cellEdit.timeToCloseMessage - [Function]</a> ### <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. 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.
@@ -62,24 +56,6 @@ const cellEdit = {
} }
``` ```
If you want to perform a async `beforeSaveCell`, you can do it like that:
```js
const cellEdit: {
// omit...
beforeSaveCell(oldValue, newValue, row, column, done) {
setTimeout(() => {
if (confirm('Do you want to accep this change?')) {
done(); // contine to save the changes
} else {
done(false); // reject the changes
}
}, 0);
return { async: true };
}
};
```
### <a name='afterSaveCell'>cellEdit.afterSaveCell - [Function]</a> ### <a name='afterSaveCell'>cellEdit.afterSaveCell - [Function]</a>
This callback function will be called after updating cell. This callback function will be called after updating cell.

View File

@@ -13,7 +13,6 @@ Available properties in a column object:
* [formatExtraData](#formatExtraData) * [formatExtraData](#formatExtraData)
* [sort](#sort) * [sort](#sort)
* [sortFunc](#sortFunc) * [sortFunc](#sortFunc)
* [sortCaret](#sortCaret)
* [onSort](#onSort) * [onSort](#onSort)
* [classes](#classes) * [classes](#classes)
* [style](#style) * [style](#style)
@@ -155,20 +154,6 @@ Enable the column sort via a `true` value given.
} }
``` ```
## <a name='sortCaret'>column.sortCaret - [Function]</a>
Use`column.sortCaret` to custom the sort caret. This callback function accept two arguments: `order` and `column`
```js
{
// omit...
sort: true,
sortCaret: (order, column) => {
return //...
}
}
```
> The possible value of `order` argument is **`asc`**, **`desc`** and **`undefined`**.
## <a name='classes'>column.classes - [String | Function]</a> ## <a name='classes'>column.classes - [String | Function]</a>
It's available to have custom class on table column: It's available to have custom class on table column:
@@ -379,27 +364,17 @@ A new `String` will be the result of element headerAlign.
## <a name='events'>column.events - [Object]</a> ## <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 `events` property. You can assign any [HTML Event](https://www.w3schools.com/tags/ref_eventattributes.asp) on table column via event property:
`react-bootstrap-table2` currently only support following events which will receive some specific information:
* onClick
* onDoubleClick
* onMouseEnter
* onMouseLeave
* onContextMenu
```js ```js
{ {
// omit... // omit...
events: { events: {
onClick: (e, column, columnIndex, row, rowIndex) => { ... }, onClick: e => { ... }
} }
} }
``` ```
If the events is not listed above, the callback function will only pass the `event` object.
## <a name='headerEvents'>column.headerEvents - [Object]</a> ## <a name='headerEvents'>column.headerEvents - [Object]</a>
`headerEvents` same as [`column.events`](#events) but this is for header column. `headerEvents` same as [`column.events`](#events) but this is for header column.
@@ -553,28 +528,6 @@ The return value can be a bool or an object. If your validation is pass, return
} }
``` ```
If you want to perform a asycn validation, you can do it like this:
```js
{
// omit...
validator: (newValue, row, column, done) => {
settimeout(() => {
// async validation ok
return done();
// async validation not ok
return done({
valid: false,
message: 'SOME_REASON_HERE'
});
}, 2000);
return { async: true };
}
}
```
## <a name='editCellStyle'>column.editCellStyle - [Object | Function]</a> ## <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: 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:

View File

@@ -3,7 +3,7 @@
### Setup ### Setup
```bash ```bash
$ git clone https://github.com/react-bootstrap-table/react-bootstrap-table2.git $ git clone https://github.com/react-bootstrap-table/react-bootstrap-table2.git
$ cd react-bootstrap-table2 $ cd react-bootstrap-table
$ npm install $ npm install
$ lerna bootstrap # ./node_modules/.bin/lerna bootstrap $ lerna bootstrap # ./node_modules/.bin/lerna bootstrap
``` ```
@@ -25,4 +25,4 @@ $ npm run storybook
$ npm test $ npm test
$ npm run test:watch # for watch mode $ npm run test:watch # for watch mode
$ npm run test:coverage # generate coverage report $ npm run test:coverage # generate coverage report
``` ```

View File

@@ -13,8 +13,6 @@
* [onExpand](#onExpand) * [onExpand](#onExpand)
* [onExpandAll](#onExpandAll) * [onExpandAll](#onExpandAll)
* [showExpandColumn](#showExpandColumn) * [showExpandColumn](#showExpandColumn)
* [onlyOneExpanding](#onlyOneExpanding)
* [expandByColumnOnly](#expandByColumnOnly)
* [expandColumnRenderer](#expandColumnRenderer) * [expandColumnRenderer](#expandColumnRenderer)
* [expandHeaderColumnRenderer](#expandHeaderColumnRenderer) * [expandHeaderColumnRenderer](#expandHeaderColumnRenderer)
@@ -129,24 +127,3 @@ const expandRow = {
showExpandColumn: true showExpandColumn: true
}; };
``` ```
### <a name='onlyOneExpanding'>expandRow.onlyOneExpanding - [Bool]</a>
Default is `false`. Enable this will only allow one row get expand at the same time.
```js
const expandRow = {
renderer: (row) => ...
onlyOneExpanding: true
};
```
### <a name='expandByColumnOnly'>expandRow.expandByColumnOnly - [Bool]</a>
Default is `false`. If you want to restrict user to expand/collapse row via clicking the expand column only, you can enable it.
```js
const expandRow = {
renderer: (row) => ...,
showExpandColumn: true,
expandByColumnOnly: true
};
```

View File

@@ -12,12 +12,10 @@
* [bgColor](#bgColor) * [bgColor](#bgColor)
* [nonSelectable)](#nonSelectable) * [nonSelectable)](#nonSelectable)
* [clickToSelect)](#clickToSelect) * [clickToSelect)](#clickToSelect)
* [clickToExpand)](#clickToExpand)
* [clickToEdit](#clickToEdit) * [clickToEdit](#clickToEdit)
* [onSelect](#onSelect) * [onSelect](#onSelect)
* [onSelectAll](#onSelectAll) * [onSelectAll](#onSelectAll)
* [hideSelectColumn](#hideSelectColumn) * [hideSelectColumn](#hideSelectColumn)
* [hideSelectAll](#hideSelectAll)
* [selectionRenderer](#selectionRenderer) * [selectionRenderer](#selectionRenderer)
* [selectionHeaderRenderer](#selectionHeaderRenderer) * [selectionHeaderRenderer](#selectionHeaderRenderer)
@@ -149,16 +147,6 @@ const selectRow = {
> Note: When you also enable [cellEdit](./cell-edit.md), the `selectRow.clickToSelect` will deactivate the functionality of cell editing > 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) > If you want to click on row to select row and edit cell simultaneously, you are suppose to enable [`selectRow.clickToEdit`](#clickToEdit)
### <a name='clickToExpand'>selectRow.clickToExpand - [Bool]</a>
Default is false, enable it will let user able to expand and select row when user clicking on the row.
```js
const selectRow = {
mode: 'checkbox',
clickToExpand: true
};
```
### <a name='clickToEdit'>selectRow.clickToEdit - [Bool]</a> ### <a name='clickToEdit'>selectRow.clickToEdit - [Bool]</a>
Able to click to edit cell and select row Able to click to edit cell and select row
@@ -211,44 +199,18 @@ const selectRow = {
}; };
``` ```
> If you want to reject current select action, just return `false`:
```js
const selectRow = {
mode: 'checkbox',
onSelect: (row, isSelect, rowIndex, e) => {
if (SOME_CONDITION) {
return false;
}
}
};
```
### <a name='onSelectAll'>selectRow.onSelectAll - [Function]</a> ### <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`. This callback function will be called when select/unselect all and it only work when you configure [`selectRow.mode`](#mode) as `checkbox`.
```js ```js
const selectRow = { const selectRow = {
mode: 'checkbox', mode: 'checkbox',
onSelectAll: (isSelect, rows, e) => { onSelectAll: (isSelect, results, e) => {
// ... // ...
} }
}; };
``` ```
> If you want to control the final selection result, just return a row key array:
```js
const selectRow = {
mode: 'checkbox',
onSelectAll: (isSelect, rows, e) => {
if (isSelect && SOME_CONDITION) {
return [1, 3, 4]; // finally, key 1, 3, 4 will being selected
}
}
};
```
### <a name='hideSelectColumn'>selectRow.hideSelectColumn - [Bool]</a> ### <a name='hideSelectColumn'>selectRow.hideSelectColumn - [Bool]</a>
Default is `false`, if you don't want to have a selection column, give this prop as `true` Default is `false`, if you don't want to have a selection column, give this prop as `true`
@@ -260,13 +222,3 @@ const selectRow = {
bgColor: 'red' bgColor: 'red'
}; };
``` ```
### <a name='hideSelectAll'>selectRow.hideSelectAll - [Bool]</a>
Default is `false`, if you don't want to render the select all checkbox on the header of selection column, give this prop as `true`!
```js
const selectRow = {
mode: 'checkbox',
hideSelectAll: true
};
```

View File

@@ -82,8 +82,8 @@
"dependencies": { "dependencies": {
"classnames": "2.2.5", "classnames": "2.2.5",
"prop-types": "15.5.10", "prop-types": "15.5.10",
"react": "16.4.0", "react": "16.3.2",
"react-dom": "16.4.0", "react-dom": "16.3.2",
"underscore": "1.9.1" "underscore": "1.9.1"
}, },
"jest": { "jest": {

View File

@@ -1,6 +1,6 @@
import createContext from './src/context'; import createContext from './src/context';
import withRowLevelCellEdit from './src/row-consumer'; import bindRowLevelCellEdit from './src/row-binder';
import createEditingCell from './src/editing-cell-consumer'; import createEditingCell from './src/editing-cell-binder';
import { import {
EDITTYPE, EDITTYPE,
DBCLICK_TO_CELL_EDIT, DBCLICK_TO_CELL_EDIT,
@@ -10,7 +10,7 @@ import {
export default (options = {}) => ({ export default (options = {}) => ({
createContext, createContext,
createEditingCell, createEditingCell,
withRowLevelCellEdit, bindRowLevelCellEdit,
DBCLICK_TO_CELL_EDIT, DBCLICK_TO_CELL_EDIT,
DELAY_FOR_DBCLICK, DELAY_FOR_DBCLICK,
options options

View File

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

View File

@@ -31,7 +31,6 @@ export default (
constructor(props) { constructor(props) {
super(props); super(props);
this.doUpdate = this.doUpdate.bind(this);
this.startEditing = this.startEditing.bind(this); this.startEditing = this.startEditing.bind(this);
this.escapeEditing = this.escapeEditing.bind(this); this.escapeEditing = this.escapeEditing.bind(this);
this.completeEditing = this.completeEditing.bind(this); this.completeEditing = this.completeEditing.bind(this);
@@ -56,36 +55,11 @@ export default (
} }
handleCellUpdate(row, column, newValue) { handleCellUpdate(row, column, newValue) {
const { cellEdit } = this.props;
const { beforeSaveCell } = cellEdit.options;
const oldValue = _.get(row, column.dataField);
const beforeSaveCellDone = (result = true) => {
if (result) {
this.doUpdate(row, column, newValue);
} else {
this.escapeEditing();
}
};
if (_.isFunction(beforeSaveCell)) {
const result = beforeSaveCell(
oldValue,
newValue,
row,
column,
beforeSaveCellDone
);
if (_.isObject(result) && result.async) {
return;
}
}
this.doUpdate(row, column, newValue);
}
doUpdate(row, column, newValue) {
const { keyField, cellEdit, data } = this.props; const { keyField, cellEdit, data } = this.props;
const { afterSaveCell } = cellEdit.options; const { beforeSaveCell, afterSaveCell } = cellEdit.options;
const rowId = _.get(row, keyField);
const oldValue = _.get(row, column.dataField); const oldValue = _.get(row, column.dataField);
const rowId = _.get(row, keyField);
if (_.isFunction(beforeSaveCell)) beforeSaveCell(oldValue, newValue, row, column);
if (isRemoteCellEdit()) { if (isRemoteCellEdit()) {
handleCellChange(rowId, column.dataField, newValue); handleCellChange(rowId, column.dataField, newValue);
} else { } else {

View File

@@ -24,7 +24,6 @@ export default (_, onStartEdit) =>
onUpdate: PropTypes.func.isRequired, onUpdate: PropTypes.func.isRequired,
onEscape: PropTypes.func.isRequired, onEscape: PropTypes.func.isRequired,
timeToCloseMessage: PropTypes.number, timeToCloseMessage: PropTypes.number,
autoSelectText: PropTypes.bool,
className: PropTypes.string, className: PropTypes.string,
style: PropTypes.object style: PropTypes.object
} }
@@ -32,7 +31,6 @@ export default (_, onStartEdit) =>
static defaultProps = { static defaultProps = {
timeToCloseMessage: TIME_TO_CLOSE_MESSAGE, timeToCloseMessage: TIME_TO_CLOSE_MESSAGE,
className: null, className: null,
autoSelectText: false,
style: {} style: {}
} }
@@ -44,8 +42,6 @@ export default (_, onStartEdit) =>
this.handleClick = this.handleClick.bind(this); this.handleClick = this.handleClick.bind(this);
this.handleKeyDown = this.handleKeyDown.bind(this); this.handleKeyDown = this.handleKeyDown.bind(this);
this.beforeComplete = this.beforeComplete.bind(this); this.beforeComplete = this.beforeComplete.bind(this);
this.asyncbeforeCompete = this.asyncbeforeCompete.bind(this);
this.displayErrorMessage = this.displayErrorMessage.bind(this);
this.state = { this.state = {
invalidMessage: null invalidMessage: null
}; };
@@ -81,41 +77,16 @@ export default (_, onStartEdit) =>
}, timeToCloseMessage); }, timeToCloseMessage);
} }
displayErrorMessage(message) {
this.setState(() => ({
invalidMessage: message
}));
this.createTimer();
}
asyncbeforeCompete(newValue) {
return (result = { valid: true }) => {
const { valid, message } = result;
const { onUpdate, row, column } = this.props;
if (!valid) {
this.displayErrorMessage(message);
return;
}
onUpdate(row, column, newValue);
};
}
beforeComplete(newValue) { beforeComplete(newValue) {
const { onUpdate, row, column } = this.props; const { onUpdate, row, column } = this.props;
if (_.isFunction(column.validator)) { if (_.isFunction(column.validator)) {
const validateForm = column.validator( const validateForm = column.validator(newValue, row, column);
newValue, if (_.isObject(validateForm) && !validateForm.valid) {
row, this.setState(() => ({
column, invalidMessage: validateForm.message
this.asyncbeforeCompete(newValue) }));
); this.createTimer();
if (_.isObject(validateForm)) { return;
if (validateForm.async) {
return;
} else if (!validateForm.valid) {
this.displayErrorMessage(validateForm.message);
return;
}
} }
} }
onUpdate(row, column, newValue); onUpdate(row, column, newValue);
@@ -150,7 +121,7 @@ export default (_, onStartEdit) =>
render() { render() {
let editor; let editor;
const { row, column, className, style, rowIndex, columnIndex, autoSelectText } = this.props; const { row, column, className, style, rowIndex, columnIndex } = this.props;
const { dataField } = column; const { dataField } = column;
const value = _.get(row, dataField); const value = _.get(row, dataField);
@@ -203,13 +174,13 @@ export default (_, onStartEdit) =>
} else if (isDefaultEditorDefined && column.editor.type === EDITTYPE.SELECT) { } else if (isDefaultEditorDefined && column.editor.type === EDITTYPE.SELECT) {
editor = <DropdownEditor { ...editorProps } />; editor = <DropdownEditor { ...editorProps } />;
} else if (isDefaultEditorDefined && column.editor.type === EDITTYPE.TEXTAREA) { } else if (isDefaultEditorDefined && column.editor.type === EDITTYPE.TEXTAREA) {
editor = <TextAreaEditor { ...editorProps } autoSelectText={ autoSelectText } />; editor = <TextAreaEditor { ...editorProps } />;
} else if (isDefaultEditorDefined && column.editor.type === EDITTYPE.CHECKBOX) { } else if (isDefaultEditorDefined && column.editor.type === EDITTYPE.CHECKBOX) {
editor = <CheckBoxEditor { ...editorProps } />; editor = <CheckBoxEditor { ...editorProps } />;
} else if (isDefaultEditorDefined && column.editor.type === EDITTYPE.DATE) { } else if (isDefaultEditorDefined && column.editor.type === EDITTYPE.DATE) {
editor = <DateEditor { ...editorProps } />; editor = <DateEditor { ...editorProps } />;
} else { } else {
editor = <TextEditor { ...editorProps } autoSelectText={ autoSelectText } />; editor = <TextEditor { ...editorProps } />;
} }
return ( return (

View File

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

View File

@@ -30,14 +30,9 @@ export default (Component, selectRowEnabled) => {
/> />
); );
}; };
function withConsumer(props) { return props => (
return ( <Consumer>
<Consumer> { cellEdit => renderWithCellEdit(props, cellEdit) }
{ cellEdit => renderWithCellEdit(props, cellEdit) } </Consumer>
</Consumer> );
);
}
withConsumer.displayName = 'WithCellEditingRowConsumer';
return withConsumer;
}; };

View File

@@ -5,10 +5,9 @@ import PropTypes from 'prop-types';
class TextEditor extends Component { class TextEditor extends Component {
componentDidMount() { componentDidMount() {
const { defaultValue, didMount, autoSelectText } = this.props; const { defaultValue, didMount } = this.props;
this.text.value = defaultValue; this.text.value = defaultValue;
this.text.focus(); this.text.focus();
if (autoSelectText) this.text.select();
if (didMount) didMount(); if (didMount) didMount();
} }
@@ -17,7 +16,7 @@ class TextEditor extends Component {
} }
render() { render() {
const { defaultValue, didMount, className, autoSelectText, ...rest } = this.props; const { defaultValue, didMount, className, ...rest } = this.props;
const editorClass = cs('form-control editor edit-text', className); const editorClass = cs('form-control editor edit-text', className);
return ( return (
<input <input
@@ -39,13 +38,11 @@ TextEditor.propTypes = {
PropTypes.string, PropTypes.string,
PropTypes.number PropTypes.number
]), ]),
autoSelectText: PropTypes.bool,
didMount: PropTypes.func didMount: PropTypes.func
}; };
TextEditor.defaultProps = { TextEditor.defaultProps = {
className: null, className: null,
defaultValue: '', defaultValue: '',
autoSelectText: false,
didMount: undefined didMount: undefined
}; };
export default TextEditor; export default TextEditor;

View File

@@ -10,10 +10,9 @@ class TextAreaEditor extends Component {
} }
componentDidMount() { componentDidMount() {
const { defaultValue, didMount, autoSelectText } = this.props; const { defaultValue, didMount } = this.props;
this.text.value = defaultValue; this.text.value = defaultValue;
this.text.focus(); this.text.focus();
if (autoSelectText) this.text.select();
if (didMount) didMount(); if (didMount) didMount();
} }
@@ -29,7 +28,7 @@ class TextAreaEditor extends Component {
} }
render() { render() {
const { defaultValue, didMount, className, autoSelectText, ...rest } = this.props; const { defaultValue, didMount, className, ...rest } = this.props;
const editorClass = cs('form-control editor edit-textarea', className); const editorClass = cs('form-control editor edit-textarea', className);
return ( return (
<textarea <textarea
@@ -53,13 +52,11 @@ TextAreaEditor.propTypes = {
PropTypes.number PropTypes.number
]), ]),
onKeyDown: PropTypes.func, onKeyDown: PropTypes.func,
autoSelectText: PropTypes.bool,
didMount: PropTypes.func didMount: PropTypes.func
}; };
TextAreaEditor.defaultProps = { TextAreaEditor.defaultProps = {
className: '', className: '',
defaultValue: '', defaultValue: '',
autoSelectText: false,
onKeyDown: undefined, onKeyDown: undefined,
didMount: undefined didMount: undefined
}; };

View File

@@ -0,0 +1,210 @@
import 'jsdom-global/register';
import React from 'react';
import { mount } from 'enzyme';
import _ from 'react-bootstrap-table-next/src/utils';
import op from 'react-bootstrap-table-next/src/store/operators';
import cellEditFactory from '../index';
import { CLICK_TO_CELL_EDIT, DBCLICK_TO_CELL_EDIT } from '../src/const';
import createCellEditContext from '../src/context';
import bindCellEditing from '../src/cell-binder';
describe('Cell Binder', () => {
let wrapper;
let cellEdit;
const data = [{
id: 1,
name: 'A'
}, {
id: 2,
name: 'B'
}];
let columns;
const rowIndex = 1;
const row = { id: 1, name: 'A' };
const keyField = 'id';
const columnIndex = 1;
const { Provider } = createCellEditContext(_, op, false, jest.fn());
const BaseComponent = () => null;
const WithCellEditComponent = bindCellEditing(
props => <BaseComponent { ...props } />,
keyField,
_
);
beforeEach(() => {
columns = [{
dataField: 'id',
text: 'ID'
}, {
dataField: 'name',
text: 'Name'
}];
});
describe(`if cellEdit.mode is ${CLICK_TO_CELL_EDIT}`, () => {
beforeEach(() => {
cellEdit = cellEditFactory({ mode: CLICK_TO_CELL_EDIT });
wrapper = mount(
<Provider data={ data } keyField={ keyField } cellEdit={ cellEdit }>
<WithCellEditComponent
row={ row }
column={ columns[1] }
rowIndex={ rowIndex }
columnIndex={ columnIndex }
/>
</Provider>
);
});
it('should inject correct props to target component', () => {
expect(wrapper.find(BaseComponent)).toHaveLength(1);
expect(wrapper.find(BaseComponent).prop('clickToEdit')).toBeTruthy();
expect(wrapper.find(BaseComponent).prop('dbclickToEdit')).toBeFalsy();
});
});
describe(`if cellEdit.mode is ${DBCLICK_TO_CELL_EDIT}`, () => {
beforeEach(() => {
cellEdit = cellEditFactory({ mode: DBCLICK_TO_CELL_EDIT });
wrapper = mount(
<Provider data={ data } keyField={ keyField } cellEdit={ cellEdit }>
<WithCellEditComponent
row={ row }
column={ columns[1] }
rowIndex={ rowIndex }
columnIndex={ columnIndex }
/>
</Provider>
);
});
it('should inject correct props to target component', () => {
expect(wrapper.find(BaseComponent)).toHaveLength(1);
expect(wrapper.find(BaseComponent).prop('clickToEdit')).toBeFalsy();
expect(wrapper.find(BaseComponent).prop('dbclickToEdit')).toBeTruthy();
});
});
describe('if column prop is a key column', () => {
beforeEach(() => {
cellEdit = cellEditFactory({ mode: CLICK_TO_CELL_EDIT });
wrapper = mount(
<Provider data={ data } keyField={ keyField } cellEdit={ cellEdit }>
<WithCellEditComponent
row={ row }
column={ columns[0] }
rowIndex={ rowIndex }
columnIndex={ columnIndex }
editable
/>
</Provider>
);
});
it('should inject negative editable prop to target component', () => {
expect(wrapper.find(BaseComponent)).toHaveLength(1);
expect(wrapper.find(BaseComponent).prop('editable')).toBeFalsy();
});
});
describe('if editable prop is true(Row Level)', () => {
describe('but column.editable prop is false', () => {
beforeEach(() => {
cellEdit = cellEditFactory({ mode: CLICK_TO_CELL_EDIT });
columns[1].editable = false;
wrapper = mount(
<Provider data={ data } keyField={ keyField } cellEdit={ cellEdit }>
<WithCellEditComponent
row={ row }
column={ columns[1] }
rowIndex={ rowIndex }
columnIndex={ columnIndex }
editable
/>
</Provider>
);
});
it('should inject negative editable prop to target component', () => {
expect(wrapper.find(BaseComponent)).toHaveLength(1);
expect(wrapper.find(BaseComponent).prop('editable')).toBeFalsy();
});
});
describe('and column.editable prop is true or not defined', () => {
beforeEach(() => {
cellEdit = cellEditFactory({ mode: CLICK_TO_CELL_EDIT });
wrapper = mount(
<Provider data={ data } keyField={ keyField } cellEdit={ cellEdit }>
<WithCellEditComponent
row={ row }
column={ columns[1] }
rowIndex={ rowIndex }
columnIndex={ columnIndex }
editable
/>
</Provider>
);
});
it('should inject positive editable prop to target component', () => {
expect(wrapper.find(BaseComponent)).toHaveLength(1);
expect(wrapper.find(BaseComponent).prop('editable')).toBeTruthy();
});
});
});
describe('if editable prop is false(Row Level)', () => {
describe('even if column.editable prop is true or not defined', () => {
beforeEach(() => {
cellEdit = cellEditFactory({ mode: CLICK_TO_CELL_EDIT });
columns[1].editable = true;
wrapper = mount(
<Provider data={ data } keyField={ keyField } cellEdit={ cellEdit }>
<WithCellEditComponent
row={ row }
column={ columns[1] }
rowIndex={ rowIndex }
columnIndex={ columnIndex }
editable={ false }
/>
</Provider>
);
});
it('should inject negative editable prop to target component', () => {
expect(wrapper.find(BaseComponent)).toHaveLength(1);
expect(wrapper.find(BaseComponent).prop('editable')).toBeFalsy();
});
});
});
describe('if column.editable prop is a function', () => {
beforeEach(() => {
cellEdit = cellEditFactory({ mode: CLICK_TO_CELL_EDIT });
columns[1].editable = jest.fn().mockReturnValue(false);
wrapper = mount(
<Provider data={ data } keyField={ keyField } cellEdit={ cellEdit }>
<WithCellEditComponent
row={ row }
column={ columns[1] }
rowIndex={ rowIndex }
columnIndex={ columnIndex }
editable
/>
</Provider>
);
});
it('should call column.editable function correctly', () => {
expect(columns[1].editable).toHaveBeenCalledTimes(1);
});
it('should inject correct editable prop to target component', () => {
expect(wrapper.find(BaseComponent)).toHaveLength(1);
expect(wrapper.find(BaseComponent).prop('editable')).toBeFalsy();
});
});
});

View File

@@ -235,8 +235,7 @@ describe('CellEditContext', () => {
it('should call cellEdit.beforeSaveCell correctly', () => { it('should call cellEdit.beforeSaveCell correctly', () => {
expect(beforeSaveCell).toHaveBeenCalledTimes(1); expect(beforeSaveCell).toHaveBeenCalledTimes(1);
expect(beforeSaveCell) expect(beforeSaveCell).toHaveBeenCalledWith(oldValue, newValue, row, column);
.toHaveBeenCalledWith(oldValue, newValue, row, column, expect.anything());
}); });
}); });

View File

@@ -3,12 +3,12 @@ import React from 'react';
import { mount, shallow } from 'enzyme'; import { mount, shallow } from 'enzyme';
import _ from 'react-bootstrap-table-next/src/utils'; import _ from 'react-bootstrap-table-next/src/utils';
import cellEditFactory from '..'; import cellEditFactory from '../index';
import { CLICK_TO_CELL_EDIT } from '../src/const'; import { CLICK_TO_CELL_EDIT } from '../src/const';
import createCellEditContext from '../src/context'; import createCellEditContext from '../src/context';
import bindEditingCell from '../src/editing-cell-consumer'; import bindEditingCell from '../src/editing-cell-binder';
describe('Editing Cell Consumer', () => { describe('Cell Binder', () => {
let wrapper; let wrapper;
let cellEdit; let cellEdit;
const data = [{ const data = [{

View File

@@ -4,12 +4,12 @@ import { mount } from 'enzyme';
import _ from 'react-bootstrap-table-next/src/utils'; import _ from 'react-bootstrap-table-next/src/utils';
import op from 'react-bootstrap-table-next/src/store/operators'; import op from 'react-bootstrap-table-next/src/store/operators';
import cellEditFactory from '..'; import cellEditFactory from '../index';
import { CLICK_TO_CELL_EDIT, DBCLICK_TO_CELL_EDIT, DELAY_FOR_DBCLICK } from '../src/const'; import { CLICK_TO_CELL_EDIT, DBCLICK_TO_CELL_EDIT, DELAY_FOR_DBCLICK } from '../src/const';
import createCellEditContext from '../src/context'; import createCellEditContext from '../src/context';
import withRowLevelCellEdit from '../src/row-consumer'; import bindCellEditing from '../src/row-binder';
describe('Row Consumer', () => { describe('Row Binder', () => {
let wrapper; let wrapper;
let cellEdit; let cellEdit;
const data = [{ const data = [{
@@ -28,7 +28,7 @@ describe('Row Consumer', () => {
describe('if cellEdit.nonEditableRows is undefined', () => { describe('if cellEdit.nonEditableRows is undefined', () => {
beforeEach(() => { beforeEach(() => {
const WithCellEditComponent = withRowLevelCellEdit( const WithCellEditComponent = bindCellEditing(
props => <BaseComponent { ...props } />, props => <BaseComponent { ...props } />,
false false
); );
@@ -52,7 +52,7 @@ describe('Row Consumer', () => {
const nonEditableRows = jest.fn().mockReturnValue([value]); const nonEditableRows = jest.fn().mockReturnValue([value]);
describe('if value prop is match in one of cellEdit.nonEditableRows', () => { describe('if value prop is match in one of cellEdit.nonEditableRows', () => {
beforeEach(() => { beforeEach(() => {
const WithCellEditComponent = withRowLevelCellEdit( const WithCellEditComponent = bindCellEditing(
props => <BaseComponent { ...props } />, props => <BaseComponent { ...props } />,
false false
); );
@@ -72,7 +72,7 @@ describe('Row Consumer', () => {
describe('if value prop is not match in one of cellEdit.nonEditableRows', () => { describe('if value prop is not match in one of cellEdit.nonEditableRows', () => {
beforeEach(() => { beforeEach(() => {
const WithCellEditComponent = withRowLevelCellEdit( const WithCellEditComponent = bindCellEditing(
props => <BaseComponent { ...props } />, props => <BaseComponent { ...props } />,
false false
); );
@@ -93,7 +93,7 @@ describe('Row Consumer', () => {
describe(`if selectRowEnabled argument is true and cellEdit.mode is ${DBCLICK_TO_CELL_EDIT}`, () => { describe(`if selectRowEnabled argument is true and cellEdit.mode is ${DBCLICK_TO_CELL_EDIT}`, () => {
beforeEach(() => { beforeEach(() => {
const WithCellEditComponent = withRowLevelCellEdit( const WithCellEditComponent = bindCellEditing(
props => <BaseComponent { ...props } />, props => <BaseComponent { ...props } />,
true true
); );
@@ -115,7 +115,7 @@ describe('Row Consumer', () => {
const ridx = 0; const ridx = 0;
const cidx = 1; const cidx = 1;
beforeEach(() => { beforeEach(() => {
const WithCellEditComponent = withRowLevelCellEdit( const WithCellEditComponent = bindCellEditing(
props => <BaseComponent { ...props } />, props => <BaseComponent { ...props } />,
false false
); );

View File

@@ -1,182 +0,0 @@
/* eslint no-return-assign: 0 */
/* eslint no-console: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import paginationFactory from 'react-bootstrap-table2-paginator';
import filterFactory, { textFilter } from 'react-bootstrap-table2-filter';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator(63);
const columns = [{
dataField: 'id',
text: 'Product ID',
sort: true
}, {
dataField: 'name',
text: 'Product Name',
sort: true,
filter: textFilter()
}, {
dataField: 'price',
text: 'Product Price',
sort: true,
filter: textFilter()
}];
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'
}];
class ExposedFunctionTable extends React.Component {
handleGetCurrentData = () => {
console.log(this.node.table.props.data);
}
handleGetSelectedData = () => {
console.log(this.node.selectionContext.state.selected);
}
handleGetExpandedData = () => {
console.log(this.node.rowExpandContext.state.expanded);
}
handleGetCurrentPage = () => {
console.log(this.node.paginationContext.currPage);
}
handleGetCurrentSizePerPage = () => {
console.log(this.node.paginationContext.currSizePerPage);
}
handleGetCurrentSortColumn = () => {
console.log(this.node.sortContext.state.sortColumn);
}
handleGetCurrentSortOrder = () => {
console.log(this.node.sortContext.state.sortOrder);
}
handleGetCurrentFilter = () => {
console.log(this.node.filterContext.currFilters);
}
render() {
const expandRow = {
renderer: row => (
<div>
<p>.....</p>
<p>You can render anything here, also you can add additional data on every row object</p>
<p>expandRow.renderer callback will pass the origin row object to you</p>
</div>
),
showExpandColumn: true
};
return (
<div>
<button className="btn btn-default" onClick={ this.handleGetCurrentData }>Get Current Display Rows</button>
<button className="btn btn-default" onClick={ this.handleGetSelectedData }>Get Current Selected Rows</button>
<button className="btn btn-default" onClick={ this.handleGetExpandedData }>Get Current Expanded Rows</button>
<button className="btn btn-default" onClick={ this.handleGetCurrentPage }>Get Current Page</button>
<button className="btn btn-default" onClick={ this.handleGetCurrentSizePerPage }>Get Current Size Per Page</button>
<button className="btn btn-default" onClick={ this.handleGetCurrentSortColumn }>Get Current Sort Column</button>
<button className="btn btn-default" onClick={ this.handleGetCurrentSortOrder }>Get Current Sort Order</button>
<button className="btn btn-default" onClick={ this.handleGetCurrentFilter }>Get Current Filter Information</button>
<BootstrapTable
ref={ n => this.node = n }
keyField="id"
data={ products }
columns={ columns }
filter={ filterFactory() }
pagination={ paginationFactory() }
selectRow={ { mode: 'checkbox', clickToSelect: true } }
expandRow={ expandRow }
/>
<Code>{ sourceCode }</Code>
</div>
);
}
}
`;
export default class ExposedFunctionTable extends React.Component {
handleGetCurrentData = () => {
console.log(this.node.table.props.data);
}
handleGetSelectedData = () => {
console.log(this.node.selectionContext.state.selected);
}
handleGetExpandedData = () => {
console.log(this.node.rowExpandContext.state.expanded);
}
handleGetCurrentPage = () => {
console.log(this.node.paginationContext.currPage);
}
handleGetCurrentSizePerPage = () => {
console.log(this.node.paginationContext.currSizePerPage);
}
handleGetCurrentSortColumn = () => {
console.log(this.node.sortContext.state.sortColumn);
}
handleGetCurrentSortOrder = () => {
console.log(this.node.sortContext.state.sortOrder);
}
handleGetCurrentFilter = () => {
console.log(this.node.filterContext.currFilters);
}
render() {
const expandRow = {
renderer: row => (
<div>
<p>{ `This Expand row is belong to rowKey ${row.id}` }</p>
<p>You can render anything here, also you can add additional data on every row object</p>
<p>expandRow.renderer callback will pass the origin row object to you</p>
</div>
),
showExpandColumn: true
};
return (
<div>
<button className="btn btn-default" onClick={ this.handleGetCurrentData }>Get Current Display Rows</button>
<button className="btn btn-default" onClick={ this.handleGetSelectedData }>Get Current Selected Rows</button>
<button className="btn btn-default" onClick={ this.handleGetExpandedData }>Get Current Expanded Rows</button>
<button className="btn btn-default" onClick={ this.handleGetCurrentPage }>Get Current Page</button>
<button className="btn btn-default" onClick={ this.handleGetCurrentSizePerPage }>Get Current Size Per Page</button>
<button className="btn btn-default" onClick={ this.handleGetCurrentSortColumn }>Get Current Sort Column</button>
<button className="btn btn-default" onClick={ this.handleGetCurrentSortOrder }>Get Current Sort Order</button>
<button className="btn btn-default" onClick={ this.handleGetCurrentFilter }>Get Current Filter Information</button>
<BootstrapTable
ref={ n => this.node = n }
keyField="id"
data={ products }
columns={ columns }
filter={ filterFactory() }
pagination={ paginationFactory() }
selectRow={ { mode: 'checkbox', clickToSelect: true } }
expandRow={ expandRow }
/>
<Code>{ sourceCode }</Code>
</div>
);
}
}

View File

@@ -1,9 +1,10 @@
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next'; import BootstrapTable from 'react-bootstrap-table-next';
// import cellEditFactory from 'react-bootstrap-table2-editor';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';
const products = productsGenerator(3000); const products = productsGenerator(2000);
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
@@ -16,25 +17,41 @@ const columns = [{
text: 'Product Price' text: 'Product Price'
}]; }];
const expandRow = { // cellEdit={ cellEditFactory({
showExpandColumn: true, // mode: 'click'
renderer: row => ( // }) }
<div>
<p>{ `This Expand row is belong to rowKey ${row.id}` }</p> // const expandRow = {
<p>You can render anything here, also you can add additional data on every row object</p> // renderer: row => (
<p>expandRow.renderer callback will pass the origin row object to you</p> // <div>
</div> // <p>{ `This Expand row is belong to rowKey ${row.id}` }</p>
) // <p>You can render anything here, also you can add additional data on every row object</p>
// <p>expandRow.renderer callback will pass the origin row object to you</p>
// </div>
// )
// };
const selectRow = {
mode: 'checkbox',
clickToSelect: true,
bgColor: 'red'
// selected: [2],
// hideSelectColumn: true
// clickToEdit: true
}; };
export default () => ( /* eslint react/prefer-stateless-function: 0 */
<div> export default class Table extends React.PureComponent {
<BootstrapTable render() {
keyField="id" return (
data={ products } <div>
columns={ columns } <BootstrapTable
selectRow={ { mode: 'checkbox', clickToSelect: true } } keyField="id"
expandRow={ expandRow } data={ products }
/> columns={ columns }
</div> selectRow={ selectRow }
); />
</div>
);
}
}

View File

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

View File

@@ -1,78 +0,0 @@
/* eslint react/prefer-stateless-function: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory, { Type } from 'react-bootstrap-table2-editor';
import Code from 'components/common/code-block';
import { jobsGenerator } from 'utils/common';
const jobs = jobsGenerator();
const columns = [{
dataField: 'id',
text: 'Job ID'
}, {
dataField: 'name',
text: 'Job Name'
}, {
dataField: 'owner',
text: 'Job Owner'
}, {
dataField: 'type',
text: 'Job Type',
editor: {
type: Type.TEXTAREA
}
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory, { Type } from 'react-bootstrap-table2-editor';
const columns = [{
dataField: 'id',
text: 'Job ID'
}, {
dataField: 'name',
text: 'Job Name'
}, {
dataField: 'owner',
text: 'Job Owner'
}, {
dataField: 'type',
text: 'Job Type',
editor: {
type: Type.TEXTAREA
}
}];
<BootstrapTable
keyField="id"
data={ jobs }
columns={ columns }
cellEdit={
cellEditFactory({
mode: 'click',
autoSelectText: true
})
}
/>
`;
export default () => (
<div>
<h3>Auto Select Text Input Field When Editing</h3>
<BootstrapTable
keyField="id"
data={ jobs }
columns={ columns }
cellEdit={
cellEditFactory({
mode: 'click',
autoSelectText: true
})
}
/>
<Code>{ sourceCode }</Code>
</div>
);

View File

@@ -1,86 +0,0 @@
/* eslint no-unused-vars: 0 */
/* eslint no-console: 0 */
/* eslint no-alert: 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'
}];
function beforeSaveCell(oldValue, newValue, row, column, done) {
setTimeout(() => {
if (confirm('Do you want to accep this change?')) {
done(true);
} else {
done(false);
}
}, 0);
return { async: true };
}
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
cellEdit={ cellEditFactory({
mode: 'click',
beforeSaveCell
}) }
/>
`;
function beforeSaveCell(oldValue, newValue, row, column, done) {
setTimeout(() => {
if (confirm('Do you want to accep this change?')) {
done(true);
} else {
done(false);
}
}, 0);
return { async: true };
}
export default () => (
<div>
<h2>You will get a confirm prompt when you try to save a cell</h2>
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
cellEdit={ cellEditFactory({
mode: 'click',
beforeSaveCell
}) }
/>
<Code>{ sourceCode }</Code>
</div>
);

View File

@@ -1,101 +0,0 @@
/* 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, done) => {
setTimeout(() => {
if (isNaN(newValue)) {
return done({
valid: false,
message: 'Price should be numeric'
});
}
if (newValue < 2000) {
return done({
valid: false,
message: 'Price should bigger than 2000'
});
}
return done();
}, 2000);
return {
async: 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, done) => {
setTimeout(() => {
if (isNaN(newValue)) {
return done({
valid: false,
message: 'Price should be numeric'
});
}
if (newValue < 2000) {
return done({
valid: false,
message: 'Price should bigger than 2000'
});
}
return done();
}, 2000);
return {
async: 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

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

View File

@@ -1,6 +1,5 @@
/* eslint no-unused-vars: 0 */ /* eslint no-unused-vars: 0 */
/* eslint no-alert: 0 */ /* eslint no-alert: 0 */
/* eslint no-console: 0 */
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next'; import BootstrapTable from 'react-bootstrap-table-next';
@@ -13,22 +12,7 @@ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID', text: 'Product ID',
events: { events: {
onClick: (e, column, columnIndex, row, rowIndex) => { onClick: () => alert('Click on Product ID field')
console.log(e);
console.log(column);
console.log(columnIndex);
console.log(row);
console.log(rowIndex);
alert('Click on Product ID field');
},
onMouseEnter: (e, column, columnIndex, row, rowIndex) => {
console.log(e);
console.log(column);
console.log(columnIndex);
console.log(row);
console.log(rowIndex);
console.log('onMouseEnter on Product ID field');
}
} }
}, { }, {
dataField: 'name', dataField: 'name',
@@ -45,22 +29,7 @@ const columns = [{
dataField: 'id', dataField: 'id',
text: 'Product ID', text: 'Product ID',
events: { events: {
onClick: (e, column, columnIndex, row, rowIndex) => { onClick: () => alert('Click on Product ID field')
console.log(e);
console.log(column);
console.log(columnIndex);
console.log(row);
console.log(rowIndex);
alert('Click on Product ID field');
},
onMouseEnter: (e, column, columnIndex, row, rowIndex) => {
console.log(e);
console.log(column);
console.log(columnIndex);
console.log(row);
console.log(rowIndex);
console.log('onMouseEnter on Product ID field');
}
} }
}, { }, {
dataField: 'name', dataField: 'name',
@@ -75,7 +44,7 @@ const columns = [{
export default () => ( export default () => (
<div> <div>
<h3>Try to Click or Mouse over on Product ID columns</h3> <h3>Try to Click on Product ID columns</h3>
<BootstrapTable keyField="id" data={ products } columns={ columns } /> <BootstrapTable keyField="id" data={ products } columns={ columns } />
<Code>{ sourceCode }</Code> <Code>{ sourceCode }</Code>
</div> </div>

View File

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

View File

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

View File

@@ -1,59 +0,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,
hideSelectAll: 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,
hideSelectAll: 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

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

View File

@@ -18,9 +18,7 @@ const columns = [{
}]; }];
const selectRow = { const selectRow = {
mode: 'checkbox', mode: 'checkbox'
clickToSelect: true,
clickToExpand: true
}; };
const expandRow = { const expandRow = {
@@ -50,8 +48,7 @@ const columns = [{
const selectRow = { const selectRow = {
mode: 'checkbox', mode: 'checkbox',
clickToSelect: true, clickToSelect: true
clickToExpand: true
}; };
const expandRow = { const expandRow = {
@@ -70,7 +67,6 @@ const expandRow = {
data={ products } data={ products }
columns={ columns } columns={ columns }
selectRow={ selectRow } selectRow={ selectRow }
expandRow={ expandRow }
/> />
`; `;

View File

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

View File

@@ -1,59 +0,0 @@
/* 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
}, {
dataField: 'name',
text: 'Product Name',
sort: true,
sortCaret: (order, column) => {
if (!order) return (<span>&nbsp;&nbsp;Desc/Asc</span>);
else if (order === 'asc') return (<span>&nbsp;&nbsp;Desc/<font color="red">Asc</font></span>);
else if (order === 'desc') return (<span>&nbsp;&nbsp;<font color="red">Desc</font>/Asc</span>);
return null;
}
}, {
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,
sortCaret: (order, column) => {
if (!order) return (<span>&nbsp;&nbsp;Desc/Asc</span>);
else if (order === 'asc') return (<span>&nbsp;&nbsp;Desc/<font color="red">Asc</font></span>);
else if (order === 'desc') return (<span>&nbsp;&nbsp;<font color="red">Desc</font>/Asc</span>);
return null;
}
}, {
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

@@ -1,8 +1,6 @@
import React from 'react'; import React from 'react';
import Typed from 'typed.js'; import Typed from 'typed.js';
const PROJECT_NAME = 'react-bootstrap-table2';
export default class Welcome extends React.Component { export default class Welcome extends React.Component {
componentDidMount() { componentDidMount() {
// type.js config // type.js config
@@ -23,21 +21,14 @@ export default class Welcome extends React.Component {
return ( return (
<div> <div>
<div className="welcome"> <div className="welcome">
<div className="welcome-title"> <h1 className="welcome-title">react-bootstrap-table2</h1>
<span className="welcome-title-logo">
<img src="images/logo-color-square.svg" alt={ `${PROJECT_NAME}-logo` } />
</span>
<h1>
{PROJECT_NAME}
</h1>
</div>
<span <span
className="welcome-sub-title" className="welcome-sub-title"
ref={ (el) => { this.el = el; } } ref={ (el) => { this.el = el; } }
/> />
</div> </div>
<a href={ `https://github.com/react-bootstrap-table/${PROJECT_NAME}` } className="github-corner" aria-label="View source on Github"> <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: '#0058B7', color: '#fff', position: 'absolute', top: '0', border: '0', right: '0' } } aria-hidden="true"> <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="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="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" /> <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" />

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -1 +0,0 @@
<svg id="layer_1" data-name="layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 72 72"><defs><style>.cls-1{fill:#059ae6;}.cls-2{fill:#0058b7;}</style></defs><title>logo square</title><polygon class="cls-1" points="22.76 59 22.76 64.35 49.24 51.13 49.24 43.88 44.45 41.5 44.45 48.17 22.76 59"/><polygon class="cls-2" points="22.76 20.87 22.76 47.98 27.55 45.59 27.55 23.83 44.45 15.39 44.45 23.02 33.06 28.71 33.06 31.9 49.24 39.97 49.24 34.62 40.58 30.3 49.24 25.98 49.24 7.65 22.76 20.87"/></svg>

Before

Width:  |  Height:  |  Size: 503 B

View File

@@ -13,8 +13,6 @@ import NoDataTable from 'examples/basic/no-data-table';
import CustomizedIdClassesTable from 'examples/basic/customized-id-classes'; import CustomizedIdClassesTable from 'examples/basic/customized-id-classes';
import CaptionTable from 'examples/basic/caption-table'; import CaptionTable from 'examples/basic/caption-table';
import LargeTable from 'examples/basic/large-table'; import LargeTable from 'examples/basic/large-table';
import ExposedAPITable from 'examples/basic/exposed-function';
import TabIndexCellTable from 'examples/basic/tabindex-column';
// bootstrap 4 // bootstrap 4
import Bootstrap4DefaultSortTable from 'examples/bootstrap4/sort'; import Bootstrap4DefaultSortTable from 'examples/bootstrap4/sort';
@@ -55,7 +53,6 @@ import CustomFilterValue from 'examples/column-filter/custom-filter-value';
import SelectFilter from 'examples/column-filter/select-filter'; import SelectFilter from 'examples/column-filter/select-filter';
import SelectFilterWithDefaultValue from 'examples/column-filter/select-filter-default-value'; import SelectFilterWithDefaultValue from 'examples/column-filter/select-filter-default-value';
import SelectFilterComparator from 'examples/column-filter/select-filter-like-comparator'; import SelectFilterComparator from 'examples/column-filter/select-filter-like-comparator';
import SelectFilterWithPreservedOptionsOrder from 'examples/column-filter/select-filter-preserve-option-order';
import CustomSelectFilter from 'examples/column-filter/custom-select-filter'; import CustomSelectFilter from 'examples/column-filter/custom-select-filter';
import MultiSelectFilter from 'examples/column-filter/multi-select-filter'; import MultiSelectFilter from 'examples/column-filter/multi-select-filter';
import MultiSelectFilterDefaultValue from 'examples/column-filter/multi-select-filter-default-value'; import MultiSelectFilterDefaultValue from 'examples/column-filter/multi-select-filter-default-value';
@@ -86,7 +83,6 @@ import DefaultSortTable from 'examples/sort/default-sort-table';
import DefaultSortDirectionTable from 'examples/sort/default-sort-direction'; import DefaultSortDirectionTable from 'examples/sort/default-sort-direction';
import SortEvents from 'examples/sort/sort-events'; import SortEvents from 'examples/sort/sort-events';
import CustomSortTable from 'examples/sort/custom-sort-table'; import CustomSortTable from 'examples/sort/custom-sort-table';
import CustomSortCaretTable from 'examples/sort/custom-sort-caret';
import HeaderSortingClassesTable from 'examples/sort/header-sorting-classes'; import HeaderSortingClassesTable from 'examples/sort/header-sorting-classes';
import HeaderSortingStyleTable from 'examples/sort/header-sorting-style'; import HeaderSortingStyleTable from 'examples/sort/header-sorting-style';
@@ -98,12 +94,9 @@ import RowLevelEditableTable from 'examples/cell-edit/row-level-editable-table';
import ColumnLevelEditableTable from 'examples/cell-edit/column-level-editable-table'; import ColumnLevelEditableTable from 'examples/cell-edit/column-level-editable-table';
import CellLevelEditable from 'examples/cell-edit/cell-level-editable-table'; import CellLevelEditable from 'examples/cell-edit/cell-level-editable-table';
import CellEditHooks from 'examples/cell-edit/cell-edit-hooks-table'; import CellEditHooks from 'examples/cell-edit/cell-edit-hooks-table';
import AsyncCellEditHooks from 'examples/cell-edit/cell-edit-async-hooks-table';
import CellEditValidator from 'examples/cell-edit/cell-edit-validator-table'; import CellEditValidator from 'examples/cell-edit/cell-edit-validator-table';
import AsyncCellEditValidator from 'examples/cell-edit/cell-edit-async-validator-table';
import CellEditStyleTable from 'examples/cell-edit/cell-edit-style-table'; import CellEditStyleTable from 'examples/cell-edit/cell-edit-style-table';
import CellEditClassTable from 'examples/cell-edit/cell-edit-class-table'; import CellEditClassTable from 'examples/cell-edit/cell-edit-class-table';
import AutoSelectTextInput from 'examples/cell-edit/auto-select-text-input-table';
import EditorStyleTable from 'examples/cell-edit/editor-style-table'; import EditorStyleTable from 'examples/cell-edit/editor-style-table';
import EditorClassTable from 'examples/cell-edit/editor-class-table'; import EditorClassTable from 'examples/cell-edit/editor-class-table';
import DBClickEditWithSelection from 'examples/cell-edit/dbclick-to-edit-with-selection-table'; import DBClickEditWithSelection from 'examples/cell-edit/dbclick-to-edit-with-selection-table';
@@ -119,13 +112,11 @@ import MultipleSelectionTable from 'examples/row-selection/multiple-selection';
import ClickToSelectTable from 'examples/row-selection/click-to-select'; import ClickToSelectTable from 'examples/row-selection/click-to-select';
import DefaultSelectTable from 'examples/row-selection/default-select'; import DefaultSelectTable from 'examples/row-selection/default-select';
import SelectionManagement from 'examples/row-selection/selection-management'; import SelectionManagement from 'examples/row-selection/selection-management';
import AdvanceSelectionManagement from 'examples/row-selection/selection-advance-management';
import ClickToSelectWithCellEditTable from 'examples/row-selection/click-to-select-with-cell-edit'; import ClickToSelectWithCellEditTable from 'examples/row-selection/click-to-select-with-cell-edit';
import SelectionWithExpansionTable from 'examples/row-selection/selection-with-expansion'; import SelectionWithExpansionTable from 'examples/row-selection/selection-with-expansion';
import SelectionNoDataTable from 'examples/row-selection/selection-no-data'; import SelectionNoDataTable from 'examples/row-selection/selection-no-data';
import SelectionStyleTable from 'examples/row-selection/selection-style'; import SelectionStyleTable from 'examples/row-selection/selection-style';
import SelectionClassTable from 'examples/row-selection/selection-class'; import SelectionClassTable from 'examples/row-selection/selection-class';
import HideSelectAllTable from 'examples/row-selection/hide-select-all';
import CustomSelectionTable from 'examples/row-selection/custom-selection'; import CustomSelectionTable from 'examples/row-selection/custom-selection';
import NonSelectableRowsTable from 'examples/row-selection/non-selectable-rows'; import NonSelectableRowsTable from 'examples/row-selection/non-selectable-rows';
import SelectionBgColorTable from 'examples/row-selection/selection-bgcolor'; import SelectionBgColorTable from 'examples/row-selection/selection-bgcolor';
@@ -137,8 +128,6 @@ import BasicRowExpand from 'examples/row-expand';
import RowExpandManagement from 'examples/row-expand/expand-management'; import RowExpandManagement from 'examples/row-expand/expand-management';
import NonExpandableRows from 'examples/row-expand/non-expandable-rows'; import NonExpandableRows from 'examples/row-expand/non-expandable-rows';
import ExpandColumn from 'examples/row-expand/expand-column'; import ExpandColumn from 'examples/row-expand/expand-column';
import OnlyExpandByColumn from 'examples/row-expand/expand-by-column-only.js';
import ExpandOnlyOne from 'examples/row-expand/expand-only-one';
import CustomExpandColumn from 'examples/row-expand/custom-expand-column'; import CustomExpandColumn from 'examples/row-expand/custom-expand-column';
import ExpandHooks from 'examples/row-expand/expand-hooks'; import ExpandHooks from 'examples/row-expand/expand-hooks';
@@ -149,7 +138,6 @@ import CustomPaginationTable from 'examples/pagination/custom-pagination';
// search // search
import SearchTable from 'examples/search'; import SearchTable from 'examples/search';
import DefaultSearch from 'examples/search/default-search';
import DefaultCustomSearch from 'examples/search/default-custom-search'; import DefaultCustomSearch from 'examples/search/default-custom-search';
import FullyCustomSearch from 'examples/search/fully-custom-search'; import FullyCustomSearch from 'examples/search/fully-custom-search';
import SearchFormattedData from 'examples/search/search-formatted'; import SearchFormattedData from 'examples/search/search-formatted';
@@ -199,9 +187,7 @@ storiesOf('Basic Table', module)
.add('Indication For Empty Table', () => <NoDataTable />) .add('Indication For Empty Table', () => <NoDataTable />)
.add('Customized id and class table', () => <CustomizedIdClassesTable />) .add('Customized id and class table', () => <CustomizedIdClassesTable />)
.add('Table with caption', () => <CaptionTable />) .add('Table with caption', () => <CaptionTable />)
.add('Large Table', () => <LargeTable />) .add('Large Table', () => <LargeTable />);
.add('Exposed API', () => <ExposedAPITable />)
.add('Enable tabIndex on Cell', () => <TabIndexCellTable />);
storiesOf('Bootstrap 4', module) storiesOf('Bootstrap 4', module)
.addDecorator(bootstrapStyle(BOOTSTRAP_VERSION.FOUR)) .addDecorator(bootstrapStyle(BOOTSTRAP_VERSION.FOUR))
@@ -264,7 +250,6 @@ storiesOf('Column Filter', module)
.add('Programmatically Multi Select Filter', () => <ProgrammaticallyMultiSelectFilter />) .add('Programmatically Multi Select Filter', () => <ProgrammaticallyMultiSelectFilter />)
.add('Custom Filter', () => <CustomFilter />) .add('Custom Filter', () => <CustomFilter />)
.add('Advance Custom Filter', () => <AdvanceCustomFilter />) .add('Advance Custom Filter', () => <AdvanceCustomFilter />)
.add('Preserved Option Order on Select Filter', () => <SelectFilterWithPreservedOptionsOrder />)
.add('Clear All Filters', () => <ClearAllFilters />); .add('Clear All Filters', () => <ClearAllFilters />);
storiesOf('Work on Rows', module) storiesOf('Work on Rows', module)
@@ -280,7 +265,6 @@ storiesOf('Sort Table', module)
.add('Default Sort Direction Table', () => <DefaultSortDirectionTable />) .add('Default Sort Direction Table', () => <DefaultSortDirectionTable />)
.add('Sort Events', () => <SortEvents />) .add('Sort Events', () => <SortEvents />)
.add('Custom Sort Fuction', () => <CustomSortTable />) .add('Custom Sort Fuction', () => <CustomSortTable />)
.add('Custom Sort Caret', () => <CustomSortCaretTable />)
.add('Custom Classes on Sorting Header Column', () => <HeaderSortingClassesTable />) .add('Custom Classes on Sorting Header Column', () => <HeaderSortingClassesTable />)
.add('Custom Style on Sorting Header Column', () => <HeaderSortingStyleTable />); .add('Custom Style on Sorting Header Column', () => <HeaderSortingStyleTable />);
@@ -293,10 +277,7 @@ storiesOf('Cell Editing', module)
.add('Column Level Editable', () => <ColumnLevelEditableTable />) .add('Column Level Editable', () => <ColumnLevelEditableTable />)
.add('Cell Level Editable', () => <CellLevelEditable />) .add('Cell Level Editable', () => <CellLevelEditable />)
.add('Rich Hook Functions', () => <CellEditHooks />) .add('Rich Hook Functions', () => <CellEditHooks />)
.add('Async Hook Functions', () => <AsyncCellEditHooks />)
.add('Validation', () => <CellEditValidator />) .add('Validation', () => <CellEditValidator />)
.add('Async Validation', () => <AsyncCellEditValidator />)
.add('Auto Select Text Input', () => <AutoSelectTextInput />)
.add('Custom Cell Style', () => <CellEditStyleTable />) .add('Custom Cell Style', () => <CellEditStyleTable />)
.add('Custom Cell Classes', () => <CellEditClassTable />) .add('Custom Cell Classes', () => <CellEditClassTable />)
.add('Custom Editor Classes', () => <EditorClassTable />) .add('Custom Editor Classes', () => <EditorClassTable />)
@@ -315,13 +296,11 @@ storiesOf('Row Selection', module)
.add('Click to Select', () => <ClickToSelectTable />) .add('Click to Select', () => <ClickToSelectTable />)
.add('Default Select', () => <DefaultSelectTable />) .add('Default Select', () => <DefaultSelectTable />)
.add('Selection Management', () => <SelectionManagement />) .add('Selection Management', () => <SelectionManagement />)
.add('Advance Selection Management', () => <AdvanceSelectionManagement />)
.add('Click to Select and Edit Cell', () => <ClickToSelectWithCellEditTable />) .add('Click to Select and Edit Cell', () => <ClickToSelectWithCellEditTable />)
.add('Row Select and Expand', () => <SelectionWithExpansionTable />) .add('Row Select and Expand', () => <SelectionWithExpansionTable />)
.add('Selection without Data', () => <SelectionNoDataTable />) .add('Selection without Data', () => <SelectionNoDataTable />)
.add('Selection Style', () => <SelectionStyleTable />) .add('Selection Style', () => <SelectionStyleTable />)
.add('Selection Class', () => <SelectionClassTable />) .add('Selection Class', () => <SelectionClassTable />)
.add('Hide Select All', () => <HideSelectAllTable />)
.add('Custom Selection', () => <CustomSelectionTable />) .add('Custom Selection', () => <CustomSelectionTable />)
.add('Selection Background Color', () => <SelectionBgColorTable />) .add('Selection Background Color', () => <SelectionBgColorTable />)
.add('Not Selectabled Rows', () => <NonSelectableRowsTable />) .add('Not Selectabled Rows', () => <NonSelectableRowsTable />)
@@ -334,8 +313,6 @@ storiesOf('Row Expand', module)
.add('Expand Management', () => <RowExpandManagement />) .add('Expand Management', () => <RowExpandManagement />)
.add('Non Expandabled Rows', () => <NonExpandableRows />) .add('Non Expandabled Rows', () => <NonExpandableRows />)
.add('Expand Indicator', () => <ExpandColumn />) .add('Expand Indicator', () => <ExpandColumn />)
.add('Only Expand by Indicator', () => <OnlyExpandByColumn />)
.add('Expand Only One Row at The Same Time', () => <ExpandOnlyOne />)
.add('Custom Expand Indicator', () => <CustomExpandColumn />) .add('Custom Expand Indicator', () => <CustomExpandColumn />)
.add('Expand Hooks', () => <ExpandHooks />); .add('Expand Hooks', () => <ExpandHooks />);
@@ -348,7 +325,6 @@ storiesOf('Pagination', module)
storiesOf('Table Search', module) storiesOf('Table Search', module)
.addDecorator(bootstrapStyle()) .addDecorator(bootstrapStyle())
.add('Basic Search Table', () => <SearchTable />) .add('Basic Search Table', () => <SearchTable />)
.add('Default Search Table', () => <DefaultSearch />)
.add('Default Custom Search', () => <DefaultCustomSearch />) .add('Default Custom Search', () => <DefaultCustomSearch />)
.add('Fully Custom Search', () => <FullyCustomSearch />) .add('Fully Custom Search', () => <FullyCustomSearch />)
.add('Search Fromatted Value', () => <SearchFormattedData />) .add('Search Fromatted Value', () => <SearchFormattedData />)

View File

@@ -1,5 +1,3 @@
$logo-size: 96px;
.welcome { .welcome {
margin-top: 70px; margin-top: 70px;
text-align: center; text-align: center;
@@ -7,22 +5,7 @@ $logo-size: 96px;
&-title { &-title {
color: $grey-900; color: $grey-900;
width: 100%;
display: inline-flex;
justify-content: center;
align-content: center;
&-logo {
position: relative;
top: -8px;
right: -12px;
width: $logo-size;
height: $logo-size;
}
} }
&-sub-title { &-sub-title {
font-size: 30px; font-size: 30px;
color: $grey-500; color: $grey-500;

View File

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

View File

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

View File

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

View File

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

View File

@@ -68,9 +68,6 @@ export default (
currPage = newPage; currPage = newPage;
needNewState = true; needNewState = true;
} }
} else {
this.currPage = nextProps.pagination.options.page;
this.currSizePerPage = nextProps.pagination.options.sizePerPage;
} }
if (needNewState) { if (needNewState) {

View File

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

View File

@@ -160,27 +160,6 @@ describe('PaginationContext', () => {
}); });
}); });
describe('when remote pagination is enable', () => {
beforeEach(() => {
wrapper = shallow(shallowContext({ ...defaultPagination }, true));
instance = wrapper.instance();
wrapper.render();
nextProps = {
data,
pagination: { ...defaultPagination, options: { page: 3, sizePerPage: 5 } }
};
instance.componentWillReceiveProps(nextProps);
});
it('should always set currPage from nextProps.pagination.options.page', () => {
expect(instance.currPage).toEqual(nextProps.pagination.options.page);
});
it('should always set currSizePerPage from nextProps.pagination.options.sizePerPage', () => {
expect(instance.currSizePerPage).toEqual(nextProps.pagination.options.sizePerPage);
});
});
describe('when page is not align', () => { describe('when page is not align', () => {
beforeEach(() => { beforeEach(() => {
wrapper = shallow(shallowContext({ wrapper = shallow(shallowContext({

View File

@@ -63,22 +63,6 @@ const { SearchBar } = Search;
### Search Options ### Search Options
#### defaultSearch - [string]
Accept a string that will be used for default searching when first time table render.
```js
<ToolkitProvider
keyField="id"
data={ products }
columns={ columns }
search={ {
defaultSearch: 'search something here'
} }
>
// ...
</ToolkitProvider>
```
#### searchFormatted - [bool] #### searchFormatted - [bool]
If you want to search on the formatted data, you are supposed to enable this props. `react-bootstrap-table2` will check if you define the `column.formatter` when doing search. If you want to search on the formatted data, you are supposed to enable this props. `react-bootstrap-table2` will check if you define the `column.formatter` when doing search.

View File

@@ -17,7 +17,6 @@ class ToolkitProvider extends statelessDrcorator(React.Component) {
search: PropTypes.oneOfType([ search: PropTypes.oneOfType([
PropTypes.bool, PropTypes.bool,
PropTypes.shape({ PropTypes.shape({
defaultSearch: PropTypes.string,
searchFormatted: PropTypes.bool searchFormatted: PropTypes.bool
}) })
]), ]),
@@ -43,7 +42,7 @@ class ToolkitProvider extends statelessDrcorator(React.Component) {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
searchText: typeof props.search === 'object' ? (props.search.defaultSearch || '') : '' searchText: ''
}; };
this._ = null; this._ = null;
this.onSearch = this.onSearch.bind(this); this.onSearch = this.onSearch.bind(this);
@@ -86,7 +85,6 @@ class ToolkitProvider extends statelessDrcorator(React.Component) {
return ( return (
<ToolkitContext.Provider value={ { <ToolkitContext.Provider value={ {
searchProps: { searchProps: {
searchText: this.state.searchText,
onSearch: this.onSearch onSearch: this.onSearch
}, },
csvProps: { csvProps: {

View File

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

View File

@@ -58,7 +58,7 @@ export const save = (
} }
) => { ) => {
FileSaver.saveAs( FileSaver.saveAs(
new Blob([content], { type: 'text/plain;charset=utf-8' }), new Blob(['\ufeff', content], { type: 'text/plain;charset=utf-8' }),
fileName, fileName,
noAutoBOM noAutoBOM
); );

View File

@@ -47,7 +47,6 @@ const SearchBar = ({
style={ style } style={ style }
onKeyUp={ () => debounceCallback() } onKeyUp={ () => debounceCallback() }
className={ `form-control ${className}` } className={ `form-control ${className}` }
defaultValue={ searchText }
placeholder={ placeholder || SearchBar.defaultProps.placeholder } placeholder={ placeholder || SearchBar.defaultProps.placeholder }
{ ...rest } { ...rest }
/> />

View File

@@ -39,10 +39,8 @@ export default (options = {
const { data, columns } = this.props; const { data, columns } = this.props;
let { searchText } = this.props; let { searchText } = this.props;
if (isRemoteSearch()) { if (isRemoteSearch() && this.performRemoteSearch) {
if (this.performRemoteSearch) { handleRemoteSearchChange(searchText);
handleRemoteSearchChange(searchText);
}
return data; return data;
} }

View File

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

View File

@@ -5,12 +5,12 @@ import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import _ from './utils'; import _ from './utils';
import SimpleRow from './row/simple-row'; import Row from './simple-row';
import RowAggregator from './row/aggregate-row'; import RowAggregator from './row-aggregator';
import RowSection from './row/row-section'; import RowSection from './row-section';
import Const from './const'; import Const from './const';
import withRowSelection from './row-selection/row-consumer'; import bindSelection from './row-selection/row-binder';
import withRowExpansion from './row-expand/row-consumer'; import bindExpansion from './row-expand/row-binder';
class Body extends React.Component { class Body extends React.Component {
constructor(props) { constructor(props) {
@@ -18,13 +18,13 @@ class Body extends React.Component {
if (props.cellEdit.createContext) { if (props.cellEdit.createContext) {
this.EditingCell = props.cellEdit.createEditingCell(_, props.cellEdit.options.onStartEdit); this.EditingCell = props.cellEdit.createEditingCell(_, props.cellEdit.options.onStartEdit);
} }
this.RowComponent = bindSelection(RowAggregator);
} }
render() { render() {
const { const {
columns, columns,
data, data,
tabIndexCell,
keyField, keyField,
isEmpty, isEmpty,
noDataIndication, noDataIndication,
@@ -46,21 +46,21 @@ class Body extends React.Component {
} }
content = <RowSection content={ indication } colSpan={ visibleColumnSize } />; content = <RowSection content={ indication } colSpan={ visibleColumnSize } />;
} else { } else {
let RowComponent = SimpleRow; let RowComponent = Row;
const selectRowEnabled = selectRow.mode !== Const.ROW_SELECT_DISABLED; const selectRowEnabled = selectRow.mode !== Const.ROW_SELECT_DISABLED;
const expandRowEnabled = !!expandRow.renderer; const expandRowEnabled = !!expandRow.renderer;
const additionalRowProps = {}; const additionalRowProps = {};
if (expandRowEnabled) { if (expandRowEnabled) {
RowComponent = withRowExpansion(RowAggregator, visibleColumnSize); RowComponent = bindExpansion(RowAggregator, visibleColumnSize);
} }
if (selectRowEnabled) { // if (selectRowEnabled) {
RowComponent = withRowSelection(expandRowEnabled ? RowComponent : RowAggregator); // RowComponent = bindSelection(expandRowEnabled ? RowComponent : RowAggregator);
} // }
if (cellEdit.createContext) { if (cellEdit.createContext) {
RowComponent = cellEdit.withRowLevelCellEdit(RowComponent, selectRowEnabled, keyField, _); RowComponent = cellEdit.bindRowLevelCellEdit(RowComponent, selectRowEnabled, keyField, _);
additionalRowProps.EditingCellComponent = this.EditingCell; additionalRowProps.EditingCellComponent = this.EditingCell;
} }
@@ -74,13 +74,11 @@ class Body extends React.Component {
const baseRowProps = { const baseRowProps = {
key, key,
row, row,
tabIndexCell,
columns, columns,
keyField, keyField,
cellEdit, cellEdit,
value: key, value: key,
rowIndex: index, rowIndex: index,
visibleColumnSize,
attrs: rowEvents || {}, attrs: rowEvents || {},
...additionalRowProps ...additionalRowProps
}; };
@@ -88,7 +86,7 @@ class Body extends React.Component {
baseRowProps.style = _.isFunction(rowStyle) ? rowStyle(row, index) : rowStyle; baseRowProps.style = _.isFunction(rowStyle) ? rowStyle(row, index) : rowStyle;
baseRowProps.className = (_.isFunction(rowClasses) ? rowClasses(row, index) : rowClasses); baseRowProps.className = (_.isFunction(rowClasses) ? rowClasses(row, index) : rowClasses);
return <RowComponent { ...baseRowProps } />; return <this.RowComponent { ...baseRowProps } />;
}); });
} }

View File

@@ -15,12 +15,13 @@ class BootstrapTable extends PropsBaseResolver(Component) {
super(props); super(props);
this.validateProps(); this.validateProps();
if (props.registerExposedAPI) { if (props.registerExposedAPI) {
props.registerExposedAPI(this.getData); const getData = () => this.getData();
props.registerExposedAPI(getData);
} }
} }
// Exposed APIs // Exposed APIs
getData() { getData = () => {
return this.props.data; return this.props.data;
} }
@@ -42,10 +43,8 @@ class BootstrapTable extends PropsBaseResolver(Component) {
data, data,
columns, columns,
keyField, keyField,
tabIndexCell,
id, id,
classes, classes,
bootstrap4,
striped, striped,
hover, hover,
bordered, bordered,
@@ -67,7 +66,7 @@ class BootstrapTable extends PropsBaseResolver(Component) {
'table-striped': striped, 'table-striped': striped,
'table-hover': hover, 'table-hover': hover,
'table-bordered': bordered, 'table-bordered': bordered,
[(bootstrap4 ? 'table-sm' : 'table-condensed')]: condensed 'table-condensed': condensed
}, classes); }, classes);
const tableCaption = (caption && <Caption>{ caption }</Caption>); const tableCaption = (caption && <Caption>{ caption }</Caption>);
@@ -90,7 +89,6 @@ class BootstrapTable extends PropsBaseResolver(Component) {
<Body <Body
data={ data } data={ data }
keyField={ keyField } keyField={ keyField }
tabIndexCell={ tabIndexCell }
columns={ columns } columns={ columns }
isEmpty={ this.isEmpty() } isEmpty={ this.isEmpty() }
visibleColumnSize={ this.visibleColumnSize() } visibleColumnSize={ this.visibleColumnSize() }
@@ -120,7 +118,6 @@ BootstrapTable.propTypes = {
striped: PropTypes.bool, striped: PropTypes.bool,
bordered: PropTypes.bool, bordered: PropTypes.bool,
hover: PropTypes.bool, hover: PropTypes.bool,
tabIndexCell: PropTypes.bool,
id: PropTypes.string, id: PropTypes.string,
classes: PropTypes.string, classes: PropTypes.string,
wrapperClasses: PropTypes.string, wrapperClasses: PropTypes.string,
@@ -139,9 +136,7 @@ BootstrapTable.propTypes = {
Const.ROW_SELECT_DISABLED Const.ROW_SELECT_DISABLED
]).isRequired, ]).isRequired,
clickToSelect: PropTypes.bool, clickToSelect: PropTypes.bool,
clickToExpand: PropTypes.bool,
clickToEdit: PropTypes.bool, clickToEdit: PropTypes.bool,
hideSelectAll: PropTypes.bool,
onSelect: PropTypes.func, onSelect: PropTypes.func,
onSelectAll: PropTypes.func, onSelectAll: PropTypes.func,
style: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), style: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
@@ -159,8 +154,6 @@ BootstrapTable.propTypes = {
onExpandAll: PropTypes.func, onExpandAll: PropTypes.func,
nonExpandable: PropTypes.array, nonExpandable: PropTypes.array,
showExpandColumn: PropTypes.bool, showExpandColumn: PropTypes.bool,
onlyOneExpanding: PropTypes.bool,
expandByColumnOnly: PropTypes.bool,
expandColumnRenderer: PropTypes.func, expandColumnRenderer: PropTypes.func,
expandHeaderColumnRenderer: PropTypes.func expandHeaderColumnRenderer: PropTypes.func
}), }),

View File

@@ -2,10 +2,9 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import eventDelegater from './cell-event-delegater';
import _ from './utils'; import _ from './utils';
class Cell extends eventDelegater(Component) { class Cell extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.handleEditingCell = this.handleEditingCell.bind(this); this.handleEditingCell = this.handleEditingCell.bind(this);
@@ -35,8 +34,7 @@ class Cell extends eventDelegater(Component) {
!_.isEqual(this.props.style, nextProps.style) || !_.isEqual(this.props.style, nextProps.style) ||
!_.isEqual(this.props.column.formatExtraData, nextProps.column.formatExtraData) || !_.isEqual(this.props.column.formatExtraData, nextProps.column.formatExtraData) ||
!_.isEqual(this.props.column.events, nextProps.column.events) || !_.isEqual(this.props.column.events, nextProps.column.events) ||
!_.isEqual(this.props.column.attrs, nextProps.column.attrs) || !_.isEqual(this.props.column.attrs, nextProps.column.attrs);
this.props.tabIndex !== nextProps.tabIndex;
return shouldUpdate; return shouldUpdate;
} }
@@ -74,8 +72,11 @@ class Cell extends eventDelegater(Component) {
formatter, formatter,
formatExtraData formatExtraData
} = column; } = column;
const attrs = this.delegate({ ...rest }); const attrs = { ...rest };
let content = column.isDummyField ? null : _.get(row, dataField); let content = this.props.children;
if (!content) {
content = column.isDummyField ? null : _.get(row, dataField);
}
if (formatter) { if (formatter) {
content = column.formatter(content, row, rowIndex, formatExtraData); content = column.formatter(content, row, rowIndex, formatExtraData);

View File

@@ -54,16 +54,6 @@ const withContext = Base =>
} }
} }
componentWillReceiveProps(nextProps) {
if (!nextProps.pagination && this.props.pagination) {
this.PaginationContext = null;
}
if (nextProps.pagination && !this.props.pagination) {
this.PaginationContext = nextProps.pagination.createContext(
this.isRemotePagination, this.handleRemotePageChange);
}
}
renderBase() { renderBase() {
return ( return (
rootProps, rootProps,
@@ -73,7 +63,6 @@ const withContext = Base =>
paginationProps, paginationProps,
) => ( ) => (
<Base <Base
ref={ n => this.table = n }
{ ...this.props } { ...this.props }
{ ...sortProps } { ...sortProps }
{ ...filterProps } { ...filterProps }
@@ -94,7 +83,6 @@ const withContext = Base =>
) => ( ) => (
<this.SelectionContext.Provider <this.SelectionContext.Provider
{ ...baseProps } { ...baseProps }
ref={ n => this.selectionContext = n }
selectRow={ this.props.selectRow } selectRow={ this.props.selectRow }
data={ rootProps.getData(filterProps, searchProps, sortProps, paginationProps) } data={ rootProps.getData(filterProps, searchProps, sortProps, paginationProps) }
> >
@@ -121,7 +109,6 @@ const withContext = Base =>
) => ( ) => (
<this.RowExpandContext.Provider <this.RowExpandContext.Provider
{ ...baseProps } { ...baseProps }
ref={ n => this.rowExpandContext = n }
expandRow={ this.props.expandRow } expandRow={ this.props.expandRow }
data={ rootProps.getData(filterProps, searchProps, sortProps, paginationProps) } data={ rootProps.getData(filterProps, searchProps, sortProps, paginationProps) }
> >

View File

@@ -23,13 +23,12 @@ class RowExpandProvider extends React.Component {
} }
handleRowExpand = (rowKey, expanded, rowIndex, e) => { handleRowExpand = (rowKey, expanded, rowIndex, e) => {
const { data, keyField, expandRow: { onExpand, onlyOneExpanding } } = this.props; const { data, keyField, expandRow: { onExpand } } = this.props;
let currExpanded = [...this.state.expanded]; let currExpanded = [...this.state.expanded];
if (expanded) { if (expanded) {
if (onlyOneExpanding) currExpanded = [rowKey]; currExpanded.push(rowKey);
else currExpanded.push(rowKey);
} else { } else {
currExpanded = currExpanded.filter(value => value !== rowKey); currExpanded = currExpanded.filter(value => value !== rowKey);
} }

View File

@@ -22,7 +22,7 @@ class SelectionProvider extends React.Component {
} }
} }
state = { selected: this.props.selectRow.selected || [] }; state = { selected: (this.props.selectRow && this.props.selectRow.selected) || [] };
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
if (nextProps.selectRow) { if (nextProps.selectRow) {
@@ -43,23 +43,20 @@ class SelectionProvider extends React.Component {
let currSelected = [...this.state.selected]; let currSelected = [...this.state.selected];
this.setState(() => { if (mode === ROW_SELECT_SINGLE) { // when select mode is radio
let result = true; currSelected = [rowKey];
if (onSelect) { } else if (checked) { // when select mode is checkbox
const row = dataOperator.getRowByRowId(data, keyField, rowKey); currSelected.push(rowKey);
result = onSelect(row, checked, rowIndex, e); } else {
} currSelected = currSelected.filter(value => value !== rowKey);
if (result === true || result === undefined) { }
if (mode === ROW_SELECT_SINGLE) { // when select mode is radio
currSelected = [rowKey]; if (onSelect) {
} else if (checked) { // when select mode is checkbox const row = dataOperator.getRowByRowId(data, keyField, rowKey);
currSelected.push(rowKey); onSelect(row, checked, rowIndex, e);
} else { }
currSelected = currSelected.filter(value => value !== rowKey);
} this.setState(() => ({ selected: currSelected }));
}
return { selected: currSelected };
});
} }
handleAllRowsSelect = (e, isUnSelect) => { handleAllRowsSelect = (e, isUnSelect) => {
@@ -81,24 +78,11 @@ class SelectionProvider extends React.Component {
currSelected = selected.filter(s => typeof data.find(d => d[keyField] === s) === 'undefined'); currSelected = selected.filter(s => typeof data.find(d => d[keyField] === s) === 'undefined');
} }
this.setState(() => { if (onSelectAll) {
let result; onSelectAll(!isUnSelect, dataOperator.getSelectedRows(data, keyField, currSelected), e);
if (onSelectAll) { }
result = onSelectAll(
!isUnSelect, this.setState(() => ({ selected: currSelected }));
dataOperator.getSelectedRows(
data,
keyField,
isUnSelect ? this.state.selected : currSelected
),
e
);
if (Array.isArray(result)) {
currSelected = result;
}
}
return { selected: currSelected };
});
} }
render() { render() {

View File

@@ -24,7 +24,6 @@ const HeaderCell = (props) => {
const { const {
text, text,
sort, sort,
sortCaret,
filter, filter,
filterRenderer, filterRenderer,
headerTitle, headerTitle,
@@ -50,7 +49,6 @@ const HeaderCell = (props) => {
if (headerStyle) { if (headerStyle) {
cellStyle = _.isFunction(headerStyle) ? headerStyle(column, index) : headerStyle; cellStyle = _.isFunction(headerStyle) ? headerStyle(column, index) : headerStyle;
cellStyle = cellStyle ? { ...cellStyle } : cellStyle;
} }
if (headerTitle) { if (headerTitle) {
@@ -70,7 +68,7 @@ const HeaderCell = (props) => {
cellAttrs.className = cs(cellAttrs.className, 'sortable'); cellAttrs.className = cs(cellAttrs.className, 'sortable');
if (sorting) { if (sorting) {
sortSymbol = sortCaret ? sortCaret(sortOrder, column) : <SortCaret order={ sortOrder } />; sortSymbol = <SortCaret order={ sortOrder } />;
// append customized classes or style if table was sorting based on the current column. // append customized classes or style if table was sorting based on the current column.
cellClasses = cs( cellClasses = cs(
@@ -87,7 +85,7 @@ const HeaderCell = (props) => {
: headerSortingStyle : headerSortingStyle
}; };
} else { } else {
sortSymbol = sortCaret ? sortCaret(undefined, column) : <SortSymbol />; sortSymbol = <SortSymbol />;
} }
} }
@@ -152,7 +150,6 @@ HeaderCell.propTypes = {
onSort: PropTypes.func, onSort: PropTypes.func,
sorting: PropTypes.bool, sorting: PropTypes.bool,
sortOrder: PropTypes.oneOf([Const.SORT_ASC, Const.SORT_DESC]), sortOrder: PropTypes.oneOf([Const.SORT_ASC, Const.SORT_DESC]),
sortCaret: PropTypes.func,
isLastSorting: PropTypes.bool, isLastSorting: PropTypes.bool,
onFilter: PropTypes.func, onFilter: PropTypes.func,
onExternalFilter: PropTypes.func onExternalFilter: PropTypes.func

View File

@@ -5,8 +5,8 @@ import PropTypes from 'prop-types';
import HeaderCell from './header-cell'; import HeaderCell from './header-cell';
import SelectionHeaderCell from './row-selection/selection-header-cell'; import SelectionHeaderCell from './row-selection/selection-header-cell';
import ExpandHeaderCell from './row-expand/expand-header-cell'; import ExpandHeaderCell from './row-expand/expand-header-cell';
import withHeaderSelection from './row-selection/selection-header-cell-consumer'; import bindSelection from './row-selection/selection-header-cell-binder';
import withHeaderExpansion from './row-expand/expand-header-cell-consumer'; import bindExpansion from './row-expand/expand-header-cell-binder';
const Header = (props) => { const Header = (props) => {
const { const {
@@ -26,11 +26,11 @@ const Header = (props) => {
let ExpansionHeaderCellComp = () => null; let ExpansionHeaderCellComp = () => null;
if (expandRow.showExpandColumn) { if (expandRow.showExpandColumn) {
ExpansionHeaderCellComp = withHeaderExpansion(ExpandHeaderCell); ExpansionHeaderCellComp = bindExpansion(ExpandHeaderCell);
} }
if (selectRow) { if (selectRow) {
SelectionHeaderCellComp = withHeaderSelection(SelectionHeaderCell); SelectionHeaderCellComp = bindSelection(SelectionHeaderCell);
} }
return ( return (

View File

@@ -0,0 +1,48 @@
/* eslint react/prop-types: 0 */
/* eslint react/no-array-index-key: 0 */
import React, { Component } from 'react';
import PropTypes from 'prop-types';
// import eventDelegater from './row-event-delegater';
import RowContent from './row-pure-content';
// import shouldRowUpdater from './row-should-updater';
/* eslint react/prefer-stateless-function: 0 */
class RowAggregatorContent extends Component {
render() {
const {
className,
style,
attrs,
shouldUpdateRowContent,
...rest
} = this.props;
return (
<tr style={ style } className={ className } { ...attrs }>
{ this.props.children }
<RowContent shouldUpdate={ shouldUpdateRowContent } { ...rest } />
</tr>
);
}
}
RowAggregatorContent.propTypes = {
row: PropTypes.object.isRequired,
rowIndex: PropTypes.number.isRequired,
columns: PropTypes.array.isRequired,
style: PropTypes.object,
className: PropTypes.string,
attrs: PropTypes.object,
shouldUpdateRowContent: PropTypes.bool
};
RowAggregatorContent.defaultProps = {
editable: true,
style: {},
className: null,
attrs: {},
shouldUpdateRowContent: true
};
export default RowAggregatorContent;

View File

@@ -0,0 +1,178 @@
/* eslint react/prop-types: 0 */
/* eslint react/no-array-index-key: 0 */
import React from 'react';
import PropTypes from 'prop-types';
import _ from './utils';
import RowContent from './row-pure-content';
// import RowAggregatorContent from './row-aggregator-content';
import shouldRowUpdater from './row-should-updater';
import ExpandCell from './row-expand/expand-cell';
import SelectionCell from './row-selection/selection-cell';
// import Cell from './cell';
import eventDelegater from './row-event-delegater';
export default class RowAggregator extends shouldRowUpdater(eventDelegater(React.Component)) {
static propTypes = {
attrs: PropTypes.object,
style: PropTypes.object
}
static defaultProps = {
attrs: {},
style: {}
}
constructor(props) {
super(props);
this.clickNum = 0;
this.shouldUpdateRowContent = false;
this.createClickEventHandler = this.createClickEventHandler.bind(this);
}
shouldComponentUpdate(nextProps) {
if (
this.props.selected !== nextProps.selected ||
this.props.expanded !== nextProps.expanded ||
this.props.selectable !== nextProps.selectable ||
this.shouldUpdateByWhenEditing(nextProps) ||
this.shouldUpdatedBySelfProps(nextProps)
) {
this.shouldUpdateRowContent = this.shouldUpdatedByNormalProps(nextProps);
return true;
}
this.shouldUpdateRowContent = this.shouldUpdatedByNormalProps(nextProps);
return this.shouldUpdateRowContent;
}
createClickEventHandler(cb) {
return (e) => {
const {
row,
selected,
keyField,
selectable,
expandable,
rowIndex,
expanded,
expandRow,
selectRow,
DELAY_FOR_DBCLICK
} = this.props;
const clickFn = () => {
if (cb) {
cb(e, row, rowIndex);
}
const key = _.get(row, keyField);
if (expandRow && expandable) {
expandRow.onRowExpand(key, !expanded, rowIndex, e);
}
if (selectRow.clickToSelect && selectable) {
selectRow.onRowSelect(key, !selected, rowIndex, e);
}
};
if (DELAY_FOR_DBCLICK) {
this.clickNum += 1;
_.debounce(() => {
if (this.clickNum === 1) {
clickFn();
}
this.clickNum = 0;
}, DELAY_FOR_DBCLICK)();
} else {
clickFn();
}
};
}
render() {
const {
row,
columns,
keyField,
rowIndex,
style,
className,
attrs,
selectRow,
expandRow,
expanded,
selected,
selectable,
...rest
} = this.props;
const key = _.get(row, keyField);
const { hideSelectColumn, clickToSelect } = selectRow;
const { showExpandColumn } = expandRow;
const newAttrs = this.delegate({ ...attrs });
if (clickToSelect || !!expandRow.renderer) {
newAttrs.onClick = this.createClickEventHandler(newAttrs.onClick);
}
return (
<tr
style={ style }
className={ className }
{ ...newAttrs }
>
<td>123</td>
<td>12121212</td>
</tr>
);
// const content0 = _.get(row, columns[1].dataField);
// const content1 = _.get(row, columns[1].dataField);
// const content2 = _.get(row, columns[2].dataField);
// return (
// <tr
// style={ style }
// className={ className }
// onClick={ e => selectRow.onRowSelect(key, !selected, rowIndex, e) }
// >
// <td>1</td>
// <td>2</td>
// <td>3</td>
// <td>4</td>
// </tr>
// );
// const newCols = [{ fake: true }, ...columns];
// return (
// <tr
// style={ style }
// className={ className }
// { ...newAttrs }
// >
// {
// newCols.map((column, i) => {
// if (column.fake) {
// return (
// <Cell
// key={ `${key}_${i}_sel}` }
// column={ {} }
// row={ {} }
// rowIndex={ rowIndex }
// columnIndex={ i }
// >
// <input type="checkbox" />
// </Cell>
// );
// }
// const content = _.get(row, column.dataField);
// return (
// <Cell
// key={ `${key}_${content}}` }
// row={ row }
// rowIndex={ rowIndex }
// column={ column }
// columnIndex={ i }
// />
// );
// })
// }
// </tr>
// );
}
}

View File

@@ -2,21 +2,21 @@ const events = [
'onClick', 'onClick',
'onDoubleClick', 'onDoubleClick',
'onMouseEnter', 'onMouseEnter',
'onMouseLeave', 'onMouseLeave'
'onContextMenu'
]; ];
export default ExtendBase => export default ExtendBase =>
class CellEventDelegater extends ExtendBase { class RowEventDelegater extends ExtendBase {
constructor(props) { constructor(props) {
super(props); super(props);
this.clickNum = 0;
this.createDefaultEventHandler = this.createDefaultEventHandler.bind(this); this.createDefaultEventHandler = this.createDefaultEventHandler.bind(this);
} }
createDefaultEventHandler(cb) { createDefaultEventHandler(cb) {
return (e) => { return (e) => {
const { column, columnIndex } = this.props; const { row, rowIndex } = this.props;
cb(e, column, columnIndex); cb(e, row, rowIndex);
}; };
} }

View File

@@ -12,8 +12,7 @@ export default class ExpandCell extends Component {
expanded: PropTypes.bool.isRequired, expanded: PropTypes.bool.isRequired,
onRowExpand: PropTypes.func.isRequired, onRowExpand: PropTypes.func.isRequired,
expandColumnRenderer: PropTypes.func, expandColumnRenderer: PropTypes.func,
rowIndex: PropTypes.number, rowIndex: PropTypes.number
tabIndex: PropTypes.number
} }
constructor() { constructor() {
@@ -21,29 +20,17 @@ export default class ExpandCell extends Component {
this.handleClick = this.handleClick.bind(this); this.handleClick = this.handleClick.bind(this);
} }
shouldComponentUpdate(nextProps) {
const shouldUpdate =
this.props.rowIndex !== nextProps.rowIndex ||
this.props.expanded !== nextProps.expanded ||
this.props.rowKey !== nextProps.rowKey ||
this.props.tabIndex !== nextProps.tabIndex;
return shouldUpdate;
}
handleClick(e) { handleClick(e) {
const { rowKey, expanded, onRowExpand, rowIndex } = this.props; const { rowKey, expanded, onRowExpand, rowIndex } = this.props;
onRowExpand(rowKey, !expanded, rowIndex, e); onRowExpand(rowKey, expanded, rowIndex, e);
} }
render() { render() {
const { expanded, expandColumnRenderer, tabIndex } = this.props; const { expanded, expandColumnRenderer } = this.props;
const attrs = {};
if (tabIndex !== -1) attrs.tabIndex = tabIndex;
return ( return (
<td onClick={ this.handleClick } { ...attrs }> <td onClick={ this.handleClick }>
{ {
expandColumnRenderer ? expandColumnRenderer({ expandColumnRenderer ? expandColumnRenderer({
expanded expanded

View File

@@ -1,15 +1,19 @@
/* eslint react/prop-types: 0 */ /* eslint react/prop-types: 0 */
/* eslint react/no-array-index-key: 0 */ /* eslint react/no-array-index-key: 0 */
/* eslint no-plusplus: 0 */
import React from 'react'; import React from 'react';
import _ from '../utils'; import _ from './utils';
import Cell from '../cell'; import Cell from './cell';
export default class RowPureContent extends React.Component { export default class RowContent extends React.Component {
// shouldComponentUpdate(nextProps) {
// return this.shouldUpdatedByNormalProps(nextProps);
// }
shouldComponentUpdate(nextProps) { shouldComponentUpdate(nextProps) {
if (typeof nextProps.shouldUpdate !== 'undefined') { if (typeof this.props.shouldUpdate !== 'undefined') {
return nextProps.shouldUpdate; if (nextProps.shouldUpdate === this.props.shouldUpdate) {
return false;
}
} }
return true; return true;
} }
@@ -26,12 +30,9 @@ export default class RowPureContent extends React.Component {
onStart, onStart,
clickToEdit, clickToEdit,
dbclickToEdit, dbclickToEdit,
EditingCellComponent, EditingCellComponent
tabIndexStart
} = this.props; } = this.props;
let tabIndex = tabIndexStart;
return columns.map((column, index) => { return columns.map((column, index) => {
if (!column.hidden) { if (!column.hidden) {
const { dataField } = column; const { dataField } = column;
@@ -50,21 +51,13 @@ export default class RowPureContent extends React.Component {
// render cell // render cell
let cellTitle; let cellTitle;
let cellStyle = {}; let cellStyle = {};
let cellAttrs = { const cellAttrs = {
..._.isFunction(column.attrs) ..._.isFunction(column.attrs)
? column.attrs(content, row, rowIndex, index) ? column.attrs(content, row, rowIndex, index)
: column.attrs : column.attrs,
...column.events
}; };
if (column.events) {
const events = Object.assign({}, column.events);
Object.keys(Object.assign({}, column.events)).forEach((key) => {
const originFn = events[key];
events[key] = (...rest) => originFn(...rest, row, rowIndex);
});
cellAttrs = { ...cellAttrs, ...events };
}
const cellClasses = _.isFunction(column.classes) const cellClasses = _.isFunction(column.classes)
? column.classes(content, row, rowIndex, index) ? column.classes(content, row, rowIndex, index)
: column.classes; : column.classes;
@@ -99,10 +92,6 @@ export default class RowPureContent extends React.Component {
editableCell = column.editable(content, row, rowIndex, index); editableCell = column.editable(content, row, rowIndex, index);
} }
if (tabIndexStart !== -1) {
cellAttrs.tabIndex = tabIndex++;
}
return ( return (
<Cell <Cell
key={ `${content}-${index}` } key={ `${content}-${index}` }

View File

@@ -49,8 +49,7 @@ export default (Component) => {
/> />
); );
}; };
function withSelectionConsumer(props) {
function withConsumer(props) {
return ( return (
<SelectionContext.Consumer> <SelectionContext.Consumer>
{ selectRow => renderWithSelection(props, selectRow) } { selectRow => renderWithSelection(props, selectRow) }
@@ -58,6 +57,6 @@ export default (Component) => {
); );
} }
withConsumer.displayName = 'WithSelectionRowConsumer'; withSelectionConsumer.displayName = 'WithSelectionConsumer';
return withConsumer; return withSelectionConsumer;
}; };

View File

@@ -15,23 +15,21 @@ export default class SelectionCell extends Component {
onRowSelect: PropTypes.func, onRowSelect: PropTypes.func,
disabled: PropTypes.bool, disabled: PropTypes.bool,
rowIndex: PropTypes.number, rowIndex: PropTypes.number,
tabIndex: PropTypes.number,
clickToSelect: PropTypes.bool, clickToSelect: PropTypes.bool,
selectionRenderer: PropTypes.func selectionRenderer: PropTypes.func
} }
constructor() { constructor(props) {
super(); super(props);
this.handleClick = this.handleClick.bind(this); this.handleClick = this.handleClick.bind(this);
} }
shouldComponentUpdate(nextProps) { shouldComponentUpdate(nextProps) {
const shouldUpdate = const shouldUpdate =
this.props.rowIndex !== nextProps.rowIndex ||
this.props.selected !== nextProps.selected || this.props.selected !== nextProps.selected ||
this.props.disabled !== nextProps.disabled ||
this.props.rowKey !== nextProps.rowKey || this.props.rowKey !== nextProps.rowKey ||
this.props.tabIndex !== nextProps.tabIndex; this.props.rowIndex !== nextProps.rowIndex ||
this.props.disabled !== nextProps.disabled;
return shouldUpdate; return shouldUpdate;
} }
@@ -62,18 +60,14 @@ export default class SelectionCell extends Component {
mode: inputType, mode: inputType,
selected, selected,
disabled, disabled,
tabIndex,
selectionRenderer selectionRenderer
} = this.props; } = this.props;
const attrs = {};
if (tabIndex !== -1) attrs.tabIndex = tabIndex;
return ( return (
<BootstrapContext.Consumer> <BootstrapContext.Consumer>
{ {
({ bootstrap4 }) => ( ({ bootstrap4 }) => (
<td onClick={ this.handleClick } { ...attrs }> <td onClick={ this.handleClick }>
{ {
selectionRenderer ? selectionRenderer({ selectionRenderer ? selectionRenderer({
mode: inputType, mode: inputType,

View File

@@ -27,7 +27,6 @@ export default class SelectionHeaderCell extends Component {
mode: PropTypes.string.isRequired, mode: PropTypes.string.isRequired,
checkedStatus: PropTypes.string, checkedStatus: PropTypes.string,
onAllRowsSelect: PropTypes.func, onAllRowsSelect: PropTypes.func,
hideSelectAll: PropTypes.bool,
selectionHeaderRenderer: PropTypes.func selectionHeaderRenderer: PropTypes.func
} }
@@ -64,10 +63,7 @@ export default class SelectionHeaderCell extends Component {
CHECKBOX_STATUS_CHECKED, CHECKBOX_STATUS_INDETERMINATE, ROW_SELECT_MULTIPLE CHECKBOX_STATUS_CHECKED, CHECKBOX_STATUS_INDETERMINATE, ROW_SELECT_MULTIPLE
} = Const; } = Const;
const { mode, checkedStatus, selectionHeaderRenderer, hideSelectAll } = this.props; const { mode, checkedStatus, selectionHeaderRenderer } = this.props;
if (hideSelectAll) {
return <th data-row-selection />;
}
const checked = checkedStatus === CHECKBOX_STATUS_CHECKED; const checked = checkedStatus === CHECKBOX_STATUS_CHECKED;

View File

@@ -1,10 +1,9 @@
/* eslint react/prop-types: 0 */ /* eslint react/prop-types: 0 */
import _ from '../utils'; import _ from './utils';
export default ExtendBase => export default ExtendBase =>
class RowShouldUpdater extends ExtendBase { class RowShouldUpdater extends ExtendBase {
shouldUpdateByCellEditing(nextProps) { shouldUpdateByWhenEditing(nextProps) {
if (!(this.props.clickToEdit || this.props.dbclickToEdit)) return false;
return ( return (
nextProps.editingRowIdx === nextProps.rowIndex || nextProps.editingRowIdx === nextProps.rowIndex ||
(this.props.editingRowIdx === nextProps.rowIndex && (this.props.editingRowIdx === nextProps.rowIndex &&
@@ -24,14 +23,9 @@ export default ExtendBase =>
const shouldUpdate = const shouldUpdate =
this.props.rowIndex !== nextProps.rowIndex || this.props.rowIndex !== nextProps.rowIndex ||
this.props.editable !== nextProps.editable || this.props.editable !== nextProps.editable ||
!_.isEqual(this.props.row, nextProps.row) || this.props.columns.length !== nextProps.columns.length ||
this.props.columns.length !== nextProps.columns.length; !_.isEqual(this.props.row, nextProps.row);
return shouldUpdate; return shouldUpdate;
} }
shouldUpdateChild(nextProps) {
return this.shouldUpdateByCellEditing(nextProps) ||
this.shouldUpdatedByNormalProps(nextProps);
}
}; };

View File

@@ -1,117 +0,0 @@
/* eslint react/prop-types: 0 */
/* eslint no-plusplus: 0 */
import React from 'react';
import PropTypes from 'prop-types';
import _ from '../utils';
import ExpandCell from '../row-expand/expand-cell';
import SelectionCell from '../row-selection/selection-cell';
import shouldUpdater from './should-updater';
import eventDelegater from './event-delegater';
import RowPureContent from './row-pure-content';
export default class RowAggregator extends shouldUpdater(eventDelegater(React.Component)) {
static propTypes = {
attrs: PropTypes.object,
style: PropTypes.object
}
static defaultProps = {
attrs: {},
style: {}
}
constructor(props) {
super(props);
this.clickNum = 0;
this.shouldUpdateRowContent = false;
this.createClickEventHandler = this.createClickEventHandler.bind(this);
}
shouldComponentUpdate(nextProps) {
if (
this.props.selected !== nextProps.selected ||
this.props.expanded !== nextProps.expanded ||
this.props.selectable !== nextProps.selectable ||
this.shouldUpdatedBySelfProps(nextProps)
) {
this.shouldUpdateRowContent = this.shouldUpdateChild(nextProps);
return true;
}
this.shouldUpdateRowContent = this.shouldUpdateChild(nextProps);
return this.shouldUpdateRowContent;
}
render() {
const {
row,
columns,
keyField,
rowIndex,
style,
className,
attrs,
selectRow,
expandRow,
expanded,
selected,
selectable,
visibleColumnSize,
tabIndexCell,
...rest
} = this.props;
const key = _.get(row, keyField);
const { hideSelectColumn, clickToSelect } = selectRow;
const { showExpandColumn } = expandRow;
const newAttrs = this.delegate({ ...attrs });
if (clickToSelect || !!expandRow.renderer) {
newAttrs.onClick = this.createClickEventHandler(newAttrs.onClick);
}
let tabIndexStart = (rowIndex * visibleColumnSize) + 1;
return (
<tr
style={ style }
className={ className }
{ ...newAttrs }
>
{
showExpandColumn ? (
<ExpandCell
{ ...expandRow }
rowKey={ key }
rowIndex={ rowIndex }
expanded={ expanded }
tabIndex={ tabIndexCell ? tabIndexStart++ : -1 }
/>
) : null
}
{
!hideSelectColumn
? (
<SelectionCell
{ ...selectRow }
rowKey={ key }
rowIndex={ rowIndex }
selected={ selected }
disabled={ !selectable }
tabIndex={ tabIndexCell ? tabIndexStart++ : -1 }
/>
)
: null
}
<RowPureContent
row={ row }
columns={ columns }
keyField={ keyField }
rowIndex={ rowIndex }
shouldUpdate={ this.shouldUpdateRowContent }
tabIndexStart={ tabIndexCell ? tabIndexStart : -1 }
{ ...rest }
/>
</tr>
);
}
}

View File

@@ -1,83 +0,0 @@
import _ from '../utils';
import Const from '../const';
const events = [
'onClick',
'onDoubleClick',
'onMouseEnter',
'onMouseLeave',
'onContextMenu'
];
export default ExtendBase =>
class RowEventDelegater extends ExtendBase {
constructor(props) {
super(props);
this.clickNum = 0;
this.createDefaultEventHandler = this.createDefaultEventHandler.bind(this);
this.createClickEventHandler = this.createClickEventHandler.bind(this);
}
createClickEventHandler(cb) {
return (e) => {
const {
row,
selected,
keyField,
selectable,
expandable,
rowIndex,
expanded,
expandRow,
selectRow,
DELAY_FOR_DBCLICK
} = this.props;
const clickFn = () => {
if (cb) {
cb(e, row, rowIndex);
}
const key = _.get(row, keyField);
if (expandRow && expandable && !expandRow.expandByColumnOnly) {
if (
(selectRow.mode !== Const.ROW_SELECT_DISABLED && selectRow.clickToExpand) ||
selectRow.mode === Const.ROW_SELECT_DISABLED
) {
expandRow.onRowExpand(key, !expanded, rowIndex, e);
}
}
if (selectRow.clickToSelect && selectable) {
selectRow.onRowSelect(key, !selected, rowIndex, e);
}
};
if (DELAY_FOR_DBCLICK) {
this.clickNum += 1;
_.debounce(() => {
if (this.clickNum === 1) {
clickFn();
}
this.clickNum = 0;
}, DELAY_FOR_DBCLICK)();
} else {
clickFn();
}
};
}
createDefaultEventHandler(cb) {
return (e) => {
const { row, rowIndex } = this.props;
cb(e, row, rowIndex);
};
}
delegate(attrs = {}) {
const newAttrs = { ...attrs };
Object.keys(attrs).forEach((attr) => {
if (events.includes(attr)) {
newAttrs[attr] = this.createDefaultEventHandler(attrs[attr]);
}
});
return newAttrs;
}
};

View File

@@ -3,19 +3,18 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import RowPureContent from './row-pure-content'; import eventDelegater from './row-event-delegater';
import eventDelegater from './event-delegater'; import RowContent from './row-pure-content';
import shouldUpdater from './should-updater'; import shouldRowUpdater from './row-should-updater';
class SimpleRow extends shouldUpdater(eventDelegater(Component)) { class Row extends shouldRowUpdater(eventDelegater(Component)) {
constructor(props) { constructor(props) {
super(props); super(props);
this.shouldUpdateRowContent = false; this.shouldUpdateRowContent = false;
} }
shouldComponentUpdate(nextProps) { shouldComponentUpdate(nextProps) {
this.shouldUpdateRowContent = false; this.shouldUpdateRowContent = this.shouldUpdatedByNormalProps(nextProps);
this.shouldUpdateRowContent = this.shouldUpdateChild(nextProps);
if (this.shouldUpdateRowContent) return true; if (this.shouldUpdateRowContent) return true;
return this.shouldUpdatedBySelfProps(nextProps); return this.shouldUpdatedBySelfProps(nextProps);
@@ -26,26 +25,19 @@ class SimpleRow extends shouldUpdater(eventDelegater(Component)) {
className, className,
style, style,
attrs, attrs,
visibleColumnSize,
tabIndexCell,
...rest ...rest
} = this.props; } = this.props;
const trAttrs = this.delegate(attrs); const trAttrs = this.delegate(attrs);
const tabIndexStart = (this.props.rowIndex * visibleColumnSize) + 1;
return ( return (
<tr style={ style } className={ className } { ...trAttrs }> <tr style={ style } className={ className } { ...trAttrs }>
<RowPureContent <RowContent shouldUpdate={ this.shouldUpdateRowContent } { ...rest } />
shouldUpdate={ this.shouldUpdateRowContent }
tabIndexStart={ tabIndexCell ? tabIndexStart : -1 }
{ ...rest }
/>
</tr> </tr>
); );
} }
} }
SimpleRow.propTypes = { Row.propTypes = {
row: PropTypes.object.isRequired, row: PropTypes.object.isRequired,
rowIndex: PropTypes.number.isRequired, rowIndex: PropTypes.number.isRequired,
columns: PropTypes.array.isRequired, columns: PropTypes.array.isRequired,
@@ -54,11 +46,11 @@ SimpleRow.propTypes = {
attrs: PropTypes.object attrs: PropTypes.object
}; };
SimpleRow.defaultProps = { Row.defaultProps = {
editable: true, editable: true,
style: {}, style: {},
className: null, className: null,
attrs: {} attrs: {}
}; };
export default SimpleRow; export default Row;

View File

@@ -6,7 +6,7 @@ export const getSelectionSummary = (
keyField, keyField,
selected = [] selected = []
) => { ) => {
let allRowsSelected = data.length > 0; let allRowsSelected = true;
let allRowsNotSelected = true; let allRowsNotSelected = true;
const rowKeys = data.map(d => d[keyField]); const rowKeys = data.map(d => d[keyField]);

View File

@@ -4,10 +4,10 @@ import sinon from 'sinon';
import { shallow, mount } from 'enzyme'; import { shallow, mount } from 'enzyme';
import Body from '../src/body'; import Body from '../src/body';
import Row from '../src/row/simple-row'; import Row from '../src/row';
import RowAggregator from '../src/row/aggregate-row'; import RowAggregator from '../src/row-aggregator';
import Const from '../src/const'; import Const from '../src/const';
import RowSection from '../src/row/row-section'; import RowSection from '../src/row-section';
import SelectionContext from '../src/contexts/selection-context'; import SelectionContext from '../src/contexts/selection-context';
import ExpansionContext from '../src/contexts/row-expand-context'; import ExpansionContext from '../src/contexts/row-expand-context';
import mockBodyResolvedProps from './test-helpers/mock/body-resolved-props'; import mockBodyResolvedProps from './test-helpers/mock/body-resolved-props';
@@ -255,13 +255,14 @@ describe('Body', () => {
}); });
describe('when cellEdit.createContext props is defined', () => { describe('when cellEdit.createContext props is defined', () => {
const CellComponent = () => null;
const EditingCellComponent = () => null; const EditingCellComponent = () => null;
const RowComponent = props => <Row { ...props } />; const RowComponent = props => <Row { ...props } />;
const cellEdit = { const cellEdit = {
options: { onStartEdit: jest.fn() },
createContext: jest.fn(), createContext: jest.fn(),
bindCellLevelCellEdit: jest.fn().mockReturnValue(CellComponent),
createEditingCell: jest.fn().mockReturnValue(EditingCellComponent), createEditingCell: jest.fn().mockReturnValue(EditingCellComponent),
withRowLevelCellEdit: jest.fn().mockReturnValue(RowComponent) bindRowLevelCellEdit: jest.fn().mockReturnValue(RowComponent)
}; };
beforeEach(() => { beforeEach(() => {
wrapper = shallow( wrapper = shallow(
@@ -277,10 +278,12 @@ describe('Body', () => {
it('should render Row Component correctly', () => { it('should render Row Component correctly', () => {
expect(wrapper.length).toBe(1); expect(wrapper.length).toBe(1);
expect(cellEdit.bindCellLevelCellEdit).toHaveBeenCalledTimes(1);
expect(cellEdit.createEditingCell).toHaveBeenCalledTimes(1); expect(cellEdit.createEditingCell).toHaveBeenCalledTimes(1);
expect(cellEdit.withRowLevelCellEdit).toHaveBeenCalledTimes(1); expect(cellEdit.bindRowLevelCellEdit).toHaveBeenCalledTimes(1);
expect(wrapper.find(RowComponent)).toHaveLength(2); expect(wrapper.find(RowComponent)).toHaveLength(2);
const aRowElement = wrapper.find(RowComponent).get(0); const aRowElement = wrapper.find(RowComponent).get(0);
expect(aRowElement.props.CellComponent).toBeDefined();
expect(aRowElement.props.EditingCellComponent).toBeDefined(); expect(aRowElement.props.EditingCellComponent).toBeDefined();
}); });
}); });

View File

@@ -198,26 +198,6 @@ describe('Cell', () => {
}); });
}); });
describe('when props.tabIndex is change', () => {
const column = { dataField: 'name', text: 'Product Name' };
beforeEach(() => {
props = {
row,
columnIndex: 1,
rowIndex: 1,
tabIndex: 5,
column
};
wrapper = shallow(
<Cell { ...props } />);
});
it('should return true', () => {
nextProps = { ...props, tabIndex: 2 };
expect(wrapper.instance().shouldComponentUpdate(nextProps)).toBe(true);
});
});
describe('if column.isDummyField is true', () => { describe('if column.isDummyField is true', () => {
describe('when content is change', () => { describe('when content is change', () => {
const column = { dataField: '', text: 'Product Name', isDummyField: true }; const column = { dataField: '', text: 'Product Name', isDummyField: true };

View File

@@ -112,9 +112,9 @@ describe('Context', () => {
Provider: CellEditContext.Provider, Provider: CellEditContext.Provider,
Consumer: CellEditContext.Consumer Consumer: CellEditContext.Consumer
}), }),
options: {}, bindCellLevelCellEdit: jest.fn().mockReturnValue(() => null),
createEditingCell: jest.fn().mockReturnValue(() => null), createEditingCell: jest.fn().mockReturnValue(() => null),
withRowLevelCellEdit: jest.fn().mockReturnValue(() => null) bindRowLevelCellEdit: jest.fn().mockReturnValue(() => null)
}; };
wrapper = shallow( wrapper = shallow(
<BootstrapTable <BootstrapTable

View File

@@ -223,25 +223,6 @@ describe('DataContext', () => {
it('should set state.selected correctly', () => { it('should set state.selected correctly', () => {
expect(wrapper.state('selected')).toEqual(data.map(d => d[keyField])); expect(wrapper.state('selected')).toEqual(data.map(d => d[keyField]));
}); });
describe('when selectRow.onSelectAll is defined', () => {
const onSelectAll = jest.fn();
beforeEach(() => {
wrapper = shallow(shallowContext({
...defaultSelectRow,
onSelectAll
}));
wrapper.instance().handleAllRowsSelect(e, false);
});
it('should call selectRow.onSelectAll correctly', () => {
expect(onSelectAll).toHaveBeenCalledWith(
true,
dataOperator.getSelectedRows(data, keyField, wrapper.state('selected')),
e
);
});
});
}); });
describe('when isUnSelect argument is true', () => { describe('when isUnSelect argument is true', () => {
@@ -256,25 +237,24 @@ describe('DataContext', () => {
it('should set state.selected correctly', () => { it('should set state.selected correctly', () => {
expect(wrapper.state('selected')).toEqual([]); expect(wrapper.state('selected')).toEqual([]);
}); });
});
describe('when selectRow.onSelectAll is defined', () => { describe('when selectRow.onSelectAll is defined', () => {
const onSelectAll = jest.fn(); const onSelectAll = jest.fn();
beforeEach(() => { beforeEach(() => {
wrapper = shallow(shallowContext({ wrapper = shallow(shallowContext({
...defaultSelectRow, ...defaultSelectRow,
selected: data.map(d => d[keyField]), onSelectAll
onSelectAll }));
})); wrapper.instance().handleAllRowsSelect(e, false);
wrapper.instance().handleAllRowsSelect(e, true); });
});
it('should call selectRow.onSelectAll correctly', () => { it('should call selectRow.onSelectAll correctly', () => {
expect(onSelectAll).toHaveBeenCalledWith( expect(onSelectAll).toHaveBeenCalledWith(
false, true,
dataOperator.getSelectedRows(data, keyField, data.map(d => d[keyField])), dataOperator.getSelectedRows(data, keyField, wrapper.state('selected')),
e e
); );
});
}); });
}); });
}); });

View File

@@ -403,24 +403,6 @@ describe('HeaderCell', () => {
it('header should render SortSymbol as default', () => { it('header should render SortSymbol as default', () => {
expect(wrapper.find(SortSymbol).length).toBe(1); expect(wrapper.find(SortSymbol).length).toBe(1);
}); });
describe('when sortCaret is defined ', () => {
beforeEach(() => {
column = { ...column, sortCaret: jest.fn() };
wrapper = shallow(
<HeaderCell column={ column } index={ index } onSort={ onSortCallBack } />
);
});
it('header should not render SortSymbol', () => {
expect(wrapper.find(SortSymbol).length).toBe(0);
});
it('should call column.sortCaret correctly', () => {
expect(column.sortCaret).toHaveBeenCalledTimes(1);
expect(column.sortCaret).toHaveBeenCalledWith(undefined, column);
});
});
}); });
describe('and sorting prop is true', () => { describe('and sorting prop is true', () => {
@@ -438,30 +420,6 @@ describe('HeaderCell', () => {
}); });
}); });
describe('when sortCaret is defined ', () => {
beforeEach(() => {
column = { ...column, sortCaret: jest.fn() };
wrapper = shallow(
<HeaderCell
column={ column }
index={ index }
onSort={ onSortCallBack }
sortOrder={ Const.SORT_ASC }
sorting
/>
);
});
it('header should not render SortSymbol', () => {
expect(wrapper.find(SortSymbol).length).toBe(0);
});
it('should call column.sortCaret correctly', () => {
expect(column.sortCaret).toHaveBeenCalledTimes(1);
expect(column.sortCaret).toHaveBeenCalledWith(Const.SORT_ASC, column);
});
});
describe('when headerSortingClasses is defined ', () => { describe('when headerSortingClasses is defined ', () => {
const classes = 'foo'; const classes = 'foo';
const order = Const.SORT_DESC; const order = Const.SORT_DESC;

View File

@@ -1,14 +1,15 @@
import 'jsdom-global/register'; import 'jsdom-global/register';
import React from 'react'; import React from 'react';
import { mount } from 'enzyme'; import { mount } from 'enzyme';
import mockBodyResolvedProps from '../test-helpers/mock/body-resolved-props'; import mockBodyResolvedProps from './test-helpers/mock/body-resolved-props';
import SelectionContext from '../../src/contexts/selection-context'; import SelectionContext from '../src/contexts/selection-context';
import ExpansionContext from '../../src/contexts/row-expand-context'; import ExpansionContext from '../src/contexts/row-expand-context';
import bindSelection from '../../src/row-selection/row-consumer'; import bindSelection from '../src/row-selection/row-binder';
import bindExpansion from '../../src/row-expand/row-consumer'; import bindExpansion from '../src/row-expand/row-binder';
import ExpandCell from '../../src/row-expand/expand-cell'; import ExpandCell from '../src/row-expand/expand-cell';
import SelectionCell from '../../src/row-selection/selection-cell'; import SelectionCell from '../src/row-selection/selection-cell';
import RowAggregator from '../../src/row/aggregate-row'; import RowAggregator from '../src/row-aggregator';
import Row from '../src/row';
describe('Row Aggregator', () => { describe('Row Aggregator', () => {
let wrapper; let wrapper;
@@ -107,9 +108,9 @@ describe('Row Aggregator', () => {
}); });
it('should add onClick prop to Row Component', () => { it('should add onClick prop to Row Component', () => {
const tr = wrapper.find('tr'); const rowComp = wrapper.find(Row);
expect(tr).toHaveLength(1); expect(rowComp).toHaveLength(1);
expect(tr.props().onClick).toBeDefined(); expect(rowComp.props().attrs.onClick).toBeDefined();
}); });
}); });
}); });
@@ -215,7 +216,7 @@ describe('Row Aggregator', () => {
}); });
}); });
describe('if props.expandRow is not defined', () => { describe('if props.expandRow.renderer is defined', () => {
describe('but expandable props is false', () => { describe('but expandable props is false', () => {
const expandRow = { renderer: jest.fn(), nonExpandable: [row[keyField]] }; const expandRow = { renderer: jest.fn(), nonExpandable: [row[keyField]] };
beforeEach(() => { beforeEach(() => {
@@ -235,7 +236,7 @@ describe('Row Aggregator', () => {
}); });
}); });
describe('if props.expandRow is defined', () => { describe('if props.expandRow.renderer is defined', () => {
const expandRow = { renderer: jest.fn() }; const expandRow = { renderer: jest.fn() };
beforeEach(() => { beforeEach(() => {
wrapper = mount( wrapper = mount(
@@ -252,7 +253,7 @@ describe('Row Aggregator', () => {
}); });
}); });
describe('if props.attrs.onClick and props.expandRow both are defined', () => { describe('if props.attrs.onClick and props.expandRow.renderer both are defined', () => {
const attrs = { onClick: jest.fn() }; const attrs = { onClick: jest.fn() };
const expandRow = { renderer: jest.fn() }; const expandRow = { renderer: jest.fn() };

View File

@@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { shallow } from 'enzyme'; import { shallow } from 'enzyme';
import RowSection from '../../src/row/row-section'; import RowSection from '../src/row-section';
describe('Row', () => { describe('Row', () => {
const colSpan = 3; const colSpan = 3;

View File

@@ -3,13 +3,13 @@ import React from 'react';
import { mount } from 'enzyme'; import { mount } from 'enzyme';
import SelectionContext from '../../src/contexts/selection-context'; import SelectionContext from '../../src/contexts/selection-context';
import withSelectionConsumer from '../../src/row-selection/row-consumer'; import bindSelection from '../../src/row-selection/row-binder';
describe('withSelectionConsumer', () => { describe('Selection Row Binder', () => {
let wrapper; let wrapper;
let selectRow; let selectRow;
const BaseComponent = () => null; const BaseComponent = () => null;
const WithSelectionComponent = withSelectionConsumer(props => <BaseComponent { ...props } />); const WithSelectionComponent = bindSelection(props => <BaseComponent { ...props } />);
const data = [{ const data = [{
id: 1, id: 1,

View File

@@ -14,106 +14,24 @@ describe('<SelectionCell />', () => {
let wrapper; let wrapper;
describe('shouldComponentUpdate', () => { describe('shouldComponentUpdate', () => {
let props; const selected = true;
let nextProps;
describe('when selected prop has not been changed', () => {
it('should not update component', () => {
const nextProps = { selected };
wrapper = shallow(<SelectionCell rowKey={ 1 } mode={ mode } selected={ selected } />);
expect(wrapper.instance().shouldComponentUpdate(nextProps)).toBe(false);
});
});
describe('when selected prop has been changed', () => { describe('when selected prop has been changed', () => {
beforeEach(() => { it('should update component', () => {
props = { const nextProps = { selected: !selected };
selected: false,
mode,
rowIndex,
disabled: false,
rowKey: 1
};
wrapper = shallow(
<SelectionCell { ...props } />
);
});
it('should return true', () => { wrapper = shallow(<SelectionCell rowKey={ 1 } mode={ mode } selected={ selected } />);
nextProps = { ...props, selected: true };
expect(wrapper.instance().shouldComponentUpdate(nextProps)).toBe(true);
});
});
describe('when rowIndex prop has been changed', () => {
beforeEach(() => {
props = {
selected: false,
mode,
rowIndex,
disabled: false,
rowKey: 1
};
wrapper = shallow(
<SelectionCell { ...props } />
);
});
it('should return true', () => {
nextProps = { ...props, rowIndex: 2 };
expect(wrapper.instance().shouldComponentUpdate(nextProps)).toBe(true);
});
});
describe('when tabIndex prop has been changed', () => {
beforeEach(() => {
props = {
selected: false,
mode,
rowIndex,
disabled: false,
tabIndex: 0,
rowKey: 1
};
wrapper = shallow(
<SelectionCell { ...props } />
);
});
it('should return true', () => {
nextProps = { ...props, tabIndex: 2 };
expect(wrapper.instance().shouldComponentUpdate(nextProps)).toBe(true);
});
});
describe('when disabled prop has been changed', () => {
beforeEach(() => {
props = {
selected: false,
mode,
rowIndex,
disabled: false,
rowKey: 1
};
wrapper = shallow(
<SelectionCell { ...props } />
);
});
it('should return true', () => {
nextProps = { ...props, disabled: true };
expect(wrapper.instance().shouldComponentUpdate(nextProps)).toBe(true);
});
});
describe('when rowKey prop has been changed', () => {
beforeEach(() => {
props = {
selected: false,
mode,
rowIndex,
disabled: false,
rowKey: 1
};
wrapper = shallow(
<SelectionCell { ...props } />
);
});
it('should return true', () => {
nextProps = { ...props, rowKey: '1' };
expect(wrapper.instance().shouldComponentUpdate(nextProps)).toBe(true); expect(wrapper.instance().shouldComponentUpdate(nextProps)).toBe(true);
}); });
}); });

View File

@@ -104,22 +104,6 @@ describe('<SelectionHeaderCell />', () => {
}); });
describe('render', () => { describe('render', () => {
describe('when props.hideSelectAll is true', () => {
beforeEach(() => {
const checkedStatus = Const.CHECKBOX_STATUS_CHECKED;
wrapper = shallow(
<SelectionHeaderCell mode="checkbox" checkedStatus={ checkedStatus } hideSelectAll />
);
});
it('should render empty th element', () => {
expect(wrapper.find('th').length).toBe(1);
expect(wrapper.find('th[data-row-selection]').length).toBe(1);
expect(wrapper.find(CheckBox).length).toBe(0);
});
});
describe('when props.mode is radio', () => { describe('when props.mode is radio', () => {
beforeEach(() => { beforeEach(() => {
const checkedStatus = Const.CHECKBOX_STATUS_CHECKED; const checkedStatus = Const.CHECKBOX_STATUS_CHECKED;

View File

@@ -1,9 +1,10 @@
import React from 'react'; import React from 'react';
import sinon from 'sinon';
import { shallow } from 'enzyme'; import { shallow } from 'enzyme';
import Cell from '../../src/cell'; import Cell from '../src/cell';
import RowPureContent from '../../src/row/row-pure-content'; import Row from '../src/row';
import mockBodyResolvedProps from '../test-helpers/mock/body-resolved-props'; import mockBodyResolvedProps from './test-helpers/mock/body-resolved-props';
let defaultColumns = [{ let defaultColumns = [{
dataField: 'id', dataField: 'id',
@@ -19,7 +20,7 @@ let defaultColumns = [{
const keyField = 'id'; const keyField = 'id';
const rowIndex = 1; const rowIndex = 1;
describe('RowPureContent', () => { describe('Row', () => {
let wrapper; let wrapper;
const row = { const row = {
@@ -41,55 +42,11 @@ describe('RowPureContent', () => {
}]; }];
}); });
describe('shouldComponentUpdate', () => {
let props;
let nextProps;
describe('if nextProps.shouldUpdate is different with this.props.shouldUpdate', () => {
beforeEach(() => {
props = {
keyField,
columns: defaultColumns,
rowIndex: 1,
row,
shouldUpdate: false
};
wrapper = shallow(
<RowPureContent { ...props } />
);
});
it('should return true', () => {
nextProps = { ...props, shouldUpdate: true };
expect(wrapper.instance().shouldComponentUpdate(nextProps)).toBe(true);
});
});
describe('if nextProps.shouldUpdate is same with this.props.shouldUpdate', () => {
beforeEach(() => {
props = {
keyField,
columns: defaultColumns,
rowIndex: 1,
row,
shouldUpdate: false
};
wrapper = shallow(
<RowPureContent { ...props } />
);
});
it('should return false', () => {
nextProps = { ...props };
expect(wrapper.instance().shouldComponentUpdate(nextProps)).toBe(false);
});
});
});
describe('simplest row', () => { describe('simplest row', () => {
beforeEach(() => { beforeEach(() => {
wrapper = shallow( wrapper = shallow(
<RowPureContent <Row
{ ...mockBodyResolvedProps }
keyField={ keyField } keyField={ keyField }
rowIndex={ rowIndex } rowIndex={ rowIndex }
columns={ defaultColumns } columns={ defaultColumns }
@@ -99,49 +56,66 @@ describe('RowPureContent', () => {
}); });
it('should render successfully', () => { it('should render successfully', () => {
expect(wrapper.length).toBe(defaultColumns.length); expect(wrapper.length).toBe(1);
expect(wrapper.find('tr').length).toBe(1);
expect(wrapper.find(Cell).length).toBe(Object.keys(row).length); expect(wrapper.find(Cell).length).toBe(Object.keys(row).length);
}); });
}); });
describe('when tabIndexStart prop is -1', () => { describe('when style prop is defined', () => {
const customStyle = { backgroundColor: 'red' };
beforeEach(() => { beforeEach(() => {
wrapper = shallow( wrapper = shallow(
<RowPureContent <Row
tabIndexStart={ -1 } { ...mockBodyResolvedProps }
keyField={ keyField }
rowIndex={ rowIndex } rowIndex={ rowIndex }
columns={ defaultColumns } columns={ defaultColumns }
row={ row } row={ row }
/> style={ customStyle }
); />);
}); });
it('should not render tabIndex prop on Cell', () => { it('should render component with style successfully', () => {
wrapper.find(Cell).forEach((cell) => { expect(wrapper.length).toBe(1);
expect(cell.prop('tabIndex')).toBeUndefined(); expect(wrapper.prop('style')).toEqual(customStyle);
});
}); });
}); });
describe('when tabIndexStart prop is not -1', () => { describe('when className prop is defined', () => {
const tabIndexStart = 4; const className = 'test-class';
beforeEach(() => { beforeEach(() => {
wrapper = shallow( wrapper = shallow(
<RowPureContent <Row
tabIndexStart={ tabIndexStart } { ...mockBodyResolvedProps }
keyField={ keyField }
rowIndex={ rowIndex } rowIndex={ rowIndex }
columns={ defaultColumns } columns={ defaultColumns }
row={ row } row={ row }
/> className={ className }
); />);
}); });
it('should render correct tabIndex prop on Cell', () => { it('should render component with className successfully', () => {
wrapper.find(Cell).forEach((cell, i) => { expect(wrapper.length).toBe(1);
expect(cell.prop('tabIndex')).toEqual(tabIndexStart + i); expect(wrapper.hasClass(className)).toBe(true);
}); });
});
describe('when CellComponent prop is defined', () => {
const CellComponent = () => null;
beforeEach(() => {
wrapper = shallow(
<Row
{ ...mockBodyResolvedProps }
rowIndex={ rowIndex }
columns={ defaultColumns }
row={ row }
CellComponent={ CellComponent }
/>);
});
it('should render CellComponent successfully', () => {
expect(wrapper.length).toBe(1);
expect(wrapper.find(CellComponent)).toHaveLength(defaultColumns.length);
}); });
}); });
@@ -151,8 +125,8 @@ describe('RowPureContent', () => {
const EditingCellComponent = () => null; const EditingCellComponent = () => null;
beforeEach(() => { beforeEach(() => {
wrapper = shallow( wrapper = shallow(
<RowPureContent <Row
keyField={ keyField } { ...mockBodyResolvedProps }
rowIndex={ rowIndex } rowIndex={ rowIndex }
columns={ defaultColumns } columns={ defaultColumns }
row={ row } row={ row }
@@ -164,7 +138,7 @@ describe('RowPureContent', () => {
it('should render EditingCell component correctly', () => { it('should render EditingCell component correctly', () => {
const EditingCell = wrapper.find(EditingCellComponent); const EditingCell = wrapper.find(EditingCellComponent);
expect(wrapper.length).toBe(defaultColumns.length); expect(wrapper.length).toBe(1);
expect(EditingCell).toHaveLength(1); expect(EditingCell).toHaveLength(1);
expect(EditingCell.prop('row')).toEqual(row); expect(EditingCell.prop('row')).toEqual(row);
expect(EditingCell.prop('rowIndex')).toEqual(editingRowIdx); expect(EditingCell.prop('rowIndex')).toEqual(editingRowIdx);
@@ -173,6 +147,27 @@ describe('RowPureContent', () => {
}); });
}); });
describe('when attrs prop is defined', () => {
const customClickCallBack = sinon.stub();
const attrs = { 'data-index': 1, onClick: customClickCallBack };
beforeEach(() => {
wrapper = shallow(
<Row
{ ...mockBodyResolvedProps }
rowIndex={ rowIndex }
columns={ defaultColumns }
row={ row }
attrs={ attrs }
/>);
});
it('should render component with correct attributes', () => {
expect(wrapper.length).toBe(1);
expect(wrapper.prop('data-index')).toBe(attrs['data-index']);
expect(wrapper.prop('onClick')).toBeDefined();
});
});
describe('when column.hidden is true', () => { describe('when column.hidden is true', () => {
beforeEach(() => { beforeEach(() => {
const newColumns = [{ const newColumns = [{
@@ -187,8 +182,8 @@ describe('RowPureContent', () => {
text: 'Price' text: 'Price'
}]; }];
wrapper = shallow( wrapper = shallow(
<RowPureContent <Row
keyField={ keyField } { ...mockBodyResolvedProps }
rowIndex={ rowIndex } rowIndex={ rowIndex }
columns={ newColumns } columns={ newColumns }
row={ row } row={ row }
@@ -212,7 +207,8 @@ describe('RowPureContent', () => {
beforeEach(() => { beforeEach(() => {
columns[columnIndex].style = { backgroundColor: 'red' }; columns[columnIndex].style = { backgroundColor: 'red' };
wrapper = shallow( wrapper = shallow(
<RowPureContent <Row
{ ...mockBodyResolvedProps }
keyField={ keyField } keyField={ keyField }
rowIndex={ rowIndex } rowIndex={ rowIndex }
columns={ columns } columns={ columns }
@@ -222,7 +218,7 @@ describe('RowPureContent', () => {
}); });
it('should render Cell correctly', () => { it('should render Cell correctly', () => {
expect(wrapper.length).toBe(defaultColumns.length); expect(wrapper.length).toBe(1);
expect(wrapper.find(Cell).get(columnIndex).props.style).toEqual(columns[columnIndex].style); expect(wrapper.find(Cell).get(columnIndex).props.style).toEqual(columns[columnIndex].style);
}); });
}); });
@@ -232,10 +228,11 @@ describe('RowPureContent', () => {
let styleCallBack; let styleCallBack;
beforeEach(() => { beforeEach(() => {
styleCallBack = jest.fn().mockReturnValue(returnStyle); styleCallBack = sinon.stub().returns(returnStyle);
columns[columnIndex].style = styleCallBack; columns[columnIndex].style = styleCallBack;
wrapper = shallow( wrapper = shallow(
<RowPureContent <Row
{ ...mockBodyResolvedProps }
keyField={ keyField } keyField={ keyField }
rowIndex={ rowIndex } rowIndex={ rowIndex }
columns={ columns } columns={ columns }
@@ -244,17 +241,18 @@ describe('RowPureContent', () => {
); );
}); });
afterEach(() => { styleCallBack.mockClear(); }); afterEach(() => { styleCallBack.reset(); });
it('should render Cell correctly', () => { it('should render Cell correctly', () => {
expect(wrapper.length).toBe(defaultColumns.length); expect(wrapper.length).toBe(1);
expect(wrapper.find(Cell).get(columnIndex).props.style).toEqual(returnStyle); expect(wrapper.find(Cell).get(columnIndex).props.style).toEqual(returnStyle);
}); });
it('should call custom style function correctly', () => { it('should call custom style function correctly', () => {
expect(styleCallBack).toHaveBeenCalledTimes(1); expect(styleCallBack.callCount).toBe(1);
expect(styleCallBack).toHaveBeenCalledWith( expect(
row[columns[columnIndex].dataField], row, rowIndex, columnIndex); styleCallBack.calledWith(row[columns[columnIndex].dataField], row, rowIndex, columnIndex)
).toBe(true);
}); });
}); });
}); });
@@ -271,7 +269,8 @@ describe('RowPureContent', () => {
beforeEach(() => { beforeEach(() => {
columns[columnIndex].classes = 'td-test-class'; columns[columnIndex].classes = 'td-test-class';
wrapper = shallow( wrapper = shallow(
<RowPureContent <Row
{ ...mockBodyResolvedProps }
keyField={ keyField } keyField={ keyField }
rowIndex={ rowIndex } rowIndex={ rowIndex }
columns={ columns } columns={ columns }
@@ -281,7 +280,7 @@ describe('RowPureContent', () => {
}); });
it('should render Cell correctly', () => { it('should render Cell correctly', () => {
expect(wrapper.length).toBe(defaultColumns.length); expect(wrapper.length).toBe(1);
expect(wrapper.find(Cell).get(columnIndex).props.className) expect(wrapper.find(Cell).get(columnIndex).props.className)
.toEqual(columns[columnIndex].classes); .toEqual(columns[columnIndex].classes);
}); });
@@ -292,10 +291,11 @@ describe('RowPureContent', () => {
let classesCallBack; let classesCallBack;
beforeEach(() => { beforeEach(() => {
classesCallBack = jest.fn().mockReturnValue(returnClasses); classesCallBack = sinon.stub().returns(returnClasses);
columns[columnIndex].classes = classesCallBack; columns[columnIndex].classes = classesCallBack;
wrapper = shallow( wrapper = shallow(
<RowPureContent <Row
{ ...mockBodyResolvedProps }
keyField={ keyField } keyField={ keyField }
rowIndex={ rowIndex } rowIndex={ rowIndex }
columns={ columns } columns={ columns }
@@ -304,17 +304,19 @@ describe('RowPureContent', () => {
); );
}); });
afterEach(() => { classesCallBack.mockClear(); }); afterEach(() => { classesCallBack.reset(); });
it('should render Cell correctly', () => { it('should render Cell correctly', () => {
expect(wrapper.length).toBe(defaultColumns.length); expect(wrapper.length).toBe(1);
expect(wrapper.find(Cell).get(columnIndex).props.className).toEqual(returnClasses); expect(wrapper.find(Cell).get(columnIndex).props.className).toEqual(returnClasses);
}); });
it('should call custom classes function correctly', () => { it('should call custom classes function correctly', () => {
expect(classesCallBack).toHaveBeenCalledTimes(1); expect(classesCallBack.callCount).toBe(1);
expect(classesCallBack).toHaveBeenCalledWith( expect(
row[columns[columnIndex].dataField], row, rowIndex, columnIndex); classesCallBack.calledWith(
row[columns[columnIndex].dataField], row, rowIndex, columnIndex)
).toBe(true);
}); });
}); });
}); });
@@ -331,7 +333,8 @@ describe('RowPureContent', () => {
beforeEach(() => { beforeEach(() => {
columns[columnIndex].title = true; columns[columnIndex].title = true;
wrapper = shallow( wrapper = shallow(
<RowPureContent <Row
{ ...mockBodyResolvedProps }
keyField={ keyField } keyField={ keyField }
rowIndex={ rowIndex } rowIndex={ rowIndex }
columns={ columns } columns={ columns }
@@ -341,7 +344,7 @@ describe('RowPureContent', () => {
}); });
it('should render Cell correctly', () => { it('should render Cell correctly', () => {
expect(wrapper.length).toBe(defaultColumns.length); expect(wrapper.length).toBe(1);
expect(wrapper.find(Cell).get(columnIndex).props.title) expect(wrapper.find(Cell).get(columnIndex).props.title)
.toEqual(row[columns[columnIndex].dataField]); .toEqual(row[columns[columnIndex].dataField]);
}); });
@@ -352,10 +355,11 @@ describe('RowPureContent', () => {
let titleCallBack; let titleCallBack;
beforeEach(() => { beforeEach(() => {
titleCallBack = jest.fn().mockReturnValue(returnTitle); titleCallBack = sinon.stub().returns(returnTitle);
columns[columnIndex].title = titleCallBack; columns[columnIndex].title = titleCallBack;
wrapper = shallow( wrapper = shallow(
<RowPureContent <Row
{ ...mockBodyResolvedProps }
keyField={ keyField } keyField={ keyField }
rowIndex={ rowIndex } rowIndex={ rowIndex }
columns={ columns } columns={ columns }
@@ -364,17 +368,19 @@ describe('RowPureContent', () => {
); );
}); });
afterEach(() => { titleCallBack.mockClear(); }); afterEach(() => { titleCallBack.reset(); });
it('should render Cell correctly', () => { it('should render Cell correctly', () => {
expect(wrapper.length).toBe(defaultColumns.length); expect(wrapper.length).toBe(1);
expect(wrapper.find(Cell).get(columnIndex).props.title).toEqual(returnTitle); expect(wrapper.find(Cell).get(columnIndex).props.title).toEqual(returnTitle);
}); });
it('should call custom title function correctly', () => { it('should call custom title function correctly', () => {
expect(titleCallBack).toHaveBeenCalledTimes(1); expect(titleCallBack.callCount).toBe(1);
expect(titleCallBack).toHaveBeenCalledWith( expect(
row[columns[columnIndex].dataField], row, rowIndex, columnIndex); titleCallBack.calledWith(
row[columns[columnIndex].dataField], row, rowIndex, columnIndex)
).toBe(true);
}); });
}); });
}); });
@@ -386,11 +392,12 @@ describe('RowPureContent', () => {
beforeEach(() => { beforeEach(() => {
columns = [...defaultColumns]; columns = [...defaultColumns];
columns[columnIndex].events = { columns[columnIndex].events = {
onClick: jest.fn() onClick: sinon.stub()
}; };
wrapper = shallow( wrapper = shallow(
<RowPureContent <Row
{ ...mockBodyResolvedProps }
keyField={ keyField } keyField={ keyField }
rowIndex={ rowIndex } rowIndex={ rowIndex }
columns={ columns } columns={ columns }
@@ -400,7 +407,7 @@ describe('RowPureContent', () => {
}); });
it('should attachs DOM event successfully', () => { it('should attachs DOM event successfully', () => {
expect(wrapper.length).toBe(defaultColumns.length); expect(wrapper.length).toBe(1);
expect(wrapper.find(Cell).get(columnIndex).props.onClick).toBeDefined(); expect(wrapper.find(Cell).get(columnIndex).props.onClick).toBeDefined();
}); });
}); });
@@ -417,7 +424,8 @@ describe('RowPureContent', () => {
beforeEach(() => { beforeEach(() => {
columns[columnIndex].align = 'right'; columns[columnIndex].align = 'right';
wrapper = shallow( wrapper = shallow(
<RowPureContent <Row
{ ...mockBodyResolvedProps }
keyField={ keyField } keyField={ keyField }
rowIndex={ rowIndex } rowIndex={ rowIndex }
columns={ columns } columns={ columns }
@@ -427,7 +435,7 @@ describe('RowPureContent', () => {
}); });
it('should render Cell correctly', () => { it('should render Cell correctly', () => {
expect(wrapper.length).toBe(defaultColumns.length); expect(wrapper.length).toBe(1);
expect(wrapper.find(Cell).get(columnIndex).props.style.textAlign) expect(wrapper.find(Cell).get(columnIndex).props.style.textAlign)
.toEqual(columns[columnIndex].align); .toEqual(columns[columnIndex].align);
}); });
@@ -438,10 +446,10 @@ describe('RowPureContent', () => {
let alignCallBack; let alignCallBack;
beforeEach(() => { beforeEach(() => {
alignCallBack = jest.fn().mockReturnValue(returnAlign); alignCallBack = sinon.stub().returns(returnAlign);
columns[columnIndex].align = alignCallBack; columns[columnIndex].align = alignCallBack;
wrapper = shallow( wrapper = shallow(
<RowPureContent <Row
{ ...mockBodyResolvedProps } { ...mockBodyResolvedProps }
keyField={ keyField } keyField={ keyField }
rowIndex={ rowIndex } rowIndex={ rowIndex }
@@ -451,17 +459,18 @@ describe('RowPureContent', () => {
); );
}); });
afterEach(() => { alignCallBack.mockClear(); }); afterEach(() => { alignCallBack.reset(); });
it('should render Cell correctly', () => { it('should render Cell correctly', () => {
expect(wrapper.length).toBe(defaultColumns.length); expect(wrapper.length).toBe(1);
expect(wrapper.find(Cell).get(columnIndex).props.style.textAlign).toEqual(returnAlign); expect(wrapper.find(Cell).get(columnIndex).props.style.textAlign).toEqual(returnAlign);
}); });
it('should call custom align function correctly', () => { it('should call custom align function correctly', () => {
expect(alignCallBack).toHaveBeenCalledTimes(1); expect(alignCallBack.callCount).toBe(1);
expect(alignCallBack).toHaveBeenCalledWith( expect(
row[columns[columnIndex].dataField], row, rowIndex, columnIndex); alignCallBack.calledWith(row[columns[columnIndex].dataField], row, rowIndex, columnIndex)
).toBe(true);
}); });
}); });
}); });
@@ -488,7 +497,8 @@ describe('RowPureContent', () => {
}; };
wrapper = shallow( wrapper = shallow(
<RowPureContent <Row
{ ...mockBodyResolvedProps }
keyField={ keyField } keyField={ keyField }
rowIndex={ rowIndex } rowIndex={ rowIndex }
columns={ columns } columns={ columns }
@@ -496,7 +506,7 @@ describe('RowPureContent', () => {
/> />
); );
expect(wrapper.length).toBe(defaultColumns.length); expect(wrapper.length).toBe(1);
expect(wrapper.find(Cell).get(columnIndex).props['data-test']) expect(wrapper.find(Cell).get(columnIndex).props['data-test'])
.toEqual(columns[columnIndex].attrs['data-test']); .toEqual(columns[columnIndex].attrs['data-test']);
expect(wrapper.find(Cell).get(columnIndex).props.title) expect(wrapper.find(Cell).get(columnIndex).props.title)
@@ -513,7 +523,8 @@ describe('RowPureContent', () => {
columns[columnIndex].attrs = { title: 'title' }; columns[columnIndex].attrs = { title: 'title' };
wrapper = shallow( wrapper = shallow(
<RowPureContent <Row
{ ...mockBodyResolvedProps }
keyField={ keyField } keyField={ keyField }
rowIndex={ rowIndex } rowIndex={ rowIndex }
columns={ columns } columns={ columns }
@@ -532,7 +543,8 @@ describe('RowPureContent', () => {
columns[columnIndex].attrs = { className: 'attrs-class' }; columns[columnIndex].attrs = { className: 'attrs-class' };
wrapper = shallow( wrapper = shallow(
<RowPureContent <Row
{ ...mockBodyResolvedProps }
keyField={ keyField } keyField={ keyField }
rowIndex={ rowIndex } rowIndex={ rowIndex }
columns={ columns } columns={ columns }
@@ -551,7 +563,8 @@ describe('RowPureContent', () => {
columns[columnIndex].attrs = { style: { backgroundColor: 'attrs-style-test' } }; columns[columnIndex].attrs = { style: { backgroundColor: 'attrs-style-test' } };
wrapper = shallow( wrapper = shallow(
<RowPureContent <Row
{ ...mockBodyResolvedProps }
keyField={ keyField } keyField={ keyField }
rowIndex={ rowIndex } rowIndex={ rowIndex }
columns={ columns } columns={ columns }
@@ -570,7 +583,8 @@ describe('RowPureContent', () => {
columns[columnIndex].attrs = { style: { textAlign: 'right' } }; columns[columnIndex].attrs = { style: { textAlign: 'right' } };
wrapper = shallow( wrapper = shallow(
<RowPureContent <Row
{ ...mockBodyResolvedProps }
keyField={ keyField } keyField={ keyField }
rowIndex={ rowIndex } rowIndex={ rowIndex }
columns={ columns } columns={ columns }
@@ -592,10 +606,11 @@ describe('RowPureContent', () => {
}; };
beforeEach(() => { beforeEach(() => {
attrsCallBack = jest.fn().mockReturnValue(customAttrs); attrsCallBack = sinon.stub().returns(customAttrs);
columns[columnIndex].attrs = attrsCallBack; columns[columnIndex].attrs = attrsCallBack;
wrapper = shallow( wrapper = shallow(
<RowPureContent <Row
{ ...mockBodyResolvedProps }
keyField={ keyField } keyField={ keyField }
rowIndex={ rowIndex } rowIndex={ rowIndex }
columns={ columns } columns={ columns }
@@ -604,10 +619,8 @@ describe('RowPureContent', () => {
); );
}); });
afterEach(() => { attrsCallBack.mockClear(); });
it('should render style.attrs correctly', () => { it('should render style.attrs correctly', () => {
expect(wrapper.length).toBe(defaultColumns.length); expect(wrapper.length).toBe(1);
expect(wrapper.find(Cell).get(columnIndex).props['data-test']) expect(wrapper.find(Cell).get(columnIndex).props['data-test'])
.toEqual(customAttrs['data-test']); .toEqual(customAttrs['data-test']);
expect(wrapper.find(Cell).get(columnIndex).props.title) expect(wrapper.find(Cell).get(columnIndex).props.title)
@@ -615,9 +628,10 @@ describe('RowPureContent', () => {
}); });
it('should call custom attrs function correctly', () => { it('should call custom attrs function correctly', () => {
expect(attrsCallBack).toHaveBeenCalledTimes(1); expect(attrsCallBack.callCount).toBe(1);
expect(attrsCallBack).toHaveBeenCalledWith( expect(
row[columns[columnIndex].dataField], row, rowIndex, columnIndex); attrsCallBack.calledWith(row[columns[columnIndex].dataField], row, rowIndex, columnIndex)
).toBe(true);
}); });
}); });
}); });

View File

@@ -1,164 +0,0 @@
import React from 'react';
import { shallow } from 'enzyme';
import shouldUpdater from '../../src/row/should-updater';
describe('Row shouldUpdater', () => {
let wrapper;
let props;
let nextProps;
class DummyComponent extends shouldUpdater(React.Component) {
render() { return null; }
}
describe('shouldUpdateByCellEditing', () => {
describe('when nextProps.clickToEdit and nexrProps.dbclickToEdit both are negative', () => {
beforeEach(() => {
props = {
editingRowIdx: null,
rowIndex: 0
};
wrapper = shallow(<DummyComponent { ...props } />);
});
it('should always return false', () => {
nextProps = { ...props, editingRowIdx: 0 };
expect(wrapper.instance().shouldUpdateByCellEditing(nextProps)).toBeFalsy();
});
});
describe('when nextProps.editingRowIdx eq props.rowIndex and it\' not null', () => {
beforeEach(() => {
props = {
clickToEdit: true,
editingRowIdx: null,
rowIndex: 0
};
wrapper = shallow(<DummyComponent { ...props } />);
});
it('should return true', () => {
nextProps = { ...props, editingRowIdx: 0 };
expect(wrapper.instance().shouldUpdateByCellEditing(nextProps)).toBeTruthy();
});
});
describe('when props.editingRowIdx eq props.rowIndex but nextProps.editingRowIdx is null', () => {
beforeEach(() => {
props = {
clickToEdit: true,
editingRowIdx: 0,
rowIndex: 0
};
wrapper = shallow(<DummyComponent { ...props } />);
});
it('should return true', () => {
nextProps = { ...props, editingRowIdx: null };
expect(wrapper.instance().shouldUpdateByCellEditing(nextProps)).toBeTruthy();
});
});
});
describe('shouldUpdatedBySelfProps', () => {
describe('when nextProps.className is not eq props.className', () => {
beforeEach(() => {
props = {
className: ''
};
wrapper = shallow(<DummyComponent { ...props } />);
});
it('should return true', () => {
nextProps = { ...props, className: 'test' };
expect(wrapper.instance().shouldUpdatedBySelfProps(nextProps)).toBeTruthy();
});
});
describe('when nextProps.style is not eq props.style', () => {
beforeEach(() => {
props = {
style: null
};
wrapper = shallow(<DummyComponent { ...props } />);
});
it('should return true', () => {
nextProps = { ...props, style: { color: 'red' } };
expect(wrapper.instance().shouldUpdatedBySelfProps(nextProps)).toBeTruthy();
});
});
describe('when nextProps.attrs is not eq props.attrs', () => {
beforeEach(() => {
props = {
attrs: null
};
wrapper = shallow(<DummyComponent { ...props } />);
});
it('should return true', () => {
nextProps = { ...props, attrs: { onClick: jest.fn() } };
expect(wrapper.instance().shouldUpdatedBySelfProps(nextProps)).toBeTruthy();
});
});
});
describe('shouldUpdatedByNormalProps', () => {
describe('when nextProps.rowIndex is not eq props.rowIndex', () => {
beforeEach(() => {
props = {
rowIndex: 0
};
wrapper = shallow(<DummyComponent { ...props } />);
});
it('should return true', () => {
nextProps = { ...props, rowIndex: 1 };
expect(wrapper.instance().shouldUpdatedByNormalProps(nextProps)).toBeTruthy();
});
});
describe('when nextProps.editable is not eq props.editable', () => {
beforeEach(() => {
props = {
editable: false
};
wrapper = shallow(<DummyComponent { ...props } />);
});
it('should return true', () => {
nextProps = { ...props, editable: true };
expect(wrapper.instance().shouldUpdatedByNormalProps(nextProps)).toBeTruthy();
});
});
describe('when nextProps.columns.length is not eq props.columns.length', () => {
beforeEach(() => {
props = {
columns: [{ dataField: 'price', text: 'Price' }]
};
wrapper = shallow(<DummyComponent { ...props } />);
});
it('should return true', () => {
nextProps = { ...props, columns: [...props.columns, { dataField: 'name', text: 'Name' }] };
expect(wrapper.instance().shouldUpdatedByNormalProps(nextProps)).toBeTruthy();
});
});
describe('when nextProps.row is not eq props.row', () => {
beforeEach(() => {
props = {
row: { id: 1, name: 'test' }
};
wrapper = shallow(<DummyComponent { ...props } />);
});
it('should return true', () => {
nextProps = { ...props, row: { id: 1, name: 'test', price: 123 } };
expect(wrapper.instance().shouldUpdatedByNormalProps(nextProps)).toBeTruthy();
});
});
});
});

View File

@@ -1,216 +0,0 @@
import React from 'react';
import sinon from 'sinon';
import { shallow } from 'enzyme';
import RowPureContent from '../../src/row/row-pure-content';
import SimpleRow from '../../src/row/simple-row';
let defaultColumns = [{
dataField: 'id',
text: 'ID'
}, {
dataField: 'name',
text: 'Name'
}, {
dataField: 'price',
text: 'Price'
}];
const keyField = 'id';
const rowIndex = 1;
describe('SimpleRow', () => {
let wrapper;
const row = {
id: 1,
name: 'A',
price: 1000
};
beforeEach(() => {
defaultColumns = [{
dataField: 'id',
text: 'ID'
}, {
dataField: 'name',
text: 'Name'
}, {
dataField: 'price',
text: 'Price'
}];
});
describe('simplest row', () => {
beforeEach(() => {
wrapper = shallow(
<SimpleRow
keyField={ keyField }
rowIndex={ rowIndex }
columns={ defaultColumns }
row={ row }
/>
);
});
it('should render successfully', () => {
expect(wrapper.length).toBe(1);
expect(wrapper.find(RowPureContent)).toHaveLength(1);
});
describe('when tabIndexCell prop is enable', () => {
const visibleColumnSize = 3;
beforeEach(() => {
wrapper = shallow(
<SimpleRow
keyField={ keyField }
rowIndex={ rowIndex }
columns={ defaultColumns }
row={ row }
tabIndexCell
visibleColumnSize={ visibleColumnSize }
/>
);
});
it('should render correct tabIndexStart', () => {
expect(wrapper.length).toBe(1);
expect(wrapper.find(RowPureContent)).toHaveLength(1);
expect(wrapper.find(RowPureContent).prop('tabIndexStart')).toBe((rowIndex * visibleColumnSize) + 1);
});
});
describe('when tabIndexCell prop is disable', () => {
const visibleColumnSize = 3;
beforeEach(() => {
wrapper = shallow(
<SimpleRow
keyField={ keyField }
rowIndex={ rowIndex }
columns={ defaultColumns }
row={ row }
visibleColumnSize={ visibleColumnSize }
/>
);
});
it('should always render tabIndexStart as -1', () => {
expect(wrapper.length).toBe(1);
expect(wrapper.find(RowPureContent)).toHaveLength(1);
expect(wrapper.find(RowPureContent).prop('tabIndexStart')).toBe(-1);
});
});
});
describe('shouldComponentUpdate', () => {
let props;
let nextProps;
describe('if shouldUpdatedByNormalProps return true', () => {
beforeEach(() => {
props = {
keyField,
columns: defaultColumns,
rowIndex: 1,
row,
editable: true
};
wrapper = shallow(
<SimpleRow { ...props } />
);
});
it('should return true', () => {
nextProps = { ...props, rowIndex: 2 };
expect(wrapper.instance().shouldComponentUpdate(nextProps)).toBe(true);
});
it('should set this.shouldUpdateRowContent as true', () => {
nextProps = { ...props, rowIndex: 2 };
wrapper.instance().shouldComponentUpdate(nextProps);
expect(wrapper.instance().shouldUpdateRowContent).toBe(true);
});
});
describe('if shouldUpdatedByNormalProps return false', () => {
beforeEach(() => {
props = {
keyField,
columns: defaultColumns,
rowIndex: 1,
row,
editable: true
};
wrapper = shallow(
<SimpleRow { ...props } />
);
});
it('should return value which depends on the result of shouldUpdatedBySelfProps', () => {
nextProps = { ...props, className: 'test' };
expect(wrapper.instance().shouldComponentUpdate(nextProps)).toBe(true);
});
it('should always set this.shouldUpdateRowContent as false', () => {
nextProps = { ...props, className: 'test' };
wrapper.instance().shouldComponentUpdate(nextProps);
expect(wrapper.instance().shouldUpdateRowContent).toBe(false);
});
});
});
describe('when style prop is defined', () => {
const customStyle = { backgroundColor: 'red' };
beforeEach(() => {
wrapper = shallow(
<SimpleRow
rowIndex={ rowIndex }
columns={ defaultColumns }
row={ row }
style={ customStyle }
/>);
});
it('should render component with style successfully', () => {
expect(wrapper.length).toBe(1);
expect(wrapper.prop('style')).toEqual(customStyle);
});
});
describe('when className prop is defined', () => {
const className = 'test-class';
beforeEach(() => {
wrapper = shallow(
<SimpleRow
rowIndex={ rowIndex }
columns={ defaultColumns }
row={ row }
className={ className }
/>);
});
it('should render component with className successfully', () => {
expect(wrapper.length).toBe(1);
expect(wrapper.hasClass(className)).toBe(true);
});
});
describe('when attrs prop is defined', () => {
const customClickCallBack = sinon.stub();
const attrs = { 'data-index': 1, onClick: customClickCallBack };
beforeEach(() => {
wrapper = shallow(
<SimpleRow
rowIndex={ rowIndex }
columns={ defaultColumns }
row={ row }
attrs={ attrs }
/>);
});
it('should render component with correct attributes', () => {
expect(wrapper.length).toBe(1);
expect(wrapper.prop('data-index')).toBe(attrs['data-index']);
expect(wrapper.prop('onClick')).toBeDefined();
});
});
});

View File

@@ -6958,9 +6958,9 @@ rc@^1.1.7:
minimist "^1.2.0" minimist "^1.2.0"
strip-json-comments "~2.0.1" strip-json-comments "~2.0.1"
react-dom@16.4.0: react-dom@16.3.2:
version "16.4.0" version "16.3.2"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.4.0.tgz#099f067dd5827ce36a29eaf9a6cdc7cbf6216b1e" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.3.2.tgz#cb90f107e09536d683d84ed5d4888e9640e0e4df"
dependencies: dependencies:
fbjs "^0.8.16" fbjs "^0.8.16"
loose-envify "^1.1.0" loose-envify "^1.1.0"
@@ -6996,9 +6996,9 @@ react-test-renderer@~16.3.0-0:
prop-types "^15.6.0" prop-types "^15.6.0"
react-is "^16.3.2" react-is "^16.3.2"
react@16.4.0: react@16.3.2:
version "16.4.0" version "16.3.2"
resolved "https://registry.yarnpkg.com/react/-/react-16.4.0.tgz#402c2db83335336fba1962c08b98c6272617d585" resolved "https://registry.yarnpkg.com/react/-/react-16.3.2.tgz#fdc8420398533a1e58872f59091b272ce2f91ea9"
dependencies: dependencies:
fbjs "^0.8.16" fbjs "^0.8.16"
loose-envify "^1.1.0" loose-envify "^1.1.0"