Compare commits

...

44 Commits

Author SHA1 Message Date
AllenFang
532581bb6e Publish
- react-bootstrap-table2-example@1.0.6
 - react-bootstrap-table2-paginator@1.0.3
 - react-bootstrap-table2-toolkit@1.1.1
 - react-bootstrap-table-next@1.2.1
2018-10-07 23:33:25 +08:00
Allen
c228b229d2 Merge pull request #595 from react-bootstrap-table/develop
20181007 release
2018-10-07 23:31:56 +08:00
AllenFang
10adbf472c fix no-console 2018-10-07 16:24:15 +08:00
Allen
a6e2f0f8f8 fix #589 (#594) 2018-10-06 23:42:55 +08:00
Allen
f1d93853ec Merge pull request #593 from react-bootstrap-table/feat/587
Feat/587
2018-10-06 22:46:43 +08:00
AllenFang
bb7243c5db patch docs for column.sortCaret 2018-10-06 18:15:21 +08:00
AllenFang
3ea816b2e6 add story for #587 2018-10-06 18:15:21 +08:00
AllenFang
b268c4e0cd fix #587 2018-10-06 18:15:21 +08:00
Allen
8b8f336878 fix #585 (#592) 2018-10-06 17:29:24 +08:00
Allen
8517248aee fix #588 (#591) 2018-10-06 16:29:08 +08:00
AllenFang
ae0cd8a32f Publish
- react-bootstrap-table2-editor@1.1.0
 - react-bootstrap-table2-example@1.0.5
 - react-bootstrap-table2-toolkit@1.1.0
 - react-bootstrap-table-next@1.2.0
2018-09-30 14:26:34 +08:00
Allen
51c82cdfb3 Merge pull request #576 from react-bootstrap-table/develop
20180930 release
2018-09-30 14:24:30 +08:00
Allen
8e087329b3 Merge pull request #575 from react-bootstrap-table/bugfix/558
fix #558
2018-09-29 17:17:44 +08:00
AllenFang
ee2885d055 fix #558 2018-09-29 16:13:09 +08:00
Allen
901307e471 Merge pull request #574 from react-bootstrap-table/feat/564
Implement expandRow.onlyOneExpanding
2018-09-29 15:42:29 +08:00
AllenFang
4ff5be706a patch docs and add story for #564 2018-09-29 15:30:04 +08:00
AllenFang
f8a3fedbb2 fix #564 2018-09-29 15:29:42 +08:00
Allen
0bf5831b4e Merge pull request #573 from react-bootstrap-table/feat/567
Implement selectRow.hideSelectAll
2018-09-29 15:21:23 +08:00
AllenFang
dd0b8c6b0f add story and patch docs for #567 2018-09-29 15:13:23 +08:00
AllenFang
8f028d9dd4 fix #567, add selectRow.hideSelectAll 2018-09-29 15:12:27 +08:00
Allen
2c68f22646 fix #543 (#572) 2018-09-29 14:46:29 +08:00
Allen
02d566bb32 Merge pull request #571 from react-bootstrap-table/feat/541
Support default search
2018-09-29 14:37:36 +08:00
AllenFang
2b12045017 patch docs and add story for #541 2018-09-29 14:32:57 +08:00
AllenFang
0cdf086d56 fix #541 2018-09-29 14:31:10 +08:00
Allen
d4fa9a84e3 fix #538 (#570) 2018-09-29 14:00:33 +08:00
Allen
c84fc84b9e Merge pull request #569 from react-bootstrap-table/feat/527
Implement auto select input text when editing cell
2018-09-29 13:40:21 +08:00
AllenFang
ad8cdde513 patch docs and story for #527 2018-09-29 13:30:35 +08:00
AllenFang
db19e7dd9b fix #527 2018-09-29 13:30:35 +08:00
pnthang01
33b36e5108 add onContextMenu event (#556) 2018-09-29 12:54:23 +08:00
Darío Hereñú
7209441eb6 Typo on #16? (#552) 2018-09-21 00:05:46 +08:00
AllenFang
7a1ed67847 Publish
- react-bootstrap-table2-editor@1.0.1
 - react-bootstrap-table2-example@1.0.4
 - react-bootstrap-table2-toolkit@1.0.3
 - react-bootstrap-table-next@1.1.4
2018-09-03 23:29:46 +08:00
Allen
eaf9f4cd39 Merge pull request #525 from react-bootstrap-table/develop
release
2018-09-03 23:26:33 +08:00
Chun-MingChen
f0d85520c0 Fix typo of peer dependency 2018-09-01 21:11:31 +08:00
Allen
0e2862baa5 Merge pull request #523 from react-bootstrap-table/enhance/514
Enhance/514
2018-09-01 17:06:48 +08:00
AllenFang
5ac058c489 patch story for add cell.onStartEdit(#514) 2018-09-01 17:01:10 +08:00
AllenFang
ac38d2f28e fix #514 2018-09-01 17:00:34 +08:00
AllenFang
591abaae6e fix wonrg title 2018-09-01 16:39:26 +08:00
Allen
b76566126c Merge pull request #522 from react-bootstrap-table/feat/510
Feat/510
2018-09-01 16:37:03 +08:00
AllenFang
687583536a add stories for #510 2018-09-01 16:27:06 +08:00
AllenFang
d136ec3197 fix #510 2018-09-01 16:26:48 +08:00
Allen
37db43f5a7 Merge pull request #520 from react-bootstrap-table/feat/504
Feat/504
2018-09-01 15:05:07 +08:00
AllenFang
a966900752 patch docs for #504 2018-09-01 14:55:59 +08:00
AllenFang
3b1fc3a559 add dummy column story 2018-09-01 14:55:48 +08:00
AllenFang
849d9af8c4 fix #504 2018-09-01 14:52:29 +08:00
53 changed files with 1393 additions and 92 deletions

View File

@@ -13,7 +13,7 @@ Rebuilt [react-bootstrap-table](https://github.com/AllenFang/react-bootstrap-tab
* [`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)
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). This can help your application with less bundled size and also help us have clean design to avoid handling to much logic in kernel 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 the user from legacy [`react-bootstrap-table`](https://github.com/AllenFang/react-bootstrap-table/), please have a look on [this](./docs/migration.md).
@@ -40,4 +40,4 @@ $ yarn storybook
$ Go to localhost:6006 $ 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

@@ -10,6 +10,7 @@ $ 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)
@@ -43,6 +44,11 @@ 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.

View File

@@ -7,11 +7,13 @@ Available properties in a column object:
* [text (**required**)](#text) * [text (**required**)](#text)
#### Optional #### Optional
* [isDummyField](#isDummyField)
* [hidden](#hidden) * [hidden](#hidden)
* [formatter](#formatter) * [formatter](#formatter)
* [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)
@@ -84,6 +86,11 @@ dataField: 'address.city'
## <a name='text'>column.text (**required**) - [String]</a> ## <a name='text'>column.text (**required**) - [String]</a>
`text` will be the column text in header column by default, if your header is not only text or you want to customize the header column, please check [`column.headerFormatter`](#headerFormatter) `text` will be the column text in header column by default, if your header is not only text or you want to customize the header column, please check [`column.headerFormatter`](#headerFormatter)
## <a name='isDummyField'>column.isDummyField - [Bool]</a>
Sometime, you just want to have a column which is not perform any data but just some action components. In this situation, we suggest you to use `isDummyField`. If column is dummy, the [`column.dataField`](#dataField) can be any string value, cause of it's meaningless.
There's only one different for dummy column than normal column, which is dummy column will compare the whole row value instead of cell value when call `shouldComponentUpdate`.
## <a name='hidden'>column.hidden - [Bool]</a> ## <a name='hidden'>column.hidden - [Bool]</a>
`hidden` allow you to hide column when `true` given. `hidden` allow you to hide column when `true` given.
@@ -148,6 +155,20 @@ 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:

View File

@@ -13,6 +13,7 @@
* [onExpand](#onExpand) * [onExpand](#onExpand)
* [onExpandAll](#onExpandAll) * [onExpandAll](#onExpandAll)
* [showExpandColumn](#showExpandColumn) * [showExpandColumn](#showExpandColumn)
* [onlyOneExpanding](#onlyOneExpanding)
* [expandColumnRenderer](#expandColumnRenderer) * [expandColumnRenderer](#expandColumnRenderer)
* [expandHeaderColumnRenderer](#expandHeaderColumnRenderer) * [expandHeaderColumnRenderer](#expandHeaderColumnRenderer)
@@ -127,3 +128,13 @@ 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
};
```

View File

@@ -16,6 +16,7 @@
* [onSelect](#onSelect) * [onSelect](#onSelect)
* [onSelectAll](#onSelectAll) * [onSelectAll](#onSelectAll)
* [hideSelectColumn](#hideSelectColumn) * [hideSelectColumn](#hideSelectColumn)
* [hideSelectAll](#hideSelectAll)
* [selectionRenderer](#selectionRenderer) * [selectionRenderer](#selectionRenderer)
* [selectionHeaderRenderer](#selectionHeaderRenderer) * [selectionHeaderRenderer](#selectionHeaderRenderer)
@@ -222,3 +223,13 @@ 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

@@ -1,6 +1,6 @@
{ {
"name": "react-bootstrap-table2-editor", "name": "react-bootstrap-table2-editor",
"version": "1.0.0", "version": "1.1.0",
"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

@@ -13,7 +13,9 @@ class CheckBoxEditor extends Component {
} }
componentDidMount() { componentDidMount() {
const { didMount } = this.props;
this.checkbox.focus(); this.checkbox.focus();
if (didMount) didMount();
} }
getValue() { getValue() {
@@ -28,7 +30,7 @@ class CheckBoxEditor extends Component {
} }
render() { render() {
const { defaultValue, className, ...rest } = this.props; const { defaultValue, didMount, className, ...rest } = this.props;
const editorClass = cs('editor edit-chseckbox checkbox', className); const editorClass = cs('editor edit-chseckbox checkbox', className);
return ( return (
<input <input
@@ -50,12 +52,14 @@ CheckBoxEditor.propTypes = {
]), ]),
value: PropTypes.string, value: PropTypes.string,
defaultValue: PropTypes.any, defaultValue: PropTypes.any,
onChange: PropTypes.func onChange: PropTypes.func,
didMount: PropTypes.func
}; };
CheckBoxEditor.defaultProps = { CheckBoxEditor.defaultProps = {
className: '', className: '',
value: 'on:off', value: 'on:off',
defaultValue: false, defaultValue: false,
onChange: undefined onChange: undefined,
didMount: undefined
}; };
export default CheckBoxEditor; export default CheckBoxEditor;

View File

@@ -23,6 +23,7 @@ export default (
blurToSave: PropTypes.bool, blurToSave: PropTypes.bool,
beforeSaveCell: PropTypes.func, beforeSaveCell: PropTypes.func,
afterSaveCell: PropTypes.func, afterSaveCell: PropTypes.func,
onStartEdit: PropTypes.func,
nonEditableRows: PropTypes.func, nonEditableRows: PropTypes.func,
timeToCloseMessage: PropTypes.number, timeToCloseMessage: PropTypes.number,
errorMessage: PropTypes.any errorMessage: PropTypes.any
@@ -31,7 +32,7 @@ export default (
constructor(props) { constructor(props) {
super(props); super(props);
EditingCell = props.cellEdit.editingCellFactory(_); EditingCell = props.cellEdit.editingCellFactory(_, props.cellEdit.options.onStartEdit);
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);

View File

@@ -5,9 +5,10 @@ import PropTypes from 'prop-types';
class DateEditor extends Component { class DateEditor extends Component {
componentDidMount() { componentDidMount() {
const { defaultValue } = this.props; const { defaultValue, didMount } = this.props;
this.date.valueAsDate = new Date(defaultValue); this.date.valueAsDate = new Date(defaultValue);
this.date.focus(); this.date.focus();
if (didMount) didMount();
} }
getValue() { getValue() {
@@ -15,7 +16,7 @@ class DateEditor extends Component {
} }
render() { render() {
const { defaultValue, className, ...rest } = this.props; const { defaultValue, didMount, className, ...rest } = this.props;
const editorClass = cs('form-control editor edit-date', className); const editorClass = cs('form-control editor edit-date', className);
return ( return (
<input <input
@@ -33,10 +34,12 @@ DateEditor.propTypes = {
PropTypes.string, PropTypes.string,
PropTypes.object PropTypes.object
]), ]),
defaultValue: PropTypes.string defaultValue: PropTypes.string,
didMount: PropTypes.func
}; };
DateEditor.defaultProps = { DateEditor.defaultProps = {
className: '', className: '',
defaultValue: '' defaultValue: '',
didMount: undefined
}; };
export default DateEditor; export default DateEditor;

View File

@@ -5,9 +5,10 @@ import PropTypes from 'prop-types';
class DropDownEditor extends Component { class DropDownEditor extends Component {
componentDidMount() { componentDidMount() {
const { defaultValue } = this.props; const { defaultValue, didMount } = this.props;
this.select.value = defaultValue; this.select.value = defaultValue;
this.select.focus(); this.select.focus();
if (didMount) didMount();
} }
getValue() { getValue() {
@@ -15,7 +16,7 @@ class DropDownEditor extends Component {
} }
render() { render() {
const { defaultValue, className, options, ...rest } = this.props; const { defaultValue, didMount, className, options, ...rest } = this.props;
const editorClass = cs('form-control editor edit-select', className); const editorClass = cs('form-control editor edit-select', className);
const attr = { const attr = {
@@ -51,11 +52,13 @@ DropDownEditor.propTypes = {
label: PropTypes.string, label: PropTypes.string,
value: PropTypes.any value: PropTypes.any
})) }))
]).isRequired ]).isRequired,
didMount: PropTypes.func
}; };
DropDownEditor.defaultProps = { DropDownEditor.defaultProps = {
className: '', className: '',
defaultValue: '', defaultValue: '',
style: {} style: {},
didMount: undefined
}; };
export default DropDownEditor; export default DropDownEditor;

View File

@@ -14,7 +14,7 @@ import TextEditor from './text-editor';
import EditorIndicator from './editor-indicator'; import EditorIndicator from './editor-indicator';
import { TIME_TO_CLOSE_MESSAGE, EDITTYPE } from './const'; import { TIME_TO_CLOSE_MESSAGE, EDITTYPE } from './const';
export default _ => export default (_, onStartEdit) =>
class EditingCell extends Component { class EditingCell extends Component {
static propTypes = { static propTypes = {
row: PropTypes.object.isRequired, row: PropTypes.object.isRequired,
@@ -24,6 +24,7 @@ export default _ =>
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
} }
@@ -31,6 +32,7 @@ export default _ =>
static defaultProps = { static defaultProps = {
timeToCloseMessage: TIME_TO_CLOSE_MESSAGE, timeToCloseMessage: TIME_TO_CLOSE_MESSAGE,
className: null, className: null,
autoSelectText: false,
style: {} style: {}
} }
@@ -121,7 +123,7 @@ export default _ =>
render() { render() {
let editor; let editor;
const { row, column, className, style, rowIndex, columnIndex } = this.props; const { row, column, className, style, rowIndex, columnIndex, autoSelectText } = this.props;
const { dataField } = column; const { dataField } = column;
const value = _.get(row, dataField); const value = _.get(row, dataField);
@@ -151,6 +153,10 @@ export default _ =>
onBlur: this.handleBlur onBlur: this.handleBlur
}; };
if (onStartEdit) {
editorProps.didMount = () => onStartEdit(row, column, rowIndex, columnIndex);
}
const isDefaultEditorDefined = _.isObject(column.editor); const isDefaultEditorDefined = _.isObject(column.editor);
if (isDefaultEditorDefined) { if (isDefaultEditorDefined) {
@@ -170,13 +176,13 @@ export default _ =>
} 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 } />; editor = <TextAreaEditor { ...editorProps } autoSelectText={ autoSelectText } />;
} 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 } />; editor = <TextEditor { ...editorProps } autoSelectText={ autoSelectText } />;
} }
return ( return (

View File

@@ -5,9 +5,11 @@ import PropTypes from 'prop-types';
class TextEditor extends Component { class TextEditor extends Component {
componentDidMount() { componentDidMount() {
const { defaultValue } = this.props; const { defaultValue, didMount, autoSelectText } = this.props;
this.text.value = defaultValue; this.text.value = defaultValue;
this.text.focus(); this.text.focus();
if (autoSelectText) this.text.select();
if (didMount) didMount();
} }
getValue() { getValue() {
@@ -15,7 +17,7 @@ class TextEditor extends Component {
} }
render() { render() {
const { defaultValue, className, ...rest } = this.props; const { defaultValue, didMount, className, autoSelectText, ...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
@@ -36,10 +38,14 @@ TextEditor.propTypes = {
defaultValue: PropTypes.oneOfType([ defaultValue: PropTypes.oneOfType([
PropTypes.string, PropTypes.string,
PropTypes.number PropTypes.number
]) ]),
autoSelectText: PropTypes.bool,
didMount: PropTypes.func
}; };
TextEditor.defaultProps = { TextEditor.defaultProps = {
className: null, className: null,
defaultValue: '' defaultValue: '',
autoSelectText: false,
didMount: undefined
}; };
export default TextEditor; export default TextEditor;

View File

@@ -10,9 +10,11 @@ class TextAreaEditor extends Component {
} }
componentDidMount() { componentDidMount() {
const { defaultValue } = this.props; const { defaultValue, didMount, autoSelectText } = this.props;
this.text.value = defaultValue; this.text.value = defaultValue;
this.text.focus(); this.text.focus();
if (autoSelectText) this.text.select();
if (didMount) didMount();
} }
getValue() { getValue() {
@@ -27,7 +29,7 @@ class TextAreaEditor extends Component {
} }
render() { render() {
const { defaultValue, className, ...rest } = this.props; const { defaultValue, didMount, className, autoSelectText, ...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
@@ -50,11 +52,15 @@ TextAreaEditor.propTypes = {
PropTypes.string, PropTypes.string,
PropTypes.number PropTypes.number
]), ]),
onKeyDown: PropTypes.func onKeyDown: PropTypes.func,
autoSelectText: PropTypes.bool,
didMount: PropTypes.func
}; };
TextAreaEditor.defaultProps = { TextAreaEditor.defaultProps = {
className: '', className: '',
defaultValue: '', defaultValue: '',
onKeyDown: undefined autoSelectText: false,
onKeyDown: undefined,
didMount: undefined
}; };
export default TextAreaEditor; export default TextAreaEditor;

View File

@@ -0,0 +1,182 @@
/* 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

@@ -0,0 +1,78 @@
/* 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

@@ -41,6 +41,7 @@ const columns = [{
columns={ columns } columns={ columns }
cellEdit={ cellEditFactory({ cellEdit={ cellEditFactory({
mode: 'click', mode: 'click',
onStartEdit: (row, column, rowIndex, columnIndex) => { console.log('start to edit!!!'); },
beforeSaveCell: (oldValue, newValue, row, column) => { console.log('Before Saving Cell!!'); }, beforeSaveCell: (oldValue, newValue, row, column) => { console.log('Before Saving Cell!!'); },
afterSaveCell: (oldValue, newValue, row, column) => { console.log('After Saving Cell!!'); } afterSaveCell: (oldValue, newValue, row, column) => { console.log('After Saving Cell!!'); }
}) } }) }
@@ -55,6 +56,7 @@ export default () => (
columns={ columns } columns={ columns }
cellEdit={ cellEditFactory({ cellEdit={ cellEditFactory({
mode: 'click', mode: 'click',
onStartEdit: (row, column, rowIndex, columnIndex) => { console.log('Start to edit!!!'); },
beforeSaveCell: (oldValue, newValue, row, column) => { console.log('Before Saving Cell!!'); }, beforeSaveCell: (oldValue, newValue, row, column) => { console.log('Before Saving Cell!!'); },
afterSaveCell: (oldValue, newValue, row, column) => { console.log('After Saving Cell!!'); } afterSaveCell: (oldValue, newValue, row, column) => { console.log('After Saving Cell!!'); }
}) } }) }

View File

@@ -52,7 +52,7 @@ const columns = [{
export default () => ( export default () => (
<div> <div>
<h3>Dropdown Editor</h3> <h3>Checkbox Editor</h3>
<BootstrapTable <BootstrapTable
keyField="id" keyField="id"
data={ todos } data={ todos }

View File

@@ -118,7 +118,7 @@ const columns = [{
export default () => ( export default () => (
<div> <div>
<h3>Dropdown Editor</h3> <h3>Custom Editor</h3>
<BootstrapTable <BootstrapTable
keyField="id" keyField="id"
data={ products } data={ products }

View File

@@ -65,7 +65,7 @@ const columns = [{
export default () => ( export default () => (
<div> <div>
<h3>Dropdown Editor</h3> <h3>Date Editor</h3>
<BootstrapTable <BootstrapTable
keyField="id" keyField="id"
data={ stocks } data={ stocks }

View File

@@ -56,7 +56,7 @@ const columns = [{
export default () => ( export default () => (
<div> <div>
<h3>Dropdown Editor</h3> <h3>Textarea Editor</h3>
<BootstrapTable <BootstrapTable
keyField="id" keyField="id"
data={ jobs } data={ jobs }

View File

@@ -0,0 +1,221 @@
/* eslint jsx-a11y/label-has-for: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block';
const products = [
{ id: 12, name: 'Item 12', price: 12.5, inStock: false },
{ id: 13, name: 'Item 13', price: 13.5, inStock: true },
{ id: 14, name: 'Item 14', price: 14.5, inStock: true }
];
const columns = [
{
dataField: 'id',
text: 'Product ID'
},
{
dataField: 'name',
text: 'Product Name'
},
{
dataField: 'price',
text: 'Product Price'
},
{
dataField: 'inStock',
text: 'In Stock',
formatter: (cellContent, row) => (
<div className="checkbox disabled">
<label>
<input type="checkbox" checked={ row.inStock } disabled />
</label>
</div>
)
},
{
dataField: 'df1',
isDummyField: true,
text: 'Action 1',
formatter: (cellContent, row) => {
if (row.inStock) {
return (
<h5>
<span className="label label-success"> Available</span>
</h5>
);
}
return (
<h5>
<span className="label label-danger"> Backordered</span>
</h5>
);
}
},
{
dataField: 'df2',
isDummyField: true,
text: 'Action 2',
formatter: (cellContent, row) => {
if (row.inStock) {
return (
<h5>
<span className="label label-success"> Available</span>
</h5>
);
}
return (
<h5>
<span className="label label-danger"> Backordered</span>
</h5>
);
}
}
];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [
{
dataField: 'id',
text: 'Product ID'
},
{
dataField: 'name',
text: 'Product Name'
},
{
dataField: 'price',
text: 'Product Price'
},
{
dataField: 'inStock',
text: 'In Stock',
formatter: (cellContent, row) => (
<div className="checkbox disabled">
<label>
<input type="checkbox" checked={ row.inStock } disabled />
</label>
</div>
)
},
{
dataField: 'df1',
isDummyField: true,
text: 'Action 1',
formatter: (cellContent, row) => {
if (row.inStock) {
return (
<h5>
<span className="label label-success"> Available</span>
</h5>
);
}
return (
<h5>
<span className="label label-danger"> Backordered</span>
</h5>
);
}
},
{
dataField: 'df2',
isDummyField: true,
text: 'Action 2',
formatter: (cellContent, row) => {
if (row.inStock) {
return (
<h5>
<span className="label label-success"> Available</span>
</h5>
);
}
return (
<h5>
<span className="label label-danger"> Backordered</span>
</h5>
);
}
}
];
class ProductList extends React.Component {
constructor(props) {
super(props);
this.state = { products };
}
toggleInStock = () => {
let newProducts = [...this.state.products];
newProducts = newProducts.map((d) => {
if (d.id === 13) {
return {
...d,
inStock: !d.inStock
};
}
return d;
});
this.setState(curr => ({ ...curr, products: newProducts }));
};
render() {
return (
<div>
<h1 className="h2">Products</h1>
<BootstrapTable
keyField="id"
data={ this.state.products }
columns={ columns }
/>
<button onClick={ this.toggleInStock } className="btn btn-primary">
Toggle item 13 stock status
</button>
</div>
);
}
}
`;
class ProductList extends React.Component {
constructor(props) {
super(props);
this.state = { products };
}
toggleInStock = () => {
let newProducts = [...this.state.products];
newProducts = newProducts.map((d) => {
if (d.id === 13) {
return {
...d,
inStock: !d.inStock
};
}
return d;
});
this.setState(curr => ({ ...curr, products: newProducts }));
};
render() {
return (
<div>
<h3>Action 1 and Action 2 are dummy column</h3>
<button onClick={ this.toggleInStock } className="btn btn-primary">
Toggle item 13 stock status
</button>
<BootstrapTable
keyField="id"
data={ this.state.products }
columns={ columns }
/>
<Code>{ sourceCode }</Code>
</div>
);
}
}
export default ProductList;

View File

@@ -0,0 +1,98 @@
/* eslint react/prop-types: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import ToolkitProvider from 'react-bootstrap-table2-toolkit';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const 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 from 'react-bootstrap-table2-toolkit';
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const MyExportCSV = (props) => {
const handleClick = () => {
props.onExport();
};
return (
<div>
<button className="btn btn-success" onClick={ handleClick }>Export to CSV</button>
</div>
);
};
<ToolkitProvider
keyField="id"
data={ products }
columns={ columns }
exportCSV
>
{
props => (
<div>
<BootstrapTable { ...props.baseProps } />
<hr />
<MyExportCSV { ...props.csvProps } />
</div>
)
}
</ToolkitProvider>
`;
const MyExportCSV = (props) => {
const handleClick = () => {
// passing my custom data
props.onExport(products.filter(r => r.id > 2));
};
return (
<div>
<button className="btn btn-success" onClick={ handleClick }>Only export Product ID bigger than 2</button>
</div>
);
};
export default () => (
<div>
<ToolkitProvider
keyField="id"
data={ products }
columns={ columns }
exportCSV
>
{
props => (
<div>
<BootstrapTable { ...props.baseProps } />
<hr />
<MyExportCSV { ...props.csvProps } />
</div>
)
}
</ToolkitProvider>
<Code>{ sourceCode }</Code>
</div>
);

View File

@@ -0,0 +1,140 @@
/* eslint react/prop-types: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import ToolkitProvider, { CSVExport } from 'react-bootstrap-table2-toolkit';
import paginationFactory from 'react-bootstrap-table2-paginator';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const { ExportCSVButton } = CSVExport;
const products1 = productsGenerator(15);
const products2 = productsGenerator(15);
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, { CSVExport } from 'react-bootstrap-table2-toolkit';
const { ExportCSVButton } = CSVExport;
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const selectRow = {
mode: 'checkbox',
clickToSelect: true
};
<ToolkitProvider
keyField="id"
data={ products1 }
columns={ columns }
exportCSV={ { onlyExportSelection: true, exportAll: true } }
>
{
props => (
<div>
<ExportCSVButton { ...props.csvProps }>Export CSV!!</ExportCSVButton>
<hr />
<BootstrapTable
{ ...props.baseProps }
selectRow={ selectRow }
pagination={ paginationFactory() }
/>
</div>
)
}
</ToolkitProvider>
<ToolkitProvider
keyField="id"
data={ products2 }
columns={ columns }
exportCSV={ { onlyExportSelection: true, exportAll: false } }
>
{
props => (
<div>
<ExportCSVButton { ...props.csvProps }>Export CSV!!</ExportCSVButton>
<hr />
<BootstrapTable
{ ...props.baseProps }
selectRow={ selectRow }
pagination={ paginationFactory() }
/>
</div>
)
}
</ToolkitProvider>
`;
const selectRow = {
mode: 'checkbox',
clickToSelect: true
};
export default () => (
<div>
<h3>Export all selected row</h3>
<ToolkitProvider
keyField="id"
data={ products1 }
columns={ columns }
exportCSV={ { onlyExportSelection: true, exportAll: true } }
>
{
props => (
<div>
<ExportCSVButton { ...props.csvProps }>Export CSV!!</ExportCSVButton>
<hr />
<BootstrapTable
{ ...props.baseProps }
selectRow={ selectRow }
pagination={ paginationFactory() }
/>
</div>
)
}
</ToolkitProvider>
<h3>Export all selected rows in currect visible rows</h3>
<ToolkitProvider
keyField="id"
data={ products2 }
columns={ columns }
exportCSV={ { onlyExportSelection: true, exportAll: false } }
>
{
props => (
<div>
<ExportCSVButton { ...props.csvProps }>Export CSV!!</ExportCSVButton>
<hr />
<BootstrapTable
{ ...props.baseProps }
selectRow={ selectRow }
pagination={ paginationFactory() }
/>
</div>
)
}
</ToolkitProvider>
<Code>{ sourceCode }</Code>
</div>
);

View File

@@ -0,0 +1,73 @@
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

@@ -0,0 +1,59 @@
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const selectRow = {
mode: 'checkbox',
clickToSelect: true,
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

@@ -0,0 +1,83 @@
/* 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

@@ -0,0 +1,59 @@
/* 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,6 +1,6 @@
{ {
"name": "react-bootstrap-table2-example", "name": "react-bootstrap-table2-example",
"version": "1.0.3", "version": "1.0.6",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"private": true, "private": true,
@@ -15,7 +15,7 @@
"peerDependencies": { "peerDependencies": {
"prop-types": "^15.0.0", "prop-types": "^15.0.0",
"react": "^16.3.0", "react": "^16.3.0",
"react-dom": "^116.3.0" "react-dom": "^16.3.0"
}, },
"devDependencies": { "devDependencies": {
"@storybook/addon-console": "^1.0.0", "@storybook/addon-console": "^1.0.0",

View File

@@ -13,6 +13,7 @@ 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';
// bootstrap 4 // bootstrap 4
import Bootstrap4DefaultSortTable from 'examples/bootstrap4/sort'; import Bootstrap4DefaultSortTable from 'examples/bootstrap4/sort';
@@ -30,6 +31,7 @@ import ColumnTitleTable from 'examples/columns/column-title-table';
import ColumnEventTable from 'examples/columns/column-event-table'; import ColumnEventTable from 'examples/columns/column-event-table';
import ColumnHiddenTable from 'examples/columns/column-hidden-table'; import ColumnHiddenTable from 'examples/columns/column-hidden-table';
import ColumnAttrsTable from 'examples/columns/column-attrs-table'; import ColumnAttrsTable from 'examples/columns/column-attrs-table';
import DummyColumnTable from 'examples/columns/dummy-column-table';
// work on header columns // work on header columns
import HeaderColumnFormatTable from 'examples/header-columns/column-format-table'; import HeaderColumnFormatTable from 'examples/header-columns/column-format-table';
@@ -82,6 +84,7 @@ 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';
@@ -96,6 +99,7 @@ import CellEditHooks from 'examples/cell-edit/cell-edit-hooks-table';
import CellEditValidator from 'examples/cell-edit/cell-edit-validator-table'; import CellEditValidator from 'examples/cell-edit/cell-edit-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 DropdownEditorTable from 'examples/cell-edit/dropdown-editor-table'; import DropdownEditorTable from 'examples/cell-edit/dropdown-editor-table';
@@ -114,6 +118,7 @@ import ClickToSelectWithCellEditTable from 'examples/row-selection/click-to-sele
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';
@@ -125,6 +130,7 @@ 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 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';
@@ -135,6 +141,7 @@ 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';
@@ -145,8 +152,10 @@ import ExportCSV from 'examples/csv';
import CSVFormatter from 'examples/csv/csv-column-formatter'; import CSVFormatter from 'examples/csv/csv-column-formatter';
import CustomCSVHeader from 'examples/csv/custom-csv-header'; import CustomCSVHeader from 'examples/csv/custom-csv-header';
import HideCSVColumn from 'examples/csv/hide-column'; import HideCSVColumn from 'examples/csv/hide-column';
import ExportOnlySelected from 'examples/csv/export-only-selected';
import CSVColumnType from 'examples/csv/csv-column-type'; import CSVColumnType from 'examples/csv/csv-column-type';
import CustomCSVButton from 'examples/csv/custom-csv-button'; import CustomCSVButton from 'examples/csv/custom-csv-button';
import ExportCustomData from 'examples/csv/export-custom-data';
import CustomCSV from 'examples/csv/custom-csv'; import CustomCSV from 'examples/csv/custom-csv';
// loading overlay // loading overlay
@@ -182,7 +191,8 @@ 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 />);
storiesOf('Bootstrap 4', module) storiesOf('Bootstrap 4', module)
.addDecorator(bootstrapStyle(BOOTSTRAP_VERSION.FOUR)) .addDecorator(bootstrapStyle(BOOTSTRAP_VERSION.FOUR))
@@ -201,7 +211,8 @@ storiesOf('Work on Columns', module)
.add('Column Event', () => <ColumnEventTable />) .add('Column Event', () => <ColumnEventTable />)
.add('Customize Column Class', () => <ColumnClassTable />) .add('Customize Column Class', () => <ColumnClassTable />)
.add('Customize Column Style', () => <ColumnStyleTable />) .add('Customize Column Style', () => <ColumnStyleTable />)
.add('Customize Column HTML attribute', () => <ColumnAttrsTable />); .add('Customize Column HTML attribute', () => <ColumnAttrsTable />)
.add('Dummy Column', () => <DummyColumnTable />);
storiesOf('Work on Header Columns', module) storiesOf('Work on Header Columns', module)
.addDecorator(bootstrapStyle()) .addDecorator(bootstrapStyle())
@@ -259,6 +270,7 @@ 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 />);
@@ -272,6 +284,7 @@ storiesOf('Cell Editing', module)
.add('Cell Level Editable', () => <CellLevelEditable />) .add('Cell Level Editable', () => <CellLevelEditable />)
.add('Rich Hook Functions', () => <CellEditHooks />) .add('Rich Hook Functions', () => <CellEditHooks />)
.add('Validation', () => <CellEditValidator />) .add('Validation', () => <CellEditValidator />)
.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 />)
@@ -293,6 +306,7 @@ storiesOf('Row Selection', module)
.add('Selection without Data', () => <SelectionNoDataTable />) .add('Selection without Data', () => <SelectionNoDataTable />)
.add('Selection Style', () => <SelectionStyleTable />) .add('Selection Style', () => <SelectionStyleTable />)
.add('Selection Class', () => <SelectionClassTable />) .add('Selection Class', () => <SelectionClassTable />)
.add('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 />)
@@ -305,6 +319,7 @@ 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('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 />);
@@ -317,6 +332,7 @@ 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 />)
@@ -328,8 +344,10 @@ storiesOf('Export CSV', module)
.add('Format CSV Column', () => <CSVFormatter />) .add('Format CSV Column', () => <CSVFormatter />)
.add('Custom CSV Header', () => <CustomCSVHeader />) .add('Custom CSV Header', () => <CustomCSVHeader />)
.add('Hide CSV Column', () => <HideCSVColumn />) .add('Hide CSV Column', () => <HideCSVColumn />)
.add('Only Export Selected Rows', () => <ExportOnlySelected />)
.add('CSV Column Type', () => <CSVColumnType />) .add('CSV Column Type', () => <CSVColumnType />)
.add('Custom CSV Button', () => <CustomCSVButton />) .add('Custom CSV Button', () => <CustomCSVButton />)
.add('Export Custom Data', () => <ExportCustomData />)
.add('Custom CSV', () => <CustomCSV />); .add('Custom CSV', () => <CustomCSV />);
storiesOf('EmptyTableOverlay', module) storiesOf('EmptyTableOverlay', module)

View File

@@ -1,6 +1,6 @@
{ {
"name": "react-bootstrap-table2-paginator", "name": "react-bootstrap-table2-paginator",
"version": "1.0.2", "version": "1.0.3",
"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,6 +68,9 @@ 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

@@ -160,6 +160,27 @@ 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,6 +63,22 @@ 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.
@@ -123,4 +139,7 @@ Default is `false`. Give true to avoid to attach the csv header.
Default is `true`. Default is `true`.
#### exportAll - [bool] #### exportAll - [bool]
Default is `true`. `false` will only export current data which display on table. Default is `true`. `false` will only export current data which display on table.
#### onlyExportSelection - [bool]
Default is `false`. `true` will only export the data which is selected.

View File

@@ -17,6 +17,7 @@ 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
}) })
]), ]),
@@ -26,7 +27,9 @@ class ToolkitProvider extends statelessDrcorator(React.Component) {
fileName: PropTypes.string, fileName: PropTypes.string,
separator: PropTypes.string, separator: PropTypes.string,
ignoreHeader: PropTypes.bool, ignoreHeader: PropTypes.bool,
noAutoBOM: PropTypes.bool noAutoBOM: PropTypes.bool,
exportAll: PropTypes.bool,
onlyExportSelection: PropTypes.bool
}) })
]) ])
} }
@@ -40,7 +43,7 @@ class ToolkitProvider extends statelessDrcorator(React.Component) {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
searchText: '' searchText: typeof props.search === 'object' ? (props.search.defaultSearch || '') : ''
}; };
this._ = null; this._ = null;
this.onSearch = this.onSearch.bind(this); this.onSearch = this.onSearch.bind(this);
@@ -83,6 +86,7 @@ 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.0.2", "version": "1.1.1",
"description": "The toolkit for react-bootstrap-table2", "description": "The toolkit for react-bootstrap-table2",
"main": "./lib/index.js", "main": "./lib/index.js",
"repository": { "repository": {

View File

@@ -11,7 +11,7 @@ const ExportCSVButton = (props) => {
return ( return (
<button <button
type="button" type="button"
onClick={ onExport } onClick={ () => onExport() }
{ ...rest } { ...rest }
> >
{ children } { children }

View File

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

View File

@@ -5,13 +5,14 @@ const csvDefaultOptions = {
separator: ',', separator: ',',
ignoreHeader: false, ignoreHeader: false,
noAutoBOM: true, noAutoBOM: true,
exportAll: true exportAll: true,
onlyExportSelection: false
}; };
export default Base => export default Base =>
class CSVOperation extends Base { class CSVOperation extends Base {
handleExportCSV = () => { handleExportCSV = (source) => {
const { columns, exportCSV } = this.props; const { columns, exportCSV, keyField } = this.props;
const meta = getMetaInfo(columns); const meta = getMetaInfo(columns);
const options = exportCSV === true ? const options = exportCSV === true ?
csvDefaultOptions : csvDefaultOptions :
@@ -20,7 +21,19 @@ export default Base =>
...exportCSV ...exportCSV
}; };
const data = options.exportAll ? this.props.data : this.getData(); // get data for csv export
let data;
if (typeof source !== 'undefined') {
data = source;
} else {
data = options.exportAll ? this.props.data : this.getData();
}
// filter data
if (options.onlyExportSelection) {
const selections = this.getSelected();
data = data.filter(row => !!selections.find(sel => row[keyField] === sel));
}
const content = transform(data, meta, this._.get, options); const content = transform(data, meta, this._.get, options);
save(content, options); save(content, options);
} }

View File

@@ -47,6 +47,7 @@ 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,8 +39,10 @@ export default (options = {
const { data, columns } = this.props; const { data, columns } = this.props;
let { searchText } = this.props; let { searchText } = this.props;
if (isRemoteSearch() && this.performRemoteSearch) { if (isRemoteSearch()) {
handleRemoteSearchChange(searchText); if (this.performRemoteSearch) {
handleRemoteSearchChange(searchText);
}
return data; return data;
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "react-bootstrap-table-next", "name": "react-bootstrap-table-next",
"version": "1.1.3", "version": "1.2.1",
"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

@@ -146,6 +146,7 @@ BootstrapTable.propTypes = {
mode: PropTypes.oneOf([Const.ROW_SELECT_SINGLE, Const.ROW_SELECT_MULTIPLE]).isRequired, mode: PropTypes.oneOf([Const.ROW_SELECT_SINGLE, Const.ROW_SELECT_MULTIPLE]).isRequired,
clickToSelect: PropTypes.bool, clickToSelect: 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]),
@@ -165,6 +166,7 @@ BootstrapTable.propTypes = {
onExpandAll: PropTypes.func, onExpandAll: PropTypes.func,
nonExpandable: PropTypes.array, nonExpandable: PropTypes.array,
showExpandColumn: PropTypes.bool, showExpandColumn: PropTypes.bool,
onlyOneExpanding: PropTypes.bool,
expandColumnRenderer: PropTypes.func, expandColumnRenderer: PropTypes.func,
expandHeaderColumnRenderer: PropTypes.func expandHeaderColumnRenderer: PropTypes.func
}), }),

View File

@@ -11,9 +11,18 @@ class Cell extends Component {
} }
shouldComponentUpdate(nextProps) { shouldComponentUpdate(nextProps) {
const shouldUpdate = let shouldUpdate = false;
_.get(this.props.row, this.props.column.dataField) if (nextProps.column.isDummyField) {
!== _.get(nextProps.row, nextProps.column.dataField) || shouldUpdate = !_.isEqual(this.props.row, nextProps.row);
} else {
shouldUpdate =
_.get(this.props.row, this.props.column.dataField)
!== _.get(nextProps.row, nextProps.column.dataField);
}
if (shouldUpdate) return true;
shouldUpdate =
this.props.column.hidden !== nextProps.column.hidden || this.props.column.hidden !== nextProps.column.hidden ||
this.props.rowIndex !== nextProps.rowIndex || this.props.rowIndex !== nextProps.rowIndex ||
this.props.columnIndex !== nextProps.columnIndex || this.props.columnIndex !== nextProps.columnIndex ||
@@ -64,7 +73,7 @@ class Cell extends Component {
formatExtraData formatExtraData
} = column; } = column;
const attrs = { ...rest }; const attrs = { ...rest };
let content = _.get(row, dataField); let 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

@@ -66,6 +66,7 @@ const withContext = Base =>
selectionProps selectionProps
) => ( ) => (
<Base <Base
ref={ n => this.table = n }
{ ...this.props } { ...this.props }
{ ...selectionProps } { ...selectionProps }
{ ...sortProps } { ...sortProps }
@@ -91,6 +92,7 @@ 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) }
> >
@@ -123,6 +125,7 @@ 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) }
> >
@@ -269,8 +272,9 @@ const withContext = Base =>
} }
render() { render() {
const { keyField, columns, bootstrap4 } = this.props; const { keyField, columns, bootstrap4, registerExposedAPI } = this.props;
const baseProps = { keyField, columns }; const baseProps = { keyField, columns };
if (registerExposedAPI) baseProps.registerExposedAPI = registerExposedAPI;
let base = this.renderBase(); let base = this.renderBase();

View File

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

View File

@@ -15,6 +15,14 @@ export default (
keyField: PropTypes.string.isRequired keyField: PropTypes.string.isRequired
} }
constructor(props) {
super(props);
if (props.registerExposedAPI) {
const getSelected = () => this.getSelected();
props.registerExposedAPI(getSelected);
}
}
state = { selected: (this.props.selectRow && this.props.selectRow.selected) || [] }; state = { selected: (this.props.selectRow && this.props.selectRow.selected) || [] };
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
@@ -25,6 +33,11 @@ export default (
} }
} }
// exposed API
getSelected() {
return this.state.selected;
}
handleRowSelect = (rowKey, checked, rowIndex, e) => { handleRowSelect = (rowKey, checked, rowIndex, e) => {
const { data, keyField, selectRow: { mode, onSelect } } = this.props; const { data, keyField, selectRow: { mode, onSelect } } = this.props;
const { ROW_SELECT_SINGLE } = Const; const { ROW_SELECT_SINGLE } = Const;
@@ -67,7 +80,15 @@ export default (
} }
if (onSelectAll) { if (onSelectAll) {
onSelectAll(!isUnSelect, dataOperator.getSelectedRows(data, keyField, currSelected), e); onSelectAll(
!isUnSelect,
dataOperator.getSelectedRows(
data,
keyField,
isUnSelect ? this.state.selected : currSelected
),
e
);
} }
this.setState(() => ({ selected: currSelected })); this.setState(() => ({ selected: currSelected }));

View File

@@ -24,6 +24,7 @@ const HeaderCell = (props) => {
const { const {
text, text,
sort, sort,
sortCaret,
filter, filter,
filterRenderer, filterRenderer,
headerTitle, headerTitle,
@@ -49,6 +50,7 @@ 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) {
@@ -68,7 +70,7 @@ const HeaderCell = (props) => {
cellAttrs.className = cs(cellAttrs.className, 'sortable'); cellAttrs.className = cs(cellAttrs.className, 'sortable');
if (sorting) { if (sorting) {
sortSymbol = <SortCaret order={ sortOrder } />; sortSymbol = sortCaret ? sortCaret(sortOrder, column) : <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(
@@ -85,7 +87,7 @@ const HeaderCell = (props) => {
: headerSortingStyle : headerSortingStyle
}; };
} else { } else {
sortSymbol = <SortSymbol />; sortSymbol = sortCaret ? sortCaret(undefined, column) : <SortSymbol />;
} }
} }
@@ -114,6 +116,7 @@ HeaderCell.propTypes = {
column: PropTypes.shape({ column: PropTypes.shape({
dataField: PropTypes.string.isRequired, dataField: PropTypes.string.isRequired,
text: PropTypes.string.isRequired, text: PropTypes.string.isRequired,
isDummyField: PropTypes.bool,
hidden: PropTypes.bool, hidden: PropTypes.bool,
headerFormatter: PropTypes.func, headerFormatter: PropTypes.func,
formatter: PropTypes.func, formatter: PropTypes.func,
@@ -149,6 +152,7 @@ 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,7 +5,8 @@ const events = [
'onClick', 'onClick',
'onDoubleClick', 'onDoubleClick',
'onMouseEnter', 'onMouseEnter',
'onMouseLeave' 'onMouseLeave',
'onContextMenu'
]; ];
export default ExtendBase => export default ExtendBase =>

View File

@@ -27,6 +27,7 @@ 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
} }
@@ -63,7 +64,10 @@ 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 } = this.props; const { mode, checkedStatus, selectionHeaderRenderer, hideSelectAll } = this.props;
if (hideSelectAll) {
return <th data-row-selection />;
}
const checked = checkedStatus === CHECKBOX_STATUS_CHECKED; const checked = checkedStatus === CHECKBOX_STATUS_CHECKED;

View File

@@ -177,22 +177,45 @@ describe('Cell', () => {
let props; let props;
let nextProps; let nextProps;
describe('when content is change', () => { describe('if column.isDummyField is false', () => {
const column = { dataField: 'name', text: 'Product Name' }; describe('when content is change', () => {
beforeEach(() => { const column = { dataField: 'name', text: 'Product Name' };
props = { beforeEach(() => {
row, props = {
columnIndex: 1, row,
rowIndex: 1, columnIndex: 1,
column rowIndex: 1,
}; column
wrapper = shallow( };
<Cell { ...props } />); wrapper = shallow(
}); <Cell { ...props } />);
});
it('should return true', () => { it('should return true', () => {
nextProps = { ...props, row: { id: 1, name: 'CDE' } }; nextProps = { ...props, row: { id: 1, name: 'CDE' } };
expect(wrapper.instance().shouldComponentUpdate(nextProps)).toBe(true); expect(wrapper.instance().shouldComponentUpdate(nextProps)).toBe(true);
});
});
});
describe('if column.isDummyField is true', () => {
describe('when content is change', () => {
const column = { dataField: '', text: 'Product Name', isDummyField: true };
beforeEach(() => {
props = {
row,
columnIndex: 1,
rowIndex: 1,
column
};
wrapper = shallow(
<Cell { ...props } />);
});
it('should return true', () => {
nextProps = { ...props, row: { id: 1, name: 'CDE', test: 'This is new Field' } };
expect(wrapper.instance().shouldComponentUpdate(nextProps)).toBe(true);
});
}); });
}); });

View File

@@ -220,6 +220,25 @@ 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', () => {
@@ -234,24 +253,25 @@ 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,
onSelectAll selected: data.map(d => d[keyField]),
})); 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(
true, false,
dataOperator.getSelectedRows(data, keyField, wrapper.state('selected')), dataOperator.getSelectedRows(data, keyField, data.map(d => d[keyField])),
e e
); );
});
}); });
}); });
}); });

View File

@@ -403,6 +403,24 @@ 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', () => {
@@ -420,6 +438,30 @@ 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

@@ -104,6 +104,22 @@ 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;