Compare commits

..

20 Commits

Author SHA1 Message Date
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
68 changed files with 2424 additions and 2607 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

@@ -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,4 +1,4 @@
import Adapter from 'enzyme-adapter-react-16.3'; import Adapter from 'enzyme-adapter-react-16';
import { configure } from 'enzyme'; import { configure } from 'enzyme';
const configureEnzyme = () => { const configureEnzyme = () => {

View File

@@ -50,8 +50,8 @@
"babel-preset-stage-0": "6.24.1", "babel-preset-stage-0": "6.24.1",
"babel-register": "6.24.1", "babel-register": "6.24.1",
"css-loader": "0.28.1", "css-loader": "0.28.1",
"enzyme": "3.4.0", "enzyme": "3.3.0",
"enzyme-adapter-react-16.3": "1.0.0", "enzyme-adapter-react-16": "1.1.1",
"enzyme-to-json": "3.3.4", "enzyme-to-json": "3.3.4",
"eslint": "4.5.0", "eslint": "4.5.0",
"eslint-config-airbnb": "15.1.0", "eslint-config-airbnb": "15.1.0",

View File

@@ -1,16 +1,16 @@
import createContext from './src/context'; import createContext from './src/context';
import bindRowLevelCellEdit from './src/row-binder'; import editingCellFactory from './src/editing-cell';
import createEditingCell from './src/editing-cell-binder';
import { import {
EDITTYPE, EDITTYPE,
CLICK_TO_CELL_EDIT,
DBCLICK_TO_CELL_EDIT, DBCLICK_TO_CELL_EDIT,
DELAY_FOR_DBCLICK DELAY_FOR_DBCLICK
} from './src/const'; } from './src/const';
export default (options = {}) => ({ export default (options = {}) => ({
createContext, createContext,
createEditingCell, editingCellFactory,
bindRowLevelCellEdit, CLICK_TO_CELL_EDIT,
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.0.1", "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

@@ -4,14 +4,15 @@ import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { CLICK_TO_CELL_EDIT, DBCLICK_TO_CELL_EDIT } from './const'; import { CLICK_TO_CELL_EDIT, DBCLICK_TO_CELL_EDIT } from './const';
const CellEditContext = React.createContext();
export default ( export default (
_, _,
dataOperator, dataOperator,
isRemoteCellEdit, isRemoteCellEdit,
handleCellChange handleCellChange
) => { ) => {
let EditingCell;
const CellEditContext = React.createContext();
class CellEditProvider extends React.Component { class CellEditProvider extends React.Component {
static propTypes = { static propTypes = {
data: PropTypes.array.isRequired, data: PropTypes.array.isRequired,
@@ -31,6 +32,7 @@ export default (
constructor(props) { constructor(props) {
super(props); super(props);
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);
@@ -100,6 +102,8 @@ export default (
const { const {
cellEdit: { cellEdit: {
options: { nonEditableRows, errorMessage, ...optionsRest }, options: { nonEditableRows, errorMessage, ...optionsRest },
editingCellFactory,
createContext,
...cellEditRest ...cellEditRest
} }
} = this.props; } = this.props;
@@ -108,6 +112,7 @@ export default (
...optionsRest, ...optionsRest,
...cellEditRest, ...cellEditRest,
...this.state, ...this.state,
EditingCell,
nonEditableRows: _.isDefined(nonEditableRows) ? nonEditableRows() : [], nonEditableRows: _.isDefined(nonEditableRows) ? nonEditableRows() : [],
onStart: this.startEditing, onStart: this.startEditing,
onEscape: this.escapeEditing, onEscape: this.escapeEditing,
@@ -116,7 +121,7 @@ export default (
return ( return (
<CellEditContext.Provider <CellEditContext.Provider
value={ { ...newCellEdit } } value={ { cellEdit: newCellEdit } }
> >
{ this.props.children } { this.props.children }
</CellEditContext.Provider> </CellEditContext.Provider>
@@ -124,8 +129,7 @@ export default (
} }
} }
return { return {
Provider: CellEditProvider Provider: CellEditProvider,
Consumer: CellEditContext.Consumer
}; };
}; };
export const Consumer = CellEditContext.Consumer;

View File

@@ -1,44 +0,0 @@
/* eslint react/prop-types: 0 */
import React from 'react';
import { Consumer } from './context';
import createEditingCell from './editing-cell';
export default (_, onStartEdit) => {
const EditingCell = createEditingCell(_, onStartEdit);
const renderWithEditingCell = (props, cellEdit) => {
const content = _.get(props.row, props.column.dataField);
let editCellstyle = props.column.editCellStyle || {};
let editCellclasses = props.column.editCellClasses;
if (_.isFunction(props.column.editCellStyle)) {
editCellstyle = props.column.editCellStyle(
content,
props.row,
props.rowIndex,
props.columnIndex
);
}
if (_.isFunction(props.column.editCellClasses)) {
editCellclasses = props.column.editCellClasses(
content,
props.row,
props.rowIndex,
props.columnIndex)
;
}
return (
<EditingCell
{ ...props }
className={ editCellclasses }
style={ editCellstyle }
{ ...cellEdit }
/>
);
};
return props => (
<Consumer>
{ cellEdit => renderWithEditingCell(props, cellEdit) }
</Consumer>
);
};

View File

@@ -24,6 +24,7 @@ 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
} }
@@ -31,6 +32,7 @@ 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: {}
} }
@@ -121,7 +123,7 @@ export default (_, onStartEdit) =>
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);
@@ -174,13 +176,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 } />; 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

@@ -1,38 +0,0 @@
/* eslint react/prop-types: 0 */
import React from 'react';
import { DELAY_FOR_DBCLICK, DBCLICK_TO_CELL_EDIT, CLICK_TO_CELL_EDIT } from './const';
import { Consumer } from './context';
export default (Component, selectRowEnabled) => {
const renderWithCellEdit = (props, cellEdit) => {
const key = props.value;
const editableRow = !(
cellEdit.nonEditableRows.length > 0 &&
cellEdit.nonEditableRows.indexOf(key) > -1
);
const attrs = {};
if (selectRowEnabled && cellEdit.mode === DBCLICK_TO_CELL_EDIT) {
attrs.DELAY_FOR_DBCLICK = DELAY_FOR_DBCLICK;
}
return (
<Component
{ ...props }
{ ...attrs }
editingRowIdx={ cellEdit.ridx }
editingColIdx={ cellEdit.cidx }
editable={ editableRow }
onStart={ cellEdit.onStart }
clickToEdit={ cellEdit.mode === CLICK_TO_CELL_EDIT }
dbclickToEdit={ cellEdit.mode === DBCLICK_TO_CELL_EDIT }
/>
);
};
return props => (
<Consumer>
{ cellEdit => renderWithCellEdit(props, cellEdit) }
</Consumer>
);
};

View File

@@ -5,9 +5,10 @@ import PropTypes from 'prop-types';
class TextEditor extends Component { class TextEditor extends Component {
componentDidMount() { componentDidMount() {
const { defaultValue, didMount } = 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(); if (didMount) didMount();
} }
@@ -16,7 +17,7 @@ class TextEditor extends Component {
} }
render() { render() {
const { defaultValue, didMount, 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
@@ -38,11 +39,13 @@ 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,9 +10,10 @@ class TextAreaEditor extends Component {
} }
componentDidMount() { componentDidMount() {
const { defaultValue, didMount } = 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(); if (didMount) didMount();
} }
@@ -28,7 +29,7 @@ class TextAreaEditor extends Component {
} }
render() { render() {
const { defaultValue, didMount, 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
@@ -52,11 +53,13 @@ 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

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

@@ -3,13 +3,14 @@ import React from 'react';
import { shallow } from 'enzyme'; import { shallow } from 'enzyme';
import _ from 'react-bootstrap-table-next/src/utils'; import _ from 'react-bootstrap-table-next/src/utils';
import dataOperator from 'react-bootstrap-table-next/src/store/operators'; import dataOperator from 'react-bootstrap-table-next/src/store/operators';
import BootstrapTable from 'react-bootstrap-table-next/src/bootstrap-table';
import { import {
CLICK_TO_CELL_EDIT, CLICK_TO_CELL_EDIT,
DBCLICK_TO_CELL_EDIT, DBCLICK_TO_CELL_EDIT,
DELAY_FOR_DBCLICK DELAY_FOR_DBCLICK
} from '../src/const'; } from '../src/const';
import createCellEditContext, { Consumer } from '../src/context'; import createCellEditContext from '../src/context';
import cellEditFactory from '../index'; import cellEditFactory from '../index';
describe('CellEditContext', () => { describe('CellEditContext', () => {
@@ -41,7 +42,14 @@ describe('CellEditContext', () => {
const defaultSelectRow = undefined; const defaultSelectRow = undefined;
const mockBase = jest.fn((() => null)); const mockBase = jest.fn((props => (
<BootstrapTable
data={ data }
columns={ columns }
keyField={ keyField }
{ ...props }
/>
)));
const handleCellChange = jest.fn(); const handleCellChange = jest.fn();
@@ -67,11 +75,11 @@ describe('CellEditContext', () => {
selectRow={ selectRow } selectRow={ selectRow }
data={ data } data={ data }
> >
<Consumer> <CellEditContext.Consumer>
{ {
cellEditProps => mockBase(cellEditProps) cellEditProps => mockBase(cellEditProps)
} }
</Consumer> </CellEditContext.Consumer>
</CellEditContext.Provider> </CellEditContext.Provider>
); );
} }
@@ -86,6 +94,10 @@ describe('CellEditContext', () => {
expect(CellEditContext.Provider).toBeDefined(); expect(CellEditContext.Provider).toBeDefined();
}); });
it('should have correct Consumer property after calling createCellEditContext', () => {
expect(CellEditContext.Consumer).toBeDefined();
});
it('should have correct state.ridx', () => { it('should have correct state.ridx', () => {
expect(wrapper.state().ridx).toBeNull(); expect(wrapper.state().ridx).toBeNull();
}); });
@@ -101,11 +113,14 @@ describe('CellEditContext', () => {
it('should pass correct cell editing props to children element', () => { it('should pass correct cell editing props to children element', () => {
expect(wrapper.length).toBe(1); expect(wrapper.length).toBe(1);
expect(JSON.stringify(mockBase.mock.calls[0])).toEqual(JSON.stringify([{ expect(JSON.stringify(mockBase.mock.calls[0])).toEqual(JSON.stringify([{
...defaultCellEdit, cellEdit: {
DBCLICK_TO_CELL_EDIT, ...defaultCellEdit,
DELAY_FOR_DBCLICK, CLICK_TO_CELL_EDIT,
...wrapper.state(), DBCLICK_TO_CELL_EDIT,
nonEditableRows: [] DELAY_FOR_DBCLICK,
...wrapper.state(),
nonEditableRows: []
}
}])); }]));
}); });
}); });

View File

@@ -1,147 +0,0 @@
import 'jsdom-global/register';
import React from 'react';
import { mount, shallow } from 'enzyme';
import _ from 'react-bootstrap-table-next/src/utils';
import cellEditFactory from '../index';
import { CLICK_TO_CELL_EDIT } from '../src/const';
import createCellEditContext from '../src/context';
import bindEditingCell from '../src/editing-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(_);
const WithCellEditComponent = bindEditingCell(_);
beforeEach(() => {
columns = [{
dataField: 'id',
text: 'ID'
}, {
dataField: 'name',
text: 'Name'
}];
});
describe('if column.editCellClasses is defined as string', () => {
beforeEach(() => {
cellEdit = cellEditFactory({ mode: CLICK_TO_CELL_EDIT });
columns[1].editCellClasses = 'test-class-1';
wrapper = shallow(
<Provider data={ data } keyField={ keyField } cellEdit={ cellEdit }>
<WithCellEditComponent
row={ row }
column={ columns[1] }
rowIndex={ rowIndex }
columnIndex={ columnIndex }
/>
</Provider>
);
wrapper = wrapper.render();
});
it('should inject className target component correctly', () => {
expect(wrapper.hasClass(`${columns[1].editCellClasses}`)).toBeTruthy();
});
});
describe('if column.editCellStyle is defined as object', () => {
beforeEach(() => {
cellEdit = cellEditFactory({ mode: CLICK_TO_CELL_EDIT });
columns[1].editCellStyle = { color: 'pink' };
wrapper = mount(
<Provider data={ data } keyField={ keyField } cellEdit={ cellEdit }>
<WithCellEditComponent
row={ row }
column={ columns[1] }
rowIndex={ rowIndex }
columnIndex={ columnIndex }
/>
</Provider>
);
});
it('should inject style target component correctly', () => {
expect(wrapper.find('.react-bootstrap-table-editing-cell').prop('style')).toEqual(columns[1].editCellStyle);
});
});
describe('if column.editCellClasses is defined as function', () => {
const className = 'test-class-1';
beforeEach(() => {
cellEdit = cellEditFactory({ mode: CLICK_TO_CELL_EDIT });
columns[1].editCellClasses = jest.fn().mockReturnValue(className);
wrapper = mount(
<Provider data={ data } keyField={ keyField } cellEdit={ cellEdit }>
<WithCellEditComponent
row={ row }
column={ columns[1] }
rowIndex={ rowIndex }
columnIndex={ columnIndex }
/>
</Provider>
);
});
it('should inject empty className and style to target component', () => {
expect(wrapper.find(className)).toBeTruthy();
});
it('should call column.editCellClasses function correctly', () => {
expect(columns[1].editCellClasses).toHaveBeenCalledTimes(1);
expect(columns[1].editCellClasses).toHaveBeenCalledWith(
_.get(row, columns[1].dataField),
row,
rowIndex,
columnIndex
);
});
});
describe('if column.editCellStyle is defined as function', () => {
const style = { color: 'blue' };
beforeEach(() => {
cellEdit = cellEditFactory({ mode: CLICK_TO_CELL_EDIT });
columns[1].editCellStyle = jest.fn().mockReturnValue(style);
wrapper = mount(
<Provider data={ data } keyField={ keyField } cellEdit={ cellEdit }>
<WithCellEditComponent
row={ row }
column={ columns[1] }
rowIndex={ rowIndex }
columnIndex={ columnIndex }
/>
</Provider>
);
});
it('should inject style target component correctly', () => {
expect(wrapper.find('.react-bootstrap-table-editing-cell').prop('style')).toEqual(style);
});
it('should call column.editCellStyle function correctly', () => {
expect(columns[1].editCellStyle).toHaveBeenCalledTimes(1);
expect(columns[1].editCellStyle).toHaveBeenCalledWith(
_.get(row, columns[1].dataField),
row,
rowIndex,
columnIndex
);
});
});
});

View File

@@ -1,138 +0,0 @@
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, DELAY_FOR_DBCLICK } from '../src/const';
import createCellEditContext from '../src/context';
import bindCellEditing from '../src/row-binder';
describe('Row Binder', () => {
let wrapper;
let cellEdit;
const data = [{
id: 1,
name: 'A'
}, {
id: 2,
name: 'B'
}];
const row = { id: 1, name: 'A' };
const keyField = 'id';
const value = _.get(row, keyField);
const { Provider } = createCellEditContext(_, op, false, jest.fn());
const BaseComponent = () => null;
describe('if cellEdit.nonEditableRows is undefined', () => {
beforeEach(() => {
const WithCellEditComponent = bindCellEditing(
props => <BaseComponent { ...props } />,
false
);
cellEdit = cellEditFactory({ mode: CLICK_TO_CELL_EDIT });
wrapper = mount(
<Provider data={ data } keyField={ keyField } cellEdit={ cellEdit }>
<WithCellEditComponent value={ value } />
</Provider>
);
});
it('should inject correct props to target component', () => {
expect(wrapper.find(BaseComponent)).toHaveLength(1);
expect(wrapper.find(BaseComponent).prop('editingRowIdx')).toBeNull();
expect(wrapper.find(BaseComponent).prop('editingColIdx')).toBeNull();
expect(wrapper.find(BaseComponent).prop('editable')).toBeTruthy();
});
});
describe('if cellEdit.nonEditableRows is defined', () => {
const nonEditableRows = jest.fn().mockReturnValue([value]);
describe('if value prop is match in one of cellEdit.nonEditableRows', () => {
beforeEach(() => {
const WithCellEditComponent = bindCellEditing(
props => <BaseComponent { ...props } />,
false
);
cellEdit = cellEditFactory({ mode: CLICK_TO_CELL_EDIT, nonEditableRows });
wrapper = mount(
<Provider data={ data } keyField={ keyField } cellEdit={ cellEdit }>
<WithCellEditComponent value={ value } />
</Provider>
);
});
it('should inject correct editable prop as false to target component', () => {
expect(wrapper.find(BaseComponent)).toHaveLength(1);
expect(wrapper.find(BaseComponent).prop('editable')).toBeFalsy();
});
});
describe('if value prop is not match in one of cellEdit.nonEditableRows', () => {
beforeEach(() => {
const WithCellEditComponent = bindCellEditing(
props => <BaseComponent { ...props } />,
false
);
cellEdit = cellEditFactory({ mode: CLICK_TO_CELL_EDIT, nonEditableRows });
wrapper = mount(
<Provider data={ data } keyField={ keyField } cellEdit={ cellEdit }>
<WithCellEditComponent value={ 2 } />
</Provider>
);
});
it('should inject correct editable prop as false to target component', () => {
expect(wrapper.find(BaseComponent)).toHaveLength(1);
expect(wrapper.find(BaseComponent).prop('editable')).toBeTruthy();
});
});
});
describe(`if selectRowEnabled argument is true and cellEdit.mode is ${DBCLICK_TO_CELL_EDIT}`, () => {
beforeEach(() => {
const WithCellEditComponent = bindCellEditing(
props => <BaseComponent { ...props } />,
true
);
cellEdit = cellEditFactory({ mode: DBCLICK_TO_CELL_EDIT });
wrapper = mount(
<Provider data={ data } keyField={ keyField } cellEdit={ cellEdit }>
<WithCellEditComponent value={ value } />
</Provider>
);
});
it('should inject correct DELAY_FOR_DBCLICK prop to target component', () => {
expect(wrapper.find(BaseComponent)).toHaveLength(1);
expect(wrapper.find(BaseComponent).prop('DELAY_FOR_DBCLICK')).toEqual(DELAY_FOR_DBCLICK);
});
});
describe('if cellEdit.ridx and cellEdit.cidx are defined', () => {
const ridx = 0;
const cidx = 1;
beforeEach(() => {
const WithCellEditComponent = bindCellEditing(
props => <BaseComponent { ...props } />,
false
);
cellEdit = cellEditFactory({ mode: CLICK_TO_CELL_EDIT });
wrapper = mount(
<Provider data={ data } keyField={ keyField } cellEdit={ cellEdit }>
<WithCellEditComponent value={ value } />
</Provider>
);
wrapper.instance().startEditing(ridx, cidx);
wrapper.update();
});
it('should inject correct editable prop as false to target component', () => {
expect(wrapper.find(BaseComponent)).toHaveLength(1);
expect(wrapper.find(BaseComponent).prop('editingRowIdx')).toEqual(ridx);
expect(wrapper.find(BaseComponent).prop('editingColIdx')).toEqual(cidx);
});
});
});

View File

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

@@ -2,9 +2,9 @@ import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next'; import BootstrapTable from 'react-bootstrap-table-next';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsExpandRowsGenerator } from 'utils/common';
const products = productsGenerator(); const products = productsExpandRowsGenerator();
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
@@ -17,12 +17,8 @@ const columns = [{
text: 'Product Price' text: 'Product Price'
}]; }];
const selectRow = {
mode: 'checkbox'
};
const expandRow = { const expandRow = {
showExpandColumn: true, onlyOneExpanding: true,
renderer: row => ( renderer: row => (
<div> <div>
<p>{ `This Expand row is belong to rowKey ${row.id}` }</p> <p>{ `This Expand row is belong to rowKey ${row.id}` }</p>
@@ -46,13 +42,7 @@ const columns = [{
text: 'Product Price' text: 'Product Price'
}]; }];
const selectRow = {
mode: 'checkbox',
clickToSelect: true
};
const expandRow = { const expandRow = {
showExpandColumn: true,
renderer: row => ( renderer: row => (
<div> <div>
<p>{ \`This Expand row is belong to rowKey $\{row.id}\` }</p> <p>{ \`This Expand row is belong to rowKey $\{row.id}\` }</p>
@@ -66,7 +56,7 @@ const expandRow = {
keyField='id' keyField='id'
data={ products } data={ products }
columns={ columns } columns={ columns }
selectRow={ selectRow } expandRow={ expandRow }
/> />
`; `;
@@ -76,7 +66,6 @@ export default () => (
keyField="id" keyField="id"
data={ products } data={ products }
columns={ columns } columns={ columns }
selectRow={ selectRow }
expandRow={ expandRow } expandRow={ expandRow }
/> />
<Code>{ sourceCode }</Code> <Code>{ sourceCode }</Code>

View File

@@ -1,7 +1,6 @@
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next'; import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor';
import Code from 'components/common/code-block'; import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common'; import { productsGenerator } from 'utils/common';
@@ -21,12 +20,11 @@ const columns = [{
const selectRow = { const selectRow = {
mode: 'checkbox', mode: 'checkbox',
clickToSelect: true, clickToSelect: true,
clickToEdit: true hideSelectAll: true
}; };
const sourceCode = `\ const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next'; import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor';
const columns = [{ const columns = [{
dataField: 'id', dataField: 'id',
@@ -42,28 +40,20 @@ const columns = [{
const selectRow = { const selectRow = {
mode: 'checkbox', mode: 'checkbox',
clickToSelect: true, clickToSelect: true,
clickToEdit: true hideSelectAll: true
}; };
<BootstrapTable <BootstrapTable
keyField="id" keyField='id'
data={ products } data={ products }
columns={ columns } columns={ columns }
selectRow={ selectRow } selectRow={ selectRow }
cellEdit={ cellEditFactory({ mode: 'dbclick' }) }
/> />
`; `;
export default () => ( export default () => (
<div> <div>
<h3>Double click to edit cell</h3> <BootstrapTable keyField="id" data={ products } columns={ columns } selectRow={ selectRow } />
<BootstrapTable
keyField="id"
data={ products }
columns={ columns }
selectRow={ selectRow }
cellEdit={ cellEditFactory({ mode: 'dbclick' }) }
/>
<Code>{ sourceCode }</Code> <Code>{ sourceCode }</Code>
</div> </div>
); );

View File

@@ -1,5 +1,5 @@
/* eslint no-unused-vars: 0 */ /* eslint no-unused-vars: 0 */
/* eslint no-console: 0 */ /* eslint no-alert: 0 */
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next'; import BootstrapTable from 'react-bootstrap-table-next';
@@ -21,10 +21,7 @@ const columns = [{
const rowEvents = { const rowEvents = {
onClick: (e, row, rowIndex) => { onClick: (e, row, rowIndex) => {
console.log(`clicked on row with index: ${rowIndex}`); alert(`clicked on row with index: ${rowIndex}`);
},
onMouseEnter: (e, row, rowIndex) => {
console.log(`enter on row with index: ${rowIndex}`);
} }
}; };
@@ -44,10 +41,7 @@ const columns = [{
const rowEvents = { const rowEvents = {
onClick: (e, row, rowIndex) => { onClick: (e, row, rowIndex) => {
console.log(\`clicked on row with index: \${rowIndex}\`); alert(\`clicked on row with index: \${rowIndex}\`);
},
onMouseEnter: (e, row, rowIndex) => {
console.log(\`enter on row with index: \${rowIndex}\`);
} }
}; };
@@ -56,7 +50,7 @@ const rowEvents = {
export default () => ( export default () => (
<div> <div>
<h3>Try to click or hover on any rows</h3> <h3>Try to click on any rows</h3>
<BootstrapTable keyField="id" data={ products } columns={ columns } rowEvents={ rowEvents } /> <BootstrapTable keyField="id" data={ products } columns={ columns } rowEvents={ rowEvents } />
<Code>{ sourceCode }</Code> <Code>{ sourceCode }</Code>
</div> </div>

View File

@@ -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

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

View File

@@ -97,9 +97,9 @@ 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 DBClickEditWithSelection from 'examples/cell-edit/dbclick-to-edit-with-selection-table';
import DropdownEditorTable from 'examples/cell-edit/dropdown-editor-table'; import DropdownEditorTable from 'examples/cell-edit/dropdown-editor-table';
import TextareaEditorTable from 'examples/cell-edit/textarea-editor-table'; import TextareaEditorTable from 'examples/cell-edit/textarea-editor-table';
import CheckboxEditorTable from 'examples/cell-edit/checkbox-editor-table'; import CheckboxEditorTable from 'examples/cell-edit/checkbox-editor-table';
@@ -113,10 +113,10 @@ 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 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 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';
@@ -128,6 +128,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';
@@ -138,6 +139,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';
@@ -278,11 +280,11 @@ 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 />)
.add('Custom Editor Style', () => <EditorStyleTable />) .add('Custom Editor Style', () => <EditorStyleTable />)
.add('DoubleClick to Edit with Selection', () => <DBClickEditWithSelection />)
.add('Dropdown Editor', () => <DropdownEditorTable />) .add('Dropdown Editor', () => <DropdownEditorTable />)
.add('Textarea Editor', () => <TextareaEditorTable />) .add('Textarea Editor', () => <TextareaEditorTable />)
.add('Checkbox Editor', () => <CheckboxEditorTable />) .add('Checkbox Editor', () => <CheckboxEditorTable />)
@@ -297,10 +299,10 @@ storiesOf('Row Selection', module)
.add('Default Select', () => <DefaultSelectTable />) .add('Default Select', () => <DefaultSelectTable />)
.add('Selection Management', () => <SelectionManagement />) .add('Selection Management', () => <SelectionManagement />)
.add('Click to Select and Edit Cell', () => <ClickToSelectWithCellEditTable />) .add('Click to Select and Edit Cell', () => <ClickToSelectWithCellEditTable />)
.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 />)
@@ -313,6 +315,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 />);
@@ -325,6 +328,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 />)

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.

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
}) })
]), ]),
@@ -42,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);
@@ -85,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.3", "version": "1.1.0",
"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(['\ufeff', content], { type: 'text/plain;charset=utf-8' }), new Blob([content], { type: 'text/plain;charset=utf-8' }),
fileName, fileName,
noAutoBOM noAutoBOM
); );

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

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

@@ -3,104 +3,129 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import cs from 'classnames';
import _ from './utils'; import _ from './utils';
import Row from './simple-row'; import Row from './row';
import RowAggregator from './row-aggregator'; import ExpandRow from './row-expand/expand-row';
import RowSection from './row-section'; import RowSection from './row-section';
import Const from './const'; import Const from './const';
import bindSelection from './row-selection/row-binder';
import bindExpansion from './row-expand/row-binder';
class Body extends React.Component { const Body = (props) => {
constructor(props) { const {
super(props); columns,
if (props.cellEdit.createContext) { data,
this.EditingCell = props.cellEdit.createEditingCell(_, props.cellEdit.options.onStartEdit); keyField,
isEmpty,
noDataIndication,
visibleColumnSize,
cellEdit,
selectRow,
selectedRowKeys,
rowStyle,
rowClasses,
rowEvents,
expandRow
} = props;
const {
bgColor,
nonSelectable
} = selectRow;
let content;
if (isEmpty) {
const indication = _.isFunction(noDataIndication) ? noDataIndication() : noDataIndication;
if (!indication) {
return null;
} }
this.RowComponent = bindSelection(RowAggregator); content = <RowSection content={ indication } colSpan={ visibleColumnSize } />;
} } else {
const nonEditableRows = cellEdit.nonEditableRows || [];
content = data.map((row, index) => {
const key = _.get(row, keyField);
const editable = !(nonEditableRows.length > 0 && nonEditableRows.indexOf(key) > -1);
render() { const selected = selectRow.mode !== Const.ROW_SELECT_DISABLED
const { ? selectedRowKeys.includes(key)
columns, : null;
data,
keyField,
isEmpty,
noDataIndication,
visibleColumnSize,
cellEdit,
selectRow,
rowStyle,
rowClasses,
rowEvents,
expandRow
} = this.props;
let content; const attrs = rowEvents || {};
let style = _.isFunction(rowStyle) ? rowStyle(row, index) : rowStyle;
let classes = (_.isFunction(rowClasses) ? rowClasses(row, index) : rowClasses);
if (selected) {
const selectedStyle = _.isFunction(selectRow.style)
? selectRow.style(row, index)
: selectRow.style;
if (isEmpty) { const selectedClasses = _.isFunction(selectRow.classes)
const indication = _.isFunction(noDataIndication) ? noDataIndication() : noDataIndication; ? selectRow.classes(row, index)
if (!indication) { : selectRow.classes;
return null;
}
content = <RowSection content={ indication } colSpan={ visibleColumnSize } />;
} else {
let RowComponent = Row;
const selectRowEnabled = selectRow.mode !== Const.ROW_SELECT_DISABLED;
const expandRowEnabled = !!expandRow.renderer;
const additionalRowProps = {}; style = {
if (expandRowEnabled) { ...style,
RowComponent = bindExpansion(RowAggregator, visibleColumnSize); ...selectedStyle
}
// if (selectRowEnabled) {
// RowComponent = bindSelection(expandRowEnabled ? RowComponent : RowAggregator);
// }
if (cellEdit.createContext) {
RowComponent = cellEdit.bindRowLevelCellEdit(RowComponent, selectRowEnabled, keyField, _);
additionalRowProps.EditingCellComponent = this.EditingCell;
}
if (selectRowEnabled || expandRowEnabled) {
additionalRowProps.expandRow = expandRow;
additionalRowProps.selectRow = selectRow;
}
content = data.map((row, index) => {
const key = _.get(row, keyField);
const baseRowProps = {
key,
row,
columns,
keyField,
cellEdit,
value: key,
rowIndex: index,
attrs: rowEvents || {},
...additionalRowProps
}; };
classes = cs(classes, selectedClasses);
baseRowProps.style = _.isFunction(rowStyle) ? rowStyle(row, index) : rowStyle; if (bgColor) {
baseRowProps.className = (_.isFunction(rowClasses) ? rowClasses(row, index) : rowClasses); style = style || {};
style.backgroundColor = _.isFunction(bgColor) ? bgColor(row, index) : bgColor;
}
}
return <this.RowComponent { ...baseRowProps } />; const selectable = !nonSelectable || !nonSelectable.includes(key);
}); const expandable = expandRow && !expandRow.nonExpandable.includes(key);
} const expanded = expandRow && expandRow.expanded.includes(key);
return ( const result = [
<tbody>{ content }</tbody> <Row
); key={ key }
row={ row }
keyField={ keyField }
rowIndex={ index }
columns={ columns }
cellEdit={ cellEdit }
editable={ editable }
selectable={ selectable }
expandable={ expandable }
selected={ selected }
expanded={ expanded }
selectRow={ selectRow }
expandRow={ expandRow }
style={ style }
className={ classes }
attrs={ attrs }
/>
];
if (expanded) {
result.push((
<ExpandRow
key={ `${key}-expanding` }
colSpan={ visibleColumnSize }
>
{ expandRow.renderer(row) }
</ExpandRow>
));
}
return result;
});
} }
}
return (
<tbody>{ content }</tbody>
);
};
Body.propTypes = { Body.propTypes = {
keyField: PropTypes.string.isRequired, keyField: PropTypes.string.isRequired,
data: PropTypes.array.isRequired, data: PropTypes.array.isRequired,
columns: PropTypes.array.isRequired, columns: PropTypes.array.isRequired,
selectRow: PropTypes.object selectRow: PropTypes.object,
selectedRowKeys: PropTypes.array
}; };
export default Body; export default Body;

View File

@@ -9,6 +9,7 @@ import Caption from './caption';
import Body from './body'; import Body from './body';
import PropsBaseResolver from './props-resolver'; import PropsBaseResolver from './props-resolver';
import Const from './const'; import Const from './const';
import { getSelectionSummary } from './store/selection';
class BootstrapTable extends PropsBaseResolver(Component) { class BootstrapTable extends PropsBaseResolver(Component) {
constructor(props) { constructor(props) {
@@ -55,9 +56,7 @@ class BootstrapTable extends PropsBaseResolver(Component) {
rowClasses, rowClasses,
wrapperClasses, wrapperClasses,
rowEvents, rowEvents,
selectRow, selected
expandRow,
cellEdit
} = this.props; } = this.props;
const tableWrapperClass = cs('react-bootstrap-table', wrapperClasses); const tableWrapperClass = cs('react-bootstrap-table', wrapperClasses);
@@ -69,7 +68,20 @@ class BootstrapTable extends PropsBaseResolver(Component) {
'table-condensed': condensed 'table-condensed': condensed
}, classes); }, classes);
const cellSelectionInfo = this.resolveSelectRowProps({
onRowSelect: this.props.onRowSelect
});
const { allRowsSelected, allRowsNotSelected } = getSelectionSummary(data, keyField, selected);
const headerCellSelectionInfo = this.resolveSelectRowPropsForHeader({
onAllRowsSelect: this.props.onAllRowsSelect,
selected,
allRowsSelected,
allRowsNotSelected
});
const tableCaption = (caption && <Caption>{ caption }</Caption>); const tableCaption = (caption && <Caption>{ caption }</Caption>);
const expandRow = this.resolveExpandRowProps();
return ( return (
<div className={ tableWrapperClass }> <div className={ tableWrapperClass }>
@@ -83,7 +95,7 @@ class BootstrapTable extends PropsBaseResolver(Component) {
onSort={ this.props.onSort } onSort={ this.props.onSort }
onFilter={ this.props.onFilter } onFilter={ this.props.onFilter }
onExternalFilter={ this.props.onExternalFilter } onExternalFilter={ this.props.onExternalFilter }
selectRow={ selectRow } selectRow={ headerCellSelectionInfo }
expandRow={ expandRow } expandRow={ expandRow }
/> />
<Body <Body
@@ -93,8 +105,9 @@ class BootstrapTable extends PropsBaseResolver(Component) {
isEmpty={ this.isEmpty() } isEmpty={ this.isEmpty() }
visibleColumnSize={ this.visibleColumnSize() } visibleColumnSize={ this.visibleColumnSize() }
noDataIndication={ noDataIndication } noDataIndication={ noDataIndication }
cellEdit={ cellEdit } cellEdit={ this.props.cellEdit || {} }
selectRow={ selectRow } selectRow={ cellSelectionInfo }
selectedRowKeys={ selected }
expandRow={ expandRow } expandRow={ expandRow }
rowStyle={ rowStyle } rowStyle={ rowStyle }
rowClasses={ rowClasses } rowClasses={ rowClasses }
@@ -130,13 +143,10 @@ BootstrapTable.propTypes = {
filter: PropTypes.object, filter: PropTypes.object,
cellEdit: PropTypes.object, cellEdit: PropTypes.object,
selectRow: PropTypes.shape({ selectRow: PropTypes.shape({
mode: PropTypes.oneOf([ mode: PropTypes.oneOf([Const.ROW_SELECT_SINGLE, Const.ROW_SELECT_MULTIPLE]).isRequired,
Const.ROW_SELECT_SINGLE,
Const.ROW_SELECT_MULTIPLE,
Const.ROW_SELECT_DISABLED
]).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]),
@@ -147,16 +157,22 @@ BootstrapTable.propTypes = {
selectionRenderer: PropTypes.func, selectionRenderer: PropTypes.func,
selectionHeaderRenderer: PropTypes.func selectionHeaderRenderer: PropTypes.func
}), }),
onRowSelect: PropTypes.func,
onAllRowsSelect: PropTypes.func,
expandRow: PropTypes.shape({ expandRow: PropTypes.shape({
renderer: PropTypes.func, renderer: PropTypes.func.isRequired,
expanded: PropTypes.array, expanded: PropTypes.array,
onExpand: PropTypes.func, onExpand: PropTypes.func,
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
}), }),
onRowExpand: PropTypes.func,
onAllRowExpand: PropTypes.func,
isAnyExpands: PropTypes.bool,
rowStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), rowStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
rowEvents: PropTypes.object, rowEvents: PropTypes.object,
rowClasses: PropTypes.oneOfType([PropTypes.string, PropTypes.func]), rowClasses: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
@@ -186,21 +202,7 @@ BootstrapTable.defaultProps = {
bordered: true, bordered: true,
hover: false, hover: false,
condensed: false, condensed: false,
noDataIndication: null, noDataIndication: null
selectRow: {
mode: Const.ROW_SELECT_DISABLED,
selected: [],
hideSelectColumn: true
},
expandRow: {
renderer: undefined,
expanded: [],
nonExpandable: []
},
cellEdit: {
mode: null,
nonEditableRows: []
}
}; };
export default BootstrapTable; export default BootstrapTable;

View File

@@ -73,10 +73,7 @@ class Cell extends Component {
formatExtraData formatExtraData
} = column; } = column;
const attrs = { ...rest }; const attrs = { ...rest };
let content = this.props.children; let content = column.isDummyField ? null : _.get(row, dataField);
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

@@ -4,8 +4,8 @@ import React, { Component } from 'react';
import _ from '../utils'; import _ from '../utils';
import createDataContext from './data-context'; import createDataContext from './data-context';
import createSortContext from './sort-context'; import createSortContext from './sort-context';
import SelectionContext from './selection-context'; import createSelectionContext from './selection-context';
import RowExpandContext from './row-expand-context'; import createRowExpandContext from './row-expand-context';
import remoteResolver from '../props-resolver/remote-resolver'; import remoteResolver from '../props-resolver/remote-resolver';
import { BootstrapContext } from './bootstrap'; import { BootstrapContext } from './bootstrap';
import dataOperator from '../store/operators'; import dataOperator from '../store/operators';
@@ -22,11 +22,11 @@ const withContext = Base =>
} }
if (props.selectRow) { if (props.selectRow) {
this.SelectionContext = SelectionContext; this.SelectionContext = createSelectionContext(dataOperator);
} }
if (props.expandRow) { if (props.expandRow) {
this.RowExpandContext = RowExpandContext; this.RowExpandContext = createRowExpandContext(dataOperator);
} }
if (props.cellEdit && props.cellEdit.createContext) { if (props.cellEdit && props.cellEdit.createContext) {
@@ -57,17 +57,23 @@ const withContext = Base =>
renderBase() { renderBase() {
return ( return (
rootProps, rootProps,
cellEditProps,
filterProps, filterProps,
searchProps, searchProps,
sortProps, sortProps,
paginationProps, paginationProps,
expandProps,
selectionProps
) => ( ) => (
<Base <Base
{ ...this.props } { ...this.props }
{ ...selectionProps }
{ ...sortProps } { ...sortProps }
{ ...cellEditProps }
{ ...filterProps } { ...filterProps }
{ ...searchProps } { ...searchProps }
{ ...paginationProps } { ...paginationProps }
{ ...expandProps }
data={ rootProps.getData(filterProps, searchProps, sortProps, paginationProps) } data={ rootProps.getData(filterProps, searchProps, sortProps, paginationProps) }
/> />
); );
@@ -76,25 +82,32 @@ const withContext = Base =>
renderWithSelectionCtx(base, baseProps) { renderWithSelectionCtx(base, baseProps) {
return ( return (
rootProps, rootProps,
cellEditProps,
filterProps, filterProps,
searchProps, searchProps,
sortProps, sortProps,
paginationProps paginationProps,
expandProps
) => ( ) => (
<this.SelectionContext.Provider <this.SelectionContext.Provider
{ ...baseProps } { ...baseProps }
selectRow={ this.props.selectRow } selectRow={ this.props.selectRow }
data={ rootProps.getData(filterProps, searchProps, sortProps, paginationProps) } data={ rootProps.getData(filterProps, searchProps, sortProps, paginationProps) }
> >
{ <this.SelectionContext.Consumer>
base( {
rootProps, selectionProps => base(
filterProps, rootProps,
searchProps, cellEditProps,
sortProps, filterProps,
paginationProps searchProps,
) sortProps,
} paginationProps,
expandProps,
selectionProps
)
}
</this.SelectionContext.Consumer>
</this.SelectionContext.Provider> </this.SelectionContext.Provider>
); );
} }
@@ -102,6 +115,7 @@ const withContext = Base =>
renderWithRowExpandCtx(base, baseProps) { renderWithRowExpandCtx(base, baseProps) {
return ( return (
rootProps, rootProps,
cellEditProps,
filterProps, filterProps,
searchProps, searchProps,
sortProps, sortProps,
@@ -112,15 +126,19 @@ const withContext = Base =>
expandRow={ this.props.expandRow } expandRow={ this.props.expandRow }
data={ rootProps.getData(filterProps, searchProps, sortProps, paginationProps) } data={ rootProps.getData(filterProps, searchProps, sortProps, paginationProps) }
> >
{ <this.RowExpandContext.Consumer>
base( {
rootProps, expandProps => base(
filterProps, rootProps,
searchProps, cellEditProps,
sortProps, filterProps,
paginationProps searchProps,
) sortProps,
} paginationProps,
expandProps
)
}
</this.RowExpandContext.Consumer>
</this.RowExpandContext.Provider> </this.RowExpandContext.Provider>
); );
} }
@@ -128,6 +146,7 @@ const withContext = Base =>
renderWithPaginationCtx(base) { renderWithPaginationCtx(base) {
return ( return (
rootProps, rootProps,
cellEditProps,
filterProps, filterProps,
searchProps, searchProps,
sortProps sortProps
@@ -142,6 +161,7 @@ const withContext = Base =>
{ {
paginationProps => base( paginationProps => base(
rootProps, rootProps,
cellEditProps,
filterProps, filterProps,
searchProps, searchProps,
sortProps, sortProps,
@@ -156,6 +176,7 @@ const withContext = Base =>
renderWithSortCtx(base, baseProps) { renderWithSortCtx(base, baseProps) {
return ( return (
rootProps, rootProps,
cellEditProps,
filterProps, filterProps,
searchProps searchProps
) => ( ) => (
@@ -170,6 +191,7 @@ const withContext = Base =>
{ {
sortProps => base( sortProps => base(
rootProps, rootProps,
cellEditProps,
filterProps, filterProps,
searchProps, searchProps,
sortProps, sortProps,
@@ -183,6 +205,7 @@ const withContext = Base =>
renderWithSearchCtx(base, baseProps) { renderWithSearchCtx(base, baseProps) {
return ( return (
rootProps, rootProps,
cellEditProps,
filterProps filterProps
) => ( ) => (
<this.SearchContext.Provider <this.SearchContext.Provider
@@ -195,6 +218,7 @@ const withContext = Base =>
{ {
searchProps => base( searchProps => base(
rootProps, rootProps,
cellEditProps,
filterProps, filterProps,
searchProps searchProps
) )
@@ -205,7 +229,10 @@ const withContext = Base =>
} }
renderWithFilterCtx(base, baseProps) { renderWithFilterCtx(base, baseProps) {
return rootProps => ( return (
rootProps,
cellEditProps
) => (
<this.FilterContext.Provider <this.FilterContext.Provider
{ ...baseProps } { ...baseProps }
ref={ n => this.filterContext = n } ref={ n => this.filterContext = n }
@@ -215,6 +242,7 @@ const withContext = Base =>
{ {
filterProps => base( filterProps => base(
rootProps, rootProps,
cellEditProps,
filterProps filterProps
) )
} }
@@ -231,7 +259,11 @@ const withContext = Base =>
cellEdit={ this.props.cellEdit } cellEdit={ this.props.cellEdit }
data={ rootProps.getData() } data={ rootProps.getData() }
> >
{ base(rootProps) } <this.CellEditContext.Consumer>
{
cellEditProps => base(rootProps, cellEditProps)
}
</this.CellEditContext.Consumer>
</this.CellEditContext.Provider> </this.CellEditContext.Provider>
); );
} }

View File

@@ -1,90 +1,92 @@
/* eslint react/prop-types: 0 */ /* eslint react/prop-types: 0 */
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import dataOperator from '../store/operators';
const RowExpandContext = React.createContext(); export default (
dataOperator
) => {
const RowExpandContext = React.createContext();
class RowExpandProvider extends React.Component { class RowExpandProvider extends React.Component {
static propTypes = { static propTypes = {
children: PropTypes.node.isRequired, children: PropTypes.node.isRequired,
data: PropTypes.array.isRequired, data: PropTypes.array.isRequired,
keyField: PropTypes.string.isRequired keyField: PropTypes.string.isRequired
}
state = { expanded: this.props.expandRow.expanded || [] };
componentWillReceiveProps(nextProps) {
if (nextProps.expandRow) {
this.setState(() => ({
expanded: nextProps.expandRow.expanded || this.state.expanded
}));
}
}
handleRowExpand = (rowKey, expanded, rowIndex, e) => {
const { data, keyField, expandRow: { onExpand } } = this.props;
let currExpanded = [...this.state.expanded];
if (expanded) {
currExpanded.push(rowKey);
} else {
currExpanded = currExpanded.filter(value => value !== rowKey);
} }
if (onExpand) { state = { expanded: this.props.expandRow.expanded || [] };
const row = dataOperator.getRowByRowId(data, keyField, rowKey);
onExpand(row, expanded, rowIndex, e);
}
this.setState(() => ({ expanded: currExpanded }));
}
handleAllRowExpand = (e, expandAll) => { componentWillReceiveProps(nextProps) {
const { if (nextProps.expandRow) {
data, this.setState(() => ({
keyField, expanded: nextProps.expandRow.expanded || this.state.expanded
expandRow: { }));
onExpandAll,
nonExpandable
} }
} = this.props;
const { expanded } = this.state;
let currExpanded;
if (expandAll) {
currExpanded = expanded.concat(dataOperator.expandableKeys(data, keyField, nonExpandable));
} else {
currExpanded = expanded.filter(s => typeof data.find(d => d[keyField] === s) === 'undefined');
} }
if (onExpandAll) { handleRowExpand = (rowKey, expanded, rowIndex, e) => {
onExpandAll(expandAll, dataOperator.getExpandedRows(data, keyField, currExpanded), e); const { data, keyField, expandRow: { onExpand, onlyOneExpanding } } = this.props;
let currExpanded = [...this.state.expanded];
if (expanded) {
if (onlyOneExpanding) currExpanded = [rowKey];
else currExpanded.push(rowKey);
} else {
currExpanded = currExpanded.filter(value => value !== rowKey);
}
if (onExpand) {
const row = dataOperator.getRowByRowId(data, keyField, rowKey);
onExpand(row, expanded, rowIndex, e);
}
this.setState(() => ({ expanded: currExpanded }));
} }
this.setState(() => ({ expanded: currExpanded })); handleAllRowExpand = (e, expandAll) => {
} const {
data,
keyField,
expandRow: {
onExpandAll,
nonExpandable
}
} = this.props;
const { expanded } = this.state;
render() { let currExpanded;
const { data, keyField } = this.props;
return (
<RowExpandContext.Provider
value={ {
...this.props.expandRow,
expanded: this.state.expanded,
isAnyExpands: dataOperator.isAnyExpands(data, keyField, this.state.expanded),
onRowExpand: this.handleRowExpand,
onAllRowExpand: this.handleAllRowExpand
} }
>
{ this.props.children }
</RowExpandContext.Provider>
);
}
}
export default { if (expandAll) {
Provider: RowExpandProvider, currExpanded = expanded.concat(dataOperator.expandableKeys(data, keyField, nonExpandable));
Consumer: RowExpandContext.Consumer } else {
currExpanded = expanded.filter(s => typeof data.find(d => d[keyField] === s) === 'undefined');
}
if (onExpandAll) {
onExpandAll(expandAll, dataOperator.getExpandedRows(data, keyField, currExpanded), e);
}
this.setState(() => ({ expanded: currExpanded }));
}
render() {
const { data, keyField } = this.props;
return (
<RowExpandContext.Provider
value={ {
isAnyExpands: dataOperator.isAnyExpands(data, keyField, this.state.expanded),
expanded: this.state.expanded,
onRowExpand: this.handleRowExpand,
onAllRowExpand: this.handleAllRowExpand
} }
>
{ this.props.children }
</RowExpandContext.Provider>
);
}
}
return {
Provider: RowExpandProvider,
Consumer: RowExpandContext.Consumer
};
}; };

View File

@@ -3,124 +3,113 @@ import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import Const from '../const'; import Const from '../const';
import dataOperator from '../store/operators'; export default (
import { getSelectionSummary } from '../store/selection'; dataOperator
) => {
const SelectionContext = React.createContext();
const SelectionContext = React.createContext(); class SelectionProvider extends React.Component {
class SelectionProvider extends React.Component { static propTypes = {
static propTypes = { children: PropTypes.node.isRequired,
children: PropTypes.node.isRequired, data: PropTypes.array.isRequired,
data: PropTypes.array.isRequired, 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) || [] };
componentWillReceiveProps(nextProps) {
if (nextProps.selectRow) {
this.setState(() => ({
selected: nextProps.selectRow.selected || this.state.selected
}));
}
}
// exposed API
getSelected() {
return this.state.selected;
}
handleRowSelect = (rowKey, checked, rowIndex, e) => {
const { data, keyField, selectRow: { mode, onSelect } } = this.props;
const { ROW_SELECT_SINGLE } = Const;
let currSelected = [...this.state.selected];
if (mode === ROW_SELECT_SINGLE) { // when select mode is radio
currSelected = [rowKey];
} else if (checked) { // when select mode is checkbox
currSelected.push(rowKey);
} else {
currSelected = currSelected.filter(value => value !== rowKey);
} }
if (onSelect) { constructor(props) {
const row = dataOperator.getRowByRowId(data, keyField, rowKey); super(props);
onSelect(row, checked, rowIndex, e); if (props.registerExposedAPI) {
} const getSelected = () => this.getSelected();
props.registerExposedAPI(getSelected);
this.setState(() => ({ selected: currSelected }));
}
handleAllRowsSelect = (e, isUnSelect) => {
const {
data,
keyField,
selectRow: {
onSelectAll,
nonSelectable
} }
} = this.props;
const { selected } = this.state;
let currSelected;
if (!isUnSelect) {
currSelected = selected.concat(dataOperator.selectableKeys(data, keyField, nonSelectable));
} else {
currSelected = selected.filter(s => typeof data.find(d => d[keyField] === s) === 'undefined');
} }
if (onSelectAll) { state = { selected: (this.props.selectRow && this.props.selectRow.selected) || [] };
onSelectAll(!isUnSelect, dataOperator.getSelectedRows(data, keyField, currSelected), e);
componentWillReceiveProps(nextProps) {
if (nextProps.selectRow) {
this.setState(() => ({
selected: nextProps.selectRow.selected || this.state.selected
}));
}
} }
this.setState(() => ({ selected: currSelected })); // exposed API
getSelected() {
return this.state.selected;
}
handleRowSelect = (rowKey, checked, rowIndex, e) => {
const { data, keyField, selectRow: { mode, onSelect } } = this.props;
const { ROW_SELECT_SINGLE } = Const;
let currSelected = [...this.state.selected];
if (mode === ROW_SELECT_SINGLE) { // when select mode is radio
currSelected = [rowKey];
} else if (checked) { // when select mode is checkbox
currSelected.push(rowKey);
} else {
currSelected = currSelected.filter(value => value !== rowKey);
}
if (onSelect) {
const row = dataOperator.getRowByRowId(data, keyField, rowKey);
onSelect(row, checked, rowIndex, e);
}
this.setState(() => ({ selected: currSelected }));
}
handleAllRowsSelect = (e, isUnSelect) => {
const {
data,
keyField,
selectRow: {
onSelectAll,
nonSelectable
}
} = this.props;
const { selected } = this.state;
let currSelected;
if (!isUnSelect) {
currSelected = selected.concat(dataOperator.selectableKeys(data, keyField, nonSelectable));
} else {
currSelected = selected.filter(s => typeof data.find(d => d[keyField] === s) === 'undefined');
}
if (onSelectAll) {
onSelectAll(
!isUnSelect,
dataOperator.getSelectedRows(
data,
keyField,
isUnSelect ? this.state.selected : currSelected
),
e
);
}
this.setState(() => ({ selected: currSelected }));
}
render() {
return (
<SelectionContext.Provider
value={ {
selected: this.state.selected,
onRowSelect: this.handleRowSelect,
onAllRowsSelect: this.handleAllRowsSelect
} }
>
{ this.props.children }
</SelectionContext.Provider>
);
}
} }
return {
render() { Provider: SelectionProvider,
const { Consumer: SelectionContext.Consumer
allRowsSelected, };
allRowsNotSelected
} = getSelectionSummary(
this.props.data,
this.props.keyField,
this.state.selected
);
let checkedStatus;
// checkbox status depending on selected rows counts
if (allRowsSelected) checkedStatus = Const.CHECKBOX_STATUS_CHECKED;
else if (allRowsNotSelected) checkedStatus = Const.CHECKBOX_STATUS_UNCHECKED;
else checkedStatus = Const.CHECKBOX_STATUS_INDETERMINATE;
return (
<SelectionContext.Provider
value={ {
...this.props.selectRow,
selected: this.state.selected,
onRowSelect: this.handleRowSelect,
onAllRowsSelect: this.handleAllRowsSelect,
allRowsSelected,
allRowsNotSelected,
checkedStatus
} }
>
{ this.props.children }
</SelectionContext.Provider>
);
}
}
export default {
Provider: SelectionProvider,
Consumer: SelectionContext.Consumer
}; };

View File

@@ -49,6 +49,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) {

View File

@@ -1,14 +1,15 @@
/* eslint react/require-default-props: 0 */ /* eslint react/require-default-props: 0 */
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import Const from './const';
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 bindSelection from './row-selection/selection-header-cell-binder';
import bindExpansion from './row-expand/expand-header-cell-binder';
const Header = (props) => { const Header = (props) => {
const { ROW_SELECT_DISABLED } = Const;
const { const {
className, className,
columns, columns,
@@ -22,24 +23,20 @@ const Header = (props) => {
bootstrap4 bootstrap4
} = props; } = props;
let SelectionHeaderCellComp = () => null;
let ExpansionHeaderCellComp = () => null;
if (expandRow.showExpandColumn) {
ExpansionHeaderCellComp = bindExpansion(ExpandHeaderCell);
}
if (selectRow) {
SelectionHeaderCellComp = bindSelection(SelectionHeaderCell);
}
return ( return (
<thead> <thead>
<tr className={ className }> <tr className={ className }>
<ExpansionHeaderCellComp />
{ {
!selectRow.hideSelectColumn ? (expandRow && expandRow.showExpandColumn)
<SelectionHeaderCellComp /> : null ? <ExpandHeaderCell
onAllRowExpand={ expandRow.onAllRowExpand }
anyExpands={ expandRow.isAnyExpands }
renderer={ expandRow.expandHeaderColumnRenderer }
/> : null
}
{
(selectRow.mode !== ROW_SELECT_DISABLED && !selectRow.hideSelectColumn)
? <SelectionHeaderCell { ...selectRow } /> : null
} }
{ {
columns.map((column, i) => { columns.map((column, i) => {

View File

@@ -0,0 +1,17 @@
export default ExtendBase =>
class ExpandRowResolver extends ExtendBase {
resolveExpandRowProps() {
const { expandRow, expanded, onRowExpand, onAllRowExpand, isAnyExpands } = this.props;
if (expandRow) {
return {
...expandRow,
expanded,
onRowExpand,
onAllRowExpand,
isAnyExpands,
nonExpandable: expandRow.nonExpandable || []
};
}
return null;
}
};

View File

@@ -1,7 +1,11 @@
import ColumnResolver from './column-resolver'; import ColumnResolver from './column-resolver';
import ExpandRowResolver from './expand-row-resolver';
import Const from '../const';
import _ from '../utils';
export default ExtendBase => export default ExtendBase =>
class TableResolver extends ColumnResolver(ExtendBase) { class TableResolver extends
ExpandRowResolver(ColumnResolver(ExtendBase)) {
validateProps() { validateProps() {
const { keyField } = this.props; const { keyField } = this.props;
if (!keyField) { if (!keyField) {
@@ -15,4 +19,63 @@ export default ExtendBase =>
isEmpty() { isEmpty() {
return this.props.data.length === 0; return this.props.data.length === 0;
} }
/**
* props resolver for cell selection
* @param {Object} options - addtional options like callback which are about to merge into props
*
* @returns {Object} result - props for cell selections
* @returns {String} result.mode - input type of row selection or disabled.
*/
resolveSelectRowProps(options) {
const { selectRow } = this.props;
const { ROW_SELECT_DISABLED } = Const;
if (_.isDefined(selectRow)) {
return {
...selectRow,
...options
};
}
return {
mode: ROW_SELECT_DISABLED
};
}
/**
* props resolver for header cell selection
* @param {Object} options - addtional options like callback which are about to merge into props
*
* @returns {Object} result - props for cell selections
* @returns {String} result.mode - input type of row selection or disabled.
* @returns {String} result.checkedStatus - checkbox status depending on selected rows counts
*/
resolveSelectRowPropsForHeader(options = {}) {
const { selectRow } = this.props;
const { allRowsSelected, allRowsNotSelected, ...rest } = options;
const {
ROW_SELECT_DISABLED, CHECKBOX_STATUS_CHECKED,
CHECKBOX_STATUS_INDETERMINATE, CHECKBOX_STATUS_UNCHECKED
} = Const;
if (_.isDefined(selectRow)) {
let checkedStatus;
// checkbox status depending on selected rows counts
if (allRowsSelected) checkedStatus = CHECKBOX_STATUS_CHECKED;
else if (allRowsNotSelected) checkedStatus = CHECKBOX_STATUS_UNCHECKED;
else checkedStatus = CHECKBOX_STATUS_INDETERMINATE;
return {
...selectRow,
...rest,
checkedStatus
};
}
return {
mode: ROW_SELECT_DISABLED
};
}
}; };

View File

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

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

@@ -1,8 +1,12 @@
import _ from './utils';
import Const from './const';
const events = [ const events = [
'onClick', 'onClick',
'onDoubleClick', 'onDoubleClick',
'onMouseEnter', 'onMouseEnter',
'onMouseLeave' 'onMouseLeave',
'onContextMenu'
]; ];
export default ExtendBase => export default ExtendBase =>
@@ -11,6 +15,7 @@ export default ExtendBase =>
super(props); super(props);
this.clickNum = 0; this.clickNum = 0;
this.createDefaultEventHandler = this.createDefaultEventHandler.bind(this); this.createDefaultEventHandler = this.createDefaultEventHandler.bind(this);
this.createClickEventHandler = this.createClickEventHandler.bind(this);
} }
createDefaultEventHandler(cb) { createDefaultEventHandler(cb) {
@@ -20,11 +25,65 @@ export default ExtendBase =>
}; };
} }
createClickEventHandler(cb) {
return (e) => {
const {
row,
selected,
keyField,
selectable,
expandable,
rowIndex,
expanded,
expandRow,
selectRow,
cellEdit: {
mode,
DBCLICK_TO_CELL_EDIT,
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.mode !== Const.ROW_SELECT_DISABLED && selectable) {
selectRow.onRowSelect(key, !selected, rowIndex, e);
}
};
if (mode === DBCLICK_TO_CELL_EDIT && selectRow.clickToEdit) {
this.clickNum += 1;
_.debounce(() => {
if (this.clickNum === 1) {
clickFn();
}
this.clickNum = 0;
}, DELAY_FOR_DBCLICK)();
} else {
clickFn();
}
};
}
delegate(attrs = {}) { delegate(attrs = {}) {
const newAttrs = { ...attrs }; const newAttrs = {};
const { expandRow, selectRow } = this.props;
if (expandRow || (selectRow && selectRow.clickToSelect)) {
newAttrs.onClick = this.createClickEventHandler(attrs.onClick);
}
Object.keys(attrs).forEach((attr) => { Object.keys(attrs).forEach((attr) => {
if (events.includes(attr)) { if (!newAttrs[attr]) {
newAttrs[attr] = this.createDefaultEventHandler(attrs[attr]); if (events.includes(attr)) {
newAttrs[attr] = this.createDefaultEventHandler(attrs[attr]);
} else {
newAttrs[attr] = attrs[attr];
}
} }
}); });
return newAttrs; return newAttrs;

View File

@@ -1,8 +0,0 @@
import React from 'react';
import ExpansionContext from '../contexts/row-expand-context';
export default Component => () => (
<ExpansionContext.Consumer>
{ expandRow => <Component { ...expandRow } /> }
</ExpansionContext.Consumer>
);

View File

@@ -3,11 +3,11 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
export default class ExpansionHeaderCell extends Component { export default class SelectionHeaderCell extends Component {
static propTypes = { static propTypes = {
isAnyExpands: PropTypes.bool.isRequired, anyExpands: PropTypes.bool.isRequired,
onAllRowExpand: PropTypes.func.isRequired, onAllRowExpand: PropTypes.func.isRequired,
expandHeaderColumnRenderer: PropTypes.func renderer: PropTypes.func
} }
constructor() { constructor() {
@@ -16,13 +16,13 @@ export default class ExpansionHeaderCell extends Component {
} }
handleCheckBoxClick(e) { handleCheckBoxClick(e) {
const { isAnyExpands, onAllRowExpand } = this.props; const { anyExpands, onAllRowExpand } = this.props;
onAllRowExpand(e, !isAnyExpands); onAllRowExpand(e, !anyExpands);
} }
render() { render() {
const { isAnyExpands, expandHeaderColumnRenderer } = this.props; const { anyExpands, renderer } = this.props;
const attrs = { const attrs = {
onClick: this.handleCheckBoxClick onClick: this.handleCheckBoxClick
}; };
@@ -30,9 +30,9 @@ export default class ExpansionHeaderCell extends Component {
return ( return (
<th data-row-selection { ...attrs }> <th data-row-selection { ...attrs }>
{ {
expandHeaderColumnRenderer ? renderer ?
expandHeaderColumnRenderer({ isAnyExpands }) : renderer({ isAnyExpands: anyExpands }) :
(isAnyExpands ? '(-)' : '(+)') (anyExpands ? '(-)' : '(+)')
} }
</th> </th>
); );

View File

@@ -1,34 +0,0 @@
/* eslint react/prop-types: 0 */
import React from 'react';
import ExpandRow from './expand-row';
import ExpansionContext from '../contexts/row-expand-context';
export default (Component, visibleColumnSize) => {
const renderWithExpansion = (props, expandRow) => {
const key = props.value;
const expanded = expandRow.expanded.includes(key);
const expandable = !expandRow.nonExpandable || !expandRow.nonExpandable.includes(key);
return [
<Component
{ ...props }
key={ key }
expanded={ expanded }
expandable={ expandable }
expandRow={ { ...expandRow } }
/>,
expanded ? <ExpandRow
key={ `${key}-expanding` }
colSpan={ visibleColumnSize }
>
{ expandRow.renderer(props.row) }
</ExpandRow> : null
];
};
return props => (
<ExpansionContext.Consumer>
{ expandRow => renderWithExpansion(props, expandRow) }
</ExpansionContext.Consumer>
);
};

View File

@@ -1,113 +0,0 @@
/* eslint react/prop-types: 0 */
/* eslint react/no-array-index-key: 0 */
import React from 'react';
import _ from './utils';
import Cell from './cell';
export default class RowContent extends React.Component {
// shouldComponentUpdate(nextProps) {
// return this.shouldUpdatedByNormalProps(nextProps);
// }
shouldComponentUpdate(nextProps) {
if (typeof this.props.shouldUpdate !== 'undefined') {
if (nextProps.shouldUpdate === this.props.shouldUpdate) {
return false;
}
}
return true;
}
render() {
const {
row,
keyField,
columns,
rowIndex,
editable,
editingRowIdx,
editingColIdx,
onStart,
clickToEdit,
dbclickToEdit,
EditingCellComponent
} = this.props;
return columns.map((column, index) => {
if (!column.hidden) {
const { dataField } = column;
const content = _.get(row, dataField);
if (rowIndex === editingRowIdx && index === editingColIdx) {
return (
<EditingCellComponent
key={ `${content}-${index}-editing` }
row={ row }
rowIndex={ rowIndex }
column={ column }
columnIndex={ index }
/>
);
}
// render cell
let cellTitle;
let cellStyle = {};
const cellAttrs = {
..._.isFunction(column.attrs)
? column.attrs(content, row, rowIndex, index)
: column.attrs,
...column.events
};
const cellClasses = _.isFunction(column.classes)
? column.classes(content, row, rowIndex, index)
: column.classes;
if (column.style) {
cellStyle = _.isFunction(column.style)
? column.style(content, row, rowIndex, index)
: column.style;
cellStyle = Object.assign({}, cellStyle) || {};
}
if (column.title) {
cellTitle = _.isFunction(column.title)
? column.title(content, row, rowIndex, index)
: content;
cellAttrs.title = cellTitle;
}
if (column.align) {
cellStyle.textAlign =
_.isFunction(column.align)
? column.align(content, row, rowIndex, index)
: column.align;
}
if (cellClasses) cellAttrs.className = cellClasses;
if (!_.isEmptyObject(cellStyle)) cellAttrs.style = cellStyle;
let editableCell = _.isDefined(column.editable) ? column.editable : true;
if (column.dataField === keyField || !editable) editableCell = false;
if (_.isFunction(column.editable)) {
editableCell = column.editable(content, row, rowIndex, index);
}
return (
<Cell
key={ `${content}-${index}` }
row={ row }
editable={ editableCell }
rowIndex={ rowIndex }
columnIndex={ index }
column={ column }
onStart={ onStart }
clickToEdit={ clickToEdit }
dbclickToEdit={ dbclickToEdit }
{ ...cellAttrs }
/>
);
}
return false;
});
}
}

View File

@@ -1,62 +0,0 @@
/* eslint react/prop-types: 0 */
import React from 'react';
import cs from 'classnames';
import _ from '../utils';
import SelectionContext from '../contexts/selection-context';
export default (Component) => {
const renderWithSelection = (props, selectRow) => {
const key = props.value;
const selected = selectRow.selected.includes(key);
const selectable = !selectRow.nonSelectable || !selectRow.nonSelectable.includes(key);
let {
style,
className
} = props;
if (selected) {
const selectedStyle = _.isFunction(selectRow.style)
? selectRow.style(props.row, props.rowIndex)
: selectRow.style;
const selectedClasses = _.isFunction(selectRow.classes)
? selectRow.classes(props.row, props.rowIndex)
: selectRow.classes;
style = {
...style,
...selectedStyle
};
className = cs(className, selectedClasses) || undefined;
if (selectRow.bgColor) {
style = style || {};
style.backgroundColor = _.isFunction(selectRow.bgColor)
? selectRow.bgColor(props.row, props.rowIndex)
: selectRow.bgColor;
}
}
return (
<Component
{ ...props }
style={ style }
className={ className }
selectRow={ selectRow }
selected={ selected }
selectable={ selectable }
/>
);
};
function withSelectionConsumer(props) {
return (
<SelectionContext.Consumer>
{ selectRow => renderWithSelection(props, selectRow) }
</SelectionContext.Consumer>
);
}
withSelectionConsumer.displayName = 'WithSelectionConsumer';
return withSelectionConsumer;
};

View File

@@ -19,19 +19,15 @@ export default class SelectionCell extends Component {
selectionRenderer: PropTypes.func selectionRenderer: PropTypes.func
} }
constructor(props) { constructor() {
super(props); super();
this.handleClick = this.handleClick.bind(this); this.handleClick = this.handleClick.bind(this);
} }
shouldComponentUpdate(nextProps) { shouldComponentUpdate(nextProps) {
const shouldUpdate = const { selected } = this.props;
this.props.selected !== nextProps.selected ||
this.props.rowKey !== nextProps.rowKey ||
this.props.rowIndex !== nextProps.rowIndex ||
this.props.disabled !== nextProps.disabled;
return shouldUpdate; return nextProps.selected !== selected;
} }
handleClick(e) { handleClick(e) {

View File

@@ -1,8 +0,0 @@
import React from 'react';
import SelectionContext from '../contexts/selection-context';
export default Component => () => (
<SelectionContext.Consumer>
{ selectRow => <Component { ...selectRow } /> }
</SelectionContext.Consumer>
);

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

@@ -1,31 +0,0 @@
/* eslint react/prop-types: 0 */
import _ from './utils';
export default ExtendBase =>
class RowShouldUpdater extends ExtendBase {
shouldUpdateByWhenEditing(nextProps) {
return (
nextProps.editingRowIdx === nextProps.rowIndex ||
(this.props.editingRowIdx === nextProps.rowIndex &&
nextProps.editingRowIdx === null)
);
}
shouldUpdatedBySelfProps(nextProps) {
return (
this.props.className !== nextProps.className ||
!_.isEqual(this.props.style, nextProps.style) ||
!_.isEqual(this.props.attrs, nextProps.attrs)
);
}
shouldUpdatedByNormalProps(nextProps) {
const shouldUpdate =
this.props.rowIndex !== nextProps.rowIndex ||
this.props.editable !== nextProps.editable ||
this.props.columns.length !== nextProps.columns.length ||
!_.isEqual(this.props.row, nextProps.row);
return shouldUpdate;
}
};

View File

@@ -0,0 +1,183 @@
/* eslint react/prop-types: 0 */
/* eslint react/no-array-index-key: 0 */
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import _ from './utils';
import Cell from './cell';
import SelectionCell from './row-selection/selection-cell';
import ExpandCell from './row-expand/expand-cell';
import eventDelegater from './row-event-delegater';
import Const from './const';
class Row extends eventDelegater(Component) {
render() {
const {
row,
columns,
keyField,
rowIndex,
className,
style,
attrs,
cellEdit,
selected,
selectRow,
expanded,
expandRow,
selectable,
editable: editableRow
} = this.props;
const {
mode,
onStart,
EditingCell,
ridx: editingRowIdx,
cidx: editingColIdx,
CLICK_TO_CELL_EDIT,
DBCLICK_TO_CELL_EDIT,
...rest
} = cellEdit;
const key = _.get(row, keyField);
const { hideSelectColumn } = selectRow;
const { showExpandColumn } = expandRow || {};
const trAttrs = this.delegate(attrs);
return (
<tr style={ style } className={ className } { ...trAttrs }>
{
showExpandColumn ? (
<ExpandCell
{ ...expandRow }
rowKey={ key }
rowIndex={ rowIndex }
expanded={ expanded }
/>
) : null
}
{
(selectRow.mode !== Const.ROW_SELECT_DISABLED && !hideSelectColumn)
? (
<SelectionCell
{ ...selectRow }
rowKey={ key }
rowIndex={ rowIndex }
selected={ selected }
disabled={ !selectable }
/>
)
: null
}
{
columns.map((column, index) => {
if (!column.hidden) {
const { dataField } = column;
const content = _.get(row, dataField);
let editable = _.isDefined(column.editable) ? column.editable : true;
if (dataField === keyField || !editableRow) editable = false;
if (_.isFunction(column.editable)) {
editable = column.editable(content, row, rowIndex, index);
}
if (rowIndex === editingRowIdx && index === editingColIdx) {
let editCellstyle = column.editCellStyle || {};
let editCellclasses = column.editCellClasses;
if (_.isFunction(column.editCellStyle)) {
editCellstyle = column.editCellStyle(content, row, rowIndex, index);
}
if (_.isFunction(column.editCellClasses)) {
editCellclasses = column.editCellClasses(content, row, rowIndex, index);
}
return (
<EditingCell
key={ `${content}-${index}` }
row={ row }
rowIndex={ rowIndex }
column={ column }
columnIndex={ index }
className={ editCellclasses }
style={ editCellstyle }
{ ...rest }
/>
);
}
// render cell
let cellTitle;
let cellStyle = {};
const cellAttrs = {
..._.isFunction(column.attrs)
? column.attrs(content, row, rowIndex, index)
: column.attrs,
...column.events
};
const cellClasses = _.isFunction(column.classes)
? column.classes(content, row, rowIndex, index)
: column.classes;
if (column.style) {
cellStyle = _.isFunction(column.style)
? column.style(content, row, rowIndex, index)
: column.style;
cellStyle = Object.assign({}, cellStyle) || {};
}
if (column.title) {
cellTitle = _.isFunction(column.title)
? column.title(content, row, rowIndex, index)
: content;
cellAttrs.title = cellTitle;
}
if (column.align) {
cellStyle.textAlign =
_.isFunction(column.align)
? column.align(content, row, rowIndex, index)
: column.align;
}
if (cellClasses) cellAttrs.className = cellClasses;
if (!_.isEmptyObject(cellStyle)) cellAttrs.style = cellStyle;
return (
<Cell
key={ `${content}-${index}` }
row={ row }
rowIndex={ rowIndex }
columnIndex={ index }
column={ column }
onStart={ onStart }
editable={ editable }
clickToEdit={ mode === CLICK_TO_CELL_EDIT }
dbclickToEdit={ mode === DBCLICK_TO_CELL_EDIT }
{ ...cellAttrs }
/>
);
}
return false;
})
}
</tr>
);
}
}
Row.propTypes = {
row: PropTypes.object.isRequired,
rowIndex: PropTypes.number.isRequired,
columns: PropTypes.array.isRequired,
style: PropTypes.object,
className: PropTypes.string,
attrs: PropTypes.object
};
Row.defaultProps = {
editable: true,
style: {},
className: null,
attrs: {}
};
export default Row;

View File

@@ -1,56 +0,0 @@
/* 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';
class Row extends shouldRowUpdater(eventDelegater(Component)) {
constructor(props) {
super(props);
this.shouldUpdateRowContent = false;
}
shouldComponentUpdate(nextProps) {
this.shouldUpdateRowContent = this.shouldUpdatedByNormalProps(nextProps);
if (this.shouldUpdateRowContent) return true;
return this.shouldUpdatedBySelfProps(nextProps);
}
render() {
const {
className,
style,
attrs,
...rest
} = this.props;
const trAttrs = this.delegate(attrs);
return (
<tr style={ style } className={ className } { ...trAttrs }>
<RowContent shouldUpdate={ this.shouldUpdateRowContent } { ...rest } />
</tr>
);
}
}
Row.propTypes = {
row: PropTypes.object.isRequired,
rowIndex: PropTypes.number.isRequired,
columns: PropTypes.array.isRequired,
style: PropTypes.object,
className: PropTypes.string,
attrs: PropTypes.object
};
Row.defaultProps = {
editable: true,
style: {},
className: null,
attrs: {}
};
export default Row;

View File

@@ -1,15 +1,11 @@
import 'jsdom-global/register';
import React from 'react'; import React from 'react';
import sinon from 'sinon'; import sinon from 'sinon';
import { shallow, mount } from 'enzyme'; import { shallow } from 'enzyme';
import Body from '../src/body'; import Body from '../src/body';
import Row from '../src/row'; import Row from '../src/row';
import RowAggregator from '../src/row-aggregator';
import Const from '../src/const'; import Const from '../src/const';
import RowSection from '../src/row-section'; import RowSection from '../src/row-section';
import SelectionContext from '../src/contexts/selection-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';
describe('Body', () => { describe('Body', () => {
@@ -173,6 +169,92 @@ describe('Body', () => {
}); });
}); });
}); });
describe('when selectRow.style is defined', () => {
const selectedRowKey = data[0][keyField];
const selectedRowKeys = [selectedRowKey];
const selectedStyle = { backgroundColor: 'green', fontWeight: 'bold' };
const selectRow = { mode: 'radio', style: selectedStyle };
beforeEach(() => {
wrapper = shallow(
<Body
{ ...mockBodyResolvedProps }
keyField="id"
columns={ columns }
data={ data }
rowStyle={ rowStyle }
selectRow={ selectRow }
selectedRowKeys={ selectedRowKeys }
/>);
});
it('should rendering selected Row component with mixing selectRow.style correctly', () => {
const selectedRow = wrapper.find(Row).get(0);
expect(JSON.stringify(selectedRow.props.style)).toBe(JSON.stringify({
...rowStyle,
...selectedStyle
}));
});
describe('and selectRow.bgColor is also defined', () => {
beforeEach(() => {
selectRow.bgColor = 'gray';
wrapper = shallow(
<Body
{ ...mockBodyResolvedProps }
keyField="id"
columns={ columns }
data={ data }
rowStyle={ rowStyle }
selectRow={ selectRow }
selectedRowKeys={ selectedRowKeys }
/>);
});
it('should rendering selected Row component with mixing selectRow.style correctly', () => {
const selectedRow = wrapper.find(Row).get(0);
expect(JSON.stringify(selectedRow.props.style)).toBe(JSON.stringify({
...rowStyle,
...selectedStyle,
backgroundColor: selectRow.bgColor
}));
});
it('should render selected Row component with correct style.backgroundColor', () => {
const selectedRow = wrapper.find(Row).get(0);
expect(selectedRow.props.style.backgroundColor).toEqual(selectRow.bgColor);
});
});
});
describe('when selectRow.bgColor is defined', () => {
const selectedRowKey = data[0][keyField];
const selectedRowKeys = [selectedRowKey];
const selectRow = { mode: 'radio', bgColor: 'gray' };
beforeEach(() => {
selectRow.bgColor = 'gray';
wrapper = shallow(
<Body
{ ...mockBodyResolvedProps }
keyField="id"
columns={ columns }
data={ data }
rowStyle={ rowStyle }
selectRow={ selectRow }
selectedRowKeys={ selectedRowKeys }
/>);
});
it('should rendering selected Row component with correct style', () => {
const selectedRow = wrapper.find(Row).get(0);
expect(JSON.stringify(selectedRow.props.style)).toBe(JSON.stringify({
...rowStyle,
backgroundColor: selectRow.bgColor
}));
});
});
}); });
describe('when rowClasses prop is defined', () => { describe('when rowClasses prop is defined', () => {
@@ -228,6 +310,31 @@ describe('Body', () => {
}); });
}); });
}); });
describe('when selectRow.classes is defined', () => {
const selectedRowKey = data[0][keyField];
const selectedRowKeys = [selectedRowKey];
const selectedClasses = 'selected-classes';
const selectRow = { mode: 'radio', classes: selectedClasses };
beforeEach(() => {
wrapper = shallow(
<Body
{ ...mockBodyResolvedProps }
keyField="id"
columns={ columns }
data={ data }
rowClasses={ rowClasses }
selectRow={ selectRow }
selectedRowKeys={ selectedRowKeys }
/>);
});
it('should rendering selected Row component with mixing selectRow.classes correctly', () => {
const selectedRow = wrapper.find(Row).get(0);
expect(selectedRow.props.className).toBe(`${rowClasses} ${selectedClasses}`);
});
});
}); });
describe('when rowEvents prop is defined', () => { describe('when rowEvents prop is defined', () => {
@@ -254,15 +361,11 @@ describe('Body', () => {
}); });
}); });
describe('when cellEdit.createContext props is defined', () => { describe('when cellEdit.nonEditableRows props is defined', () => {
const CellComponent = () => null; const nonEditableRows = [data[1].id];
const EditingCellComponent = () => null;
const RowComponent = props => <Row { ...props } />;
const cellEdit = { const cellEdit = {
createContext: jest.fn(), mode: Const.CLICK_TO_CELL_EDIT,
bindCellLevelCellEdit: jest.fn().mockReturnValue(CellComponent), nonEditableRows
createEditingCell: jest.fn().mockReturnValue(EditingCellComponent),
bindRowLevelCellEdit: jest.fn().mockReturnValue(RowComponent)
}; };
beforeEach(() => { beforeEach(() => {
wrapper = shallow( wrapper = shallow(
@@ -276,19 +379,24 @@ describe('Body', () => {
); );
}); });
it('should render Row Component correctly', () => { it('should render Row component with correct editable prop', () => {
expect(wrapper.length).toBe(1); expect(wrapper.length).toBe(1);
expect(cellEdit.bindCellLevelCellEdit).toHaveBeenCalledTimes(1); const rows = wrapper.find(Row);
expect(cellEdit.createEditingCell).toHaveBeenCalledTimes(1); for (let i = 0; i < rows.length; i += 1) {
expect(cellEdit.bindRowLevelCellEdit).toHaveBeenCalledTimes(1); if (nonEditableRows.indexOf(rows.get(i).props.row[keyField]) > -1) {
expect(wrapper.find(RowComponent)).toHaveLength(2); expect(rows.get(i).props.editable).toBeFalsy();
const aRowElement = wrapper.find(RowComponent).get(0); } else {
expect(aRowElement.props.CellComponent).toBeDefined(); expect(rows.get(i).props.editable).toBeTruthy();
expect(aRowElement.props.EditingCellComponent).toBeDefined(); }
}
}); });
}); });
describe('when selectRow.mode is ROW_SELECT_DISABLED or expandRow.renderer is undefined', () => { describe('when selectRow.mode is checkbox or radio (row was selectable)', () => {
const selectRow = { mode: 'checkbox' };
const selectedRowKey = data[0][keyField];
const selectedRowKeys = [selectedRowKey];
beforeEach(() => { beforeEach(() => {
wrapper = shallow( wrapper = shallow(
<Body <Body
@@ -296,64 +404,234 @@ describe('Body', () => {
data={ data } data={ data }
columns={ columns } columns={ columns }
keyField={ keyField } keyField={ keyField }
selectedRowKeys={ selectedRowKeys }
selectRow={ selectRow }
/> />
); );
}); });
it('shouldn\'t render RowAggregator component', () => { it('should render Row component with correct selected prop', () => {
expect(wrapper.find(RowAggregator)).toHaveLength(0); const rows = wrapper.find(Row);
for (let i = 0; i < rows.length; i += 1) {
const row = rows.get(i);
expect(row.props.selected).toBe(selectedRowKeys.indexOf(row.props.row[keyField]) > -1);
}
}); });
});
describe('when selectRow.mode is defined correctly', () => { describe('if selectRow.style is defined as an object', () => {
const selectRow = { mode: 'checkbox' }; const style = { backgroundColor: 'red' };
beforeEach(() => { beforeEach(() => {
wrapper = mount( selectRow.style = style;
<SelectionContext.Provider data={ data } keyField={ keyField } selectRow={ selectRow }> wrapper = shallow(
<Body <Body
{ ...mockBodyResolvedProps } { ...mockBodyResolvedProps }
data={ data } data={ data }
columns={ columns } columns={ columns }
keyField={ keyField } keyField={ keyField }
selectedRowKeys={ selectedRowKeys }
selectRow={ selectRow } selectRow={ selectRow }
/> />
</SelectionContext.Provider> );
); });
it('should render Row component with correct style prop', () => {
expect(JSON.stringify(wrapper.find(Row).get(0).props.style)).toBe(JSON.stringify(style));
});
}); });
it('should render RowAggregator component correctly', () => { describe('if selectRow.style is defined as a function', () => {
const rowAggregator = wrapper.find(RowAggregator); const style = { backgroundColor: 'red' };
const styleCallBack = sinon.stub().returns(style);
expect(rowAggregator.get(0).props.selectRow.mode) beforeEach(() => {
.not.toEqual(Const.ROW_SELECT_DISABLED); selectRow.style = styleCallBack;
expect(rowAggregator.get(0).props.selected).toBeDefined(); wrapper = shallow(
expect(rowAggregator.get(0).props.selectable).toBeDefined();
});
});
describe('when expandRow.renderer is defined correctly', () => {
const expandRow = { renderer: jest.fn() };
beforeEach(() => {
wrapper = mount(
<ExpansionContext.Provider data={ data } keyField={ keyField } expandRow={ expandRow }>
<Body <Body
{ ...mockBodyResolvedProps } { ...mockBodyResolvedProps }
data={ data } data={ data }
columns={ columns } columns={ columns }
keyField={ keyField } keyField={ keyField }
expandRow={ expandRow } selectedRowKeys={ selectedRowKeys }
selectRow={ selectRow }
/> />
</ExpansionContext.Provider> );
});
it('should calling style callback correctly', () => {
expect(styleCallBack.callCount).toBe(1);
expect(styleCallBack.calledWith(data[0]), 1);
});
it('should render Row component with correct style prop', () => {
expect(JSON.stringify(wrapper.find(Row).get(0).props.style)).toBe(JSON.stringify(style));
});
});
describe('if selectRow.classes is defined as a string', () => {
const className = 'custom-class';
beforeEach(() => {
selectRow.classes = className;
wrapper = shallow(
<Body
{ ...mockBodyResolvedProps }
data={ data }
columns={ columns }
keyField={ keyField }
selectedRowKeys={ selectedRowKeys }
selectRow={ selectRow }
/>
);
});
it('should render Row component with correct className prop', () => {
expect(wrapper.find(Row).get(0).props.className).toEqual(className);
});
});
describe('if selectRow.classes is defined as a function', () => {
const className = 'custom-class';
const classesCallBack = sinon.stub().returns(className);
beforeEach(() => {
selectRow.classes = classesCallBack;
wrapper = shallow(
<Body
{ ...mockBodyResolvedProps }
data={ data }
columns={ columns }
keyField={ keyField }
selectedRowKeys={ selectedRowKeys }
selectRow={ selectRow }
/>
);
});
it('should calling style callback correctly', () => {
expect(classesCallBack.callCount).toBe(1);
expect(classesCallBack.calledWith(data[0]), 1);
});
it('should render Row component with correct style prop', () => {
expect(wrapper.find(Row).get(0).props.className).toEqual(className);
});
});
describe('if selectRow.bgColor is defined as a string', () => {
const bgColor = 'red';
beforeEach(() => {
selectRow.bgColor = bgColor;
wrapper = shallow(
<Body
{ ...mockBodyResolvedProps }
data={ data }
columns={ columns }
keyField={ keyField }
selectedRowKeys={ selectedRowKeys }
selectRow={ selectRow }
/>
);
});
it('should render Row component with correct style.backgroundColor prop', () => {
expect(wrapper.find(Row).get(0).props.style).toEqual({ backgroundColor: bgColor });
});
});
describe('if selectRow.bgColor is defined as a string', () => {
const bgColor = 'red';
const bgColorCallBack = sinon.stub().returns(bgColor);
beforeEach(() => {
selectRow.bgColor = bgColorCallBack;
wrapper = shallow(
<Body
{ ...mockBodyResolvedProps }
data={ data }
columns={ columns }
keyField={ keyField }
selectedRowKeys={ selectedRowKeys }
selectRow={ selectRow }
/>
);
});
it('should calling selectRow.bgColor callback correctly', () => {
expect(bgColorCallBack.calledOnce).toBeTruthy();
expect(bgColorCallBack.calledWith(data[0]), 1).toBeTruthy();
});
it('should render Row component with correct style.backgroundColor prop', () => {
expect(wrapper.find(Row).get(0).props.style).toEqual({ backgroundColor: bgColor });
});
});
describe('if selectRow.bgColor defined and selectRow.style.backgroundColor defined', () => {
const bgColor = 'yellow';
const style = { backgroundColor: 'red' };
beforeEach(() => {
selectRow.style = style;
selectRow.bgColor = bgColor;
wrapper = shallow(
<Body
{ ...mockBodyResolvedProps }
data={ data }
columns={ columns }
keyField={ keyField }
selectedRowKeys={ selectedRowKeys }
selectRow={ selectRow }
/>
);
});
it('should take selectRow.bgColor as higher priority', () => {
expect(wrapper.find(Row).get(0).props.style.backgroundColor).toBe(bgColor);
});
});
describe('if selectRow.nonSelectable is defined', () => {
const nonSelectableRowIndex = 1;
const nonSelectable = [data[nonSelectableRowIndex][keyField]];
beforeEach(() => {
selectRow.nonSelectable = nonSelectable;
wrapper = shallow(
<Body
{ ...mockBodyResolvedProps }
data={ data }
columns={ columns }
keyField={ keyField }
selectedRowKeys={ selectedRowKeys }
selectRow={ selectRow }
/>
);
});
it('should render Row component with correct selectable prop', () => {
expect(wrapper.find(Row).get(0).props.selectable).toBeTruthy();
expect(wrapper.find(Row).get(nonSelectableRowIndex).props.selectable).toBeFalsy();
});
});
});
describe('when selectRow.mode is ROW_SELECT_DISABLED (row was un-selectable)', () => {
beforeEach(() => {
wrapper = shallow(
<Body
{ ...mockBodyResolvedProps }
data={ data }
columns={ columns }
keyField={ keyField }
selectedRowKeys={ [] }
/>
); );
}); });
it('should render RowAggregator component correctly', () => { it('prop selected should be null', () => {
const rowAggregator = wrapper.find(RowAggregator); expect(wrapper.find(Row).get(0).props.selected).toBeNull();
expect(rowAggregator.get(0).props.expandRow.renderer).toEqual(expandRow.renderer);
expect(rowAggregator.get(0).props.expanded).toBeDefined();
expect(rowAggregator.get(0).props.expandable).toBeDefined();
}); });
}); });
}); });

View File

@@ -111,10 +111,7 @@ describe('Context', () => {
createContext: jest.fn().mockReturnValue({ createContext: jest.fn().mockReturnValue({
Provider: CellEditContext.Provider, Provider: CellEditContext.Provider,
Consumer: CellEditContext.Consumer Consumer: CellEditContext.Consumer
}), })
bindCellLevelCellEdit: jest.fn().mockReturnValue(() => null),
createEditingCell: jest.fn().mockReturnValue(() => null),
bindRowLevelCellEdit: jest.fn().mockReturnValue(() => null)
}; };
wrapper = shallow( wrapper = shallow(
<BootstrapTable <BootstrapTable

View File

@@ -4,7 +4,7 @@ import { shallow } from 'enzyme';
import dataOperator from '../../src/store/operators'; import dataOperator from '../../src/store/operators';
import BootstrapTable from '../../src/bootstrap-table'; import BootstrapTable from '../../src/bootstrap-table';
import SelectionContext from '../../src/contexts/selection-context'; import createSelectionContext from '../../src/contexts/selection-context';
describe('DataContext', () => { describe('DataContext', () => {
let wrapper; let wrapper;
@@ -42,6 +42,7 @@ describe('DataContext', () => {
const defaultSelectRow = { const defaultSelectRow = {
mode: 'checkbox' mode: 'checkbox'
}; };
const SelectionContext = createSelectionContext(dataOperator);
function shallowContext(selectRow = defaultSelectRow) { function shallowContext(selectRow = defaultSelectRow) {
return ( return (
@@ -80,13 +81,9 @@ describe('DataContext', () => {
it('should pass correct sort props to children element', () => { it('should pass correct sort props to children element', () => {
expect(wrapper.length).toBe(1); expect(wrapper.length).toBe(1);
expect(mockBase).toHaveBeenCalledWith({ expect(mockBase).toHaveBeenCalledWith({
...defaultSelectRow,
selected: wrapper.state().selected, selected: wrapper.state().selected,
onRowSelect: wrapper.instance().handleRowSelect, onRowSelect: wrapper.instance().handleRowSelect,
onAllRowsSelect: wrapper.instance().handleAllRowsSelect, onAllRowsSelect: wrapper.instance().handleAllRowsSelect
allRowsNotSelected: true,
allRowsSelected: false,
checkedStatus: 'unchecked'
}); });
}); });
}); });
@@ -223,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', () => {
@@ -237,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

@@ -1,12 +1,8 @@
import 'jsdom-global/register';
import React from 'react'; import React from 'react';
import { shallow, mount } from 'enzyme'; import { shallow } from 'enzyme';
import HeaderCell from '../src/header-cell'; import HeaderCell from '../src/header-cell';
import SelectionHeaderCell from '../src/row-selection/selection-header-cell'; import SelectionHeaderCell from '../src//row-selection/selection-header-cell';
import ExpandHeaderCell from '../src/row-expand/expand-header-cell';
import SelectionContext from '../src/contexts/selection-context';
import ExpansionContext from '../src/contexts/row-expand-context';
import Header from '../src/header'; import Header from '../src/header';
import Const from '../src/const'; import Const from '../src/const';
import mockHeaderResolvedProps from './test-helpers/mock/header-resolved-props'; import mockHeaderResolvedProps from './test-helpers/mock/header-resolved-props';
@@ -21,16 +17,6 @@ describe('Header', () => {
text: 'Name' text: 'Name'
}]; }];
const data = [{
id: 1,
name: 'A'
}, {
id: 2,
name: 'B'
}];
const keyField = 'id';
describe('simplest header', () => { describe('simplest header', () => {
beforeEach(() => { beforeEach(() => {
wrapper = shallow(<Header { ...mockHeaderResolvedProps } columns={ columns } />); wrapper = shallow(<Header { ...mockHeaderResolvedProps } columns={ columns } />);
@@ -103,18 +89,12 @@ describe('Header', () => {
describe('when selectRow.mode is radio (single selection)', () => { describe('when selectRow.mode is radio (single selection)', () => {
beforeEach(() => { beforeEach(() => {
const selectRow = { mode: 'radio' }; const selectRow = { mode: 'radio' };
wrapper = mount( wrapper = shallow(
<SelectionContext.Provider <Header
data={ data } { ...mockHeaderResolvedProps }
keyField={ keyField } columns={ columns }
selectRow={ selectRow } selectRow={ selectRow }
> />
<Header
{ ...mockHeaderResolvedProps }
columns={ columns }
selectRow={ selectRow }
/>
</SelectionContext.Provider>
); );
}); });
@@ -125,18 +105,12 @@ describe('Header', () => {
describe('when selectRow.hideSelectColumn is true', () => { describe('when selectRow.hideSelectColumn is true', () => {
beforeEach(() => { beforeEach(() => {
const selectRow = { mode: 'radio', hideSelectColumn: true }; const selectRow = { mode: 'radio', hideSelectColumn: true };
wrapper = mount( wrapper = shallow(
<SelectionContext.Provider <Header
data={ data } { ...mockHeaderResolvedProps }
keyField={ keyField } columns={ columns }
selectRow={ selectRow } selectRow={ selectRow }
> />
<Header
{ ...mockHeaderResolvedProps }
columns={ columns }
selectRow={ selectRow }
/>
</SelectionContext.Provider>
); );
}); });
@@ -172,18 +146,12 @@ describe('Header', () => {
describe('when selectRow.mode is checkbox (multiple selection)', () => { describe('when selectRow.mode is checkbox (multiple selection)', () => {
beforeEach(() => { beforeEach(() => {
const selectRow = { mode: 'checkbox' }; const selectRow = { mode: 'checkbox' };
wrapper = mount( wrapper = shallow(
<SelectionContext.Provider <Header
data={ data } { ...mockHeaderResolvedProps }
keyField={ keyField } columns={ columns }
selectRow={ selectRow } selectRow={ selectRow }
> />
<Header
{ ...mockHeaderResolvedProps }
columns={ columns }
selectRow={ selectRow }
/>
</SelectionContext.Provider>
); );
}); });
@@ -194,18 +162,12 @@ describe('Header', () => {
describe('when selectRow.hideSelectColumn is true', () => { describe('when selectRow.hideSelectColumn is true', () => {
beforeEach(() => { beforeEach(() => {
const selectRow = { mode: 'checkbox', hideSelectColumn: true }; const selectRow = { mode: 'checkbox', hideSelectColumn: true };
wrapper = mount( wrapper = shallow(
<SelectionContext.Provider <Header
data={ data } { ...mockHeaderResolvedProps }
keyField={ keyField } columns={ columns }
selectRow={ selectRow } selectRow={ selectRow }
> />
<Header
{ ...mockHeaderResolvedProps }
columns={ columns }
selectRow={ selectRow }
/>
</SelectionContext.Provider>
); );
}); });
@@ -215,44 +177,4 @@ describe('Header', () => {
}); });
}); });
}); });
describe('expandRow', () => {
describe('when expandRow.showExpandColumn is false', () => {
beforeEach(() => {
wrapper = shallow(
<Header
{ ...mockHeaderResolvedProps }
columns={ columns }
/>
);
});
it('should not render <ExpandHeaderCell />', () => {
expect(wrapper.find(ExpandHeaderCell).length).toBe(0);
});
});
describe('when expandRow.showExpandColumn is true', () => {
beforeEach(() => {
const expandRow = { renderer: jest.fn(), expanded: [], showExpandColumn: true };
wrapper = mount(
<ExpansionContext.Provider
data={ data }
keyField={ keyField }
expandRow={ expandRow }
>
<Header
{ ...mockHeaderResolvedProps }
columns={ columns }
expandRow={ expandRow }
/>
</ExpansionContext.Provider>
);
});
it('should render <ExpandHeaderCell /> correctly', () => {
expect(wrapper.find(ExpandHeaderCell).length).toBe(1);
});
});
});
}); });

View File

@@ -1,8 +1,10 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import sinon from 'sinon';
import { shallow } from 'enzyme'; import { shallow } from 'enzyme';
import { extendTo } from '../test-helpers/mock-component'; import { extendTo } from '../test-helpers/mock-component';
import baseResolver from '../../src/props-resolver/index'; import baseResolver from '../../src/props-resolver/index';
import Const from '../../src/const';
describe('TableResolver', () => { describe('TableResolver', () => {
const keyField = 'id'; const keyField = 'id';
@@ -69,4 +71,231 @@ describe('TableResolver', () => {
}); });
}); });
}); });
describe('resolveSelectRowProps', () => {
let cellSelectionInfo;
let selectRow;
describe('if selectRow was not defined', () => {
beforeEach(() => {
const mockElement = React.createElement(BootstrapTableMock, {
data, keyField, columns
}, null);
wrapper = shallow(mockElement);
cellSelectionInfo = wrapper.instance().resolveSelectRowProps();
});
it('should return object', () => {
expect(cellSelectionInfo).toBeDefined();
expect(cellSelectionInfo.constructor).toEqual(Object);
});
it('should contain mode in ROW_SELECT_DISABLED', () => {
expect(cellSelectionInfo.mode).toEqual(Const.ROW_SELECT_DISABLED);
});
});
describe('if selectRow was defined', () => {
describe('when mode was defined', () => {
it('should return object which contains ROW_SELECT_SINGLE if mode is radio', () => {
selectRow = { mode: 'radio' };
const mockElement = React.createElement(BootstrapTableMock, {
data, keyField, columns, selectRow
}, null);
wrapper = shallow(mockElement);
cellSelectionInfo = wrapper.instance().resolveSelectRowProps();
expect(cellSelectionInfo).toBeDefined();
expect(cellSelectionInfo.constructor).toEqual(Object);
expect(cellSelectionInfo.mode).toEqual(Const.ROW_SELECT_SINGLE);
});
it('should return object which contains ROW_SELECT_MULTIPLE if mode is checkbox', () => {
selectRow = { mode: 'checkbox' };
const mockElement = React.createElement(BootstrapTableMock, {
data, keyField, columns, selectRow
}, null);
wrapper = shallow(mockElement);
cellSelectionInfo = wrapper.instance().resolveSelectRowProps();
expect(cellSelectionInfo).toBeDefined();
expect(cellSelectionInfo.constructor).toEqual(Object);
expect(cellSelectionInfo.mode).toEqual(Const.ROW_SELECT_MULTIPLE);
});
});
describe('when options were given', () => {
beforeEach(() => {
selectRow = {};
const mockOptions = {
foo: 'test',
bar: sinon.stub()
};
const mockElement = React.createElement(BootstrapTableMock, {
data, keyField, columns, selectRow
}, null);
wrapper = shallow(mockElement);
cellSelectionInfo = wrapper.instance().resolveSelectRowProps(mockOptions);
});
it('should return object which contain options', () => {
expect(cellSelectionInfo).toEqual(expect.objectContaining({
foo: 'test',
bar: expect.any(Function)
}));
});
});
});
});
describe('resolveSelectRowPropsForHeader', () => {
let headerCellSelectionInfo;
let selectRow;
beforeEach(() => {
const mockElement = React.createElement(BootstrapTableMock, {
data, keyField, columns
}, null);
wrapper = shallow(mockElement);
headerCellSelectionInfo = wrapper.instance().resolveSelectRowPropsForHeader();
});
describe('if selectRow was not defined', () => {
it('should return object', () => {
expect(headerCellSelectionInfo).toBeDefined();
expect(headerCellSelectionInfo.constructor).toEqual(Object);
});
it('should contain mode in ROW_SELECT_DISABLED', () => {
expect(headerCellSelectionInfo.mode).toEqual(Const.ROW_SELECT_DISABLED);
});
});
describe('if selectRow was defined', () => {
describe('when mode was defined', () => {
it('should return object which contains ROW_SELECT_SINGLE if mode is radio', () => {
selectRow = { mode: 'radio' };
const selectedRowKeys = [];
const mockElement = React.createElement(BootstrapTableMock, {
data, keyField, columns, selectedRowKeys, selectRow
}, null);
wrapper = shallow(mockElement);
headerCellSelectionInfo = wrapper.instance().resolveSelectRowPropsForHeader();
expect(headerCellSelectionInfo).toBeDefined();
expect(headerCellSelectionInfo.constructor).toEqual(Object);
expect(headerCellSelectionInfo.mode).toEqual(Const.ROW_SELECT_SINGLE);
});
it('should return object which contains ROW_SELECT_MULTIPLE if mode is checkbox', () => {
selectRow = { mode: 'checkbox' };
const selectedRowKeys = [];
const mockElement = React.createElement(BootstrapTableMock, {
data, keyField, columns, selectedRowKeys, selectRow
}, null);
wrapper = shallow(mockElement);
headerCellSelectionInfo = wrapper.instance().resolveSelectRowPropsForHeader();
expect(headerCellSelectionInfo).toBeDefined();
expect(headerCellSelectionInfo.constructor).toEqual(Object);
expect(headerCellSelectionInfo.mode).toEqual(Const.ROW_SELECT_MULTIPLE);
});
});
describe('when options were given', () => {
beforeEach(() => {
selectRow = {};
const mockOptions = {
foo: 'test',
bar: sinon.stub(),
allRowsSelected: false,
selected: []
};
const selectedRowKeys = [];
const mockElement = React.createElement(BootstrapTableMock, {
data, keyField, columns, selectedRowKeys, selectRow
}, null);
wrapper = shallow(mockElement);
headerCellSelectionInfo = wrapper.instance().resolveSelectRowPropsForHeader(mockOptions);
});
it('should return object which contain specified options', () => {
expect(headerCellSelectionInfo).toEqual(expect.objectContaining({
foo: 'test',
bar: expect.any(Function)
}));
});
});
describe('if options.allRowsSelected is true', () => {
beforeEach(() => {
selectRow = {};
const selectedRowKeys = [1, 2];
const mockElement = React.createElement(BootstrapTableMock, {
data, keyField, columns, selectRow
}, null);
wrapper = shallow(mockElement);
headerCellSelectionInfo = wrapper.instance().resolveSelectRowPropsForHeader({
allRowsSelected: true,
selected: selectedRowKeys
});
});
it('should return checkedStatus which eqauls to checked', () => {
expect(headerCellSelectionInfo).toEqual(expect.objectContaining({
checkedStatus: Const.CHECKBOX_STATUS_CHECKED
}));
});
});
describe('if options.allRowsSelected and options.allRowsNotSelected both are false', () => {
beforeEach(() => {
selectRow = {};
const selectedRowKeys = [1];
const mockElement = React.createElement(BootstrapTableMock, {
data, keyField, columns, selectRow
}, null);
wrapper = shallow(mockElement);
headerCellSelectionInfo = wrapper.instance().resolveSelectRowPropsForHeader({
allRowsSelected: false,
allRowsNotSelected: false,
selected: selectedRowKeys
});
});
it('should return checkedStatus which eqauls to indeterminate', () => {
expect(headerCellSelectionInfo).toEqual(expect.objectContaining({
checkedStatus: Const.CHECKBOX_STATUS_INDETERMINATE
}));
});
});
describe('if options.allRowsNotSelected is true', () => {
beforeEach(() => {
selectRow = {};
const selectedRowKeys = [];
const mockElement = React.createElement(BootstrapTableMock, {
data, keyField, columns, selectRow
}, null);
wrapper = shallow(mockElement);
headerCellSelectionInfo = wrapper.instance().resolveSelectRowPropsForHeader({
allRowsSelected: false,
allRowsNotSelected: true,
selected: selectedRowKeys
});
});
it('should return checkedStatus which eqauls to unchecked', () => {
expect(headerCellSelectionInfo).toEqual(expect.objectContaining({
checkedStatus: Const.CHECKBOX_STATUS_UNCHECKED
}));
});
});
});
});
}); });

View File

@@ -1,296 +0,0 @@
import 'jsdom-global/register';
import React from 'react';
import { mount } from 'enzyme';
import mockBodyResolvedProps from './test-helpers/mock/body-resolved-props';
import SelectionContext from '../src/contexts/selection-context';
import ExpansionContext from '../src/contexts/row-expand-context';
import bindSelection from '../src/row-selection/row-binder';
import bindExpansion from '../src/row-expand/row-binder';
import ExpandCell from '../src/row-expand/expand-cell';
import SelectionCell from '../src/row-selection/selection-cell';
import RowAggregator from '../src/row-aggregator';
import Row from '../src/row';
describe('Row Aggregator', () => {
let wrapper;
let rowAggregator;
const RowAggregatorWithSelection = bindSelection(RowAggregator);
const RowAggregatorWithExpansion = bindExpansion(RowAggregator);
const data = [{
id: 1,
name: 'A'
}, {
id: 2,
name: 'B'
}, {
id: 3,
name: 'C'
}];
const columns = [{
dataField: 'id',
text: 'ID'
}, {
dataField: 'name',
text: 'Name'
}];
const rowIndex = 1;
const row = data[rowIndex];
const keyField = 'id';
const getBaseProps = () => ({
row,
value: row[keyField],
columns,
keyField,
rowIndex,
...mockBodyResolvedProps
});
describe('when selectRow is enable', () => {
describe('if props.selectRow.hideSelectColumn is false', () => {
beforeEach(() => {
const selectRow = { mode: 'radio' };
wrapper = mount(
<SelectionContext.Provider data={ data } keyField={ keyField } selectRow={ selectRow }>
<RowAggregatorWithSelection { ...getBaseProps() } />
</SelectionContext.Provider>
);
});
it('should render RowAggregator correctly', () => {
rowAggregator = wrapper.find(RowAggregator);
expect(rowAggregator).toHaveLength(1);
});
it('should render selection column correctly', () => {
const selectionCell = wrapper.find(SelectionCell);
expect(selectionCell).toHaveLength(1);
expect(selectionCell.props().selected).toEqual(rowAggregator.props().selected);
expect(selectionCell.props().disabled).toEqual(!rowAggregator.props().selectable);
});
});
describe('if props.selectRow.hideSelectColumn is true', () => {
beforeEach(() => {
const selectRow = { mode: 'radio', hideSelectColumn: true };
wrapper = mount(
<SelectionContext.Provider data={ data } keyField={ keyField } selectRow={ selectRow }>
<RowAggregatorWithSelection { ...getBaseProps() } />
</SelectionContext.Provider>
);
});
it('should render RowAggregator correctly', () => {
rowAggregator = wrapper.find(RowAggregator);
expect(rowAggregator).toHaveLength(1);
});
it('should not render selection column', () => {
const selectionCell = wrapper.find(SelectionCell);
expect(selectionCell).toHaveLength(0);
});
});
describe('if props.selectRow.clickToSelect is defined', () => {
beforeEach(() => {
const selectRow = { mode: 'radio', clickToSelect: true };
wrapper = mount(
<SelectionContext.Provider data={ data } keyField={ keyField } selectRow={ selectRow }>
<RowAggregatorWithSelection { ...getBaseProps() } />
</SelectionContext.Provider>
);
});
it('should render RowAggregator correctly', () => {
rowAggregator = wrapper.find(RowAggregator);
expect(rowAggregator).toHaveLength(1);
});
it('should add onClick prop to Row Component', () => {
const rowComp = wrapper.find(Row);
expect(rowComp).toHaveLength(1);
expect(rowComp.props().attrs.onClick).toBeDefined();
});
});
});
describe('when expandRow is enable', () => {
describe('if props.expandRow.showExpandColumn is false', () => {
beforeEach(() => {
const expandRow = { renderer: jest.fn() };
wrapper = mount(
<ExpansionContext.Provider data={ data } keyField={ keyField } expandRow={ expandRow }>
<RowAggregatorWithExpansion { ...getBaseProps() } />
</ExpansionContext.Provider>
);
});
it('should render RowAggregator correctly', () => {
rowAggregator = wrapper.find(RowAggregator);
expect(rowAggregator).toHaveLength(1);
});
it('should not render expansion column', () => {
const expandCell = wrapper.find(ExpandCell);
expect(expandCell).toHaveLength(0);
});
});
describe('if props.expandRow.showExpandColumn is true', () => {
beforeEach(() => {
const expandRow = { renderer: jest.fn(), showExpandColumn: true };
wrapper = mount(
<ExpansionContext.Provider data={ data } keyField={ keyField } expandRow={ expandRow }>
<RowAggregatorWithExpansion { ...getBaseProps() } />
</ExpansionContext.Provider>
);
});
it('should render RowAggregator correctly', () => {
rowAggregator = wrapper.find(RowAggregator);
expect(rowAggregator).toHaveLength(1);
});
it('should render expansion column correctly', () => {
const expandCell = wrapper.find(ExpandCell);
expect(expandCell).toHaveLength(1);
expect(expandCell.props().expanded).toEqual(rowAggregator.props().expanded);
});
});
});
describe('createClickEventHandler', () => {
describe('if props.attrs.onClick is defined', () => {
const attrs = { onClick: jest.fn() };
beforeEach(() => {
const selectRow = { mode: 'radio' };
wrapper = mount(
<SelectionContext.Provider data={ data } keyField={ keyField } selectRow={ selectRow }>
<RowAggregatorWithSelection { ...getBaseProps() } attrs={ attrs } />
</SelectionContext.Provider>
);
wrapper.find('tr').simulate('click');
});
it('should call attrs.onClick correctly', () => {
expect(attrs.onClick).toHaveBeenCalledTimes(1);
});
});
describe('if props.selectRow.clickToSelect is true', () => {
const selectRow = { mode: 'radio', clickToSelect: true };
beforeEach(() => {
wrapper = mount(
<SelectionContext.Provider data={ data } keyField={ keyField } selectRow={ selectRow }>
<RowAggregatorWithSelection { ...getBaseProps() } />
</SelectionContext.Provider>
);
wrapper.find(RowAggregator).props().selectRow.onRowSelect = jest.fn();
wrapper.find('tr').simulate('click');
});
it('should call selectRow.onRowSelect correctly', () => {
expect(wrapper.find(RowAggregator).props().selectRow.onRowSelect).toHaveBeenCalledTimes(1);
});
});
describe('if props.selectRow.clickToSelect is true', () => {
describe('but selectable props is false', () => {
const selectRow = { mode: 'radio', clickToSelect: true, nonSelectable: [row[keyField]] };
beforeEach(() => {
wrapper = mount(
<SelectionContext.Provider data={ data } keyField={ keyField } selectRow={ selectRow }>
<RowAggregatorWithSelection { ...getBaseProps() } />
</SelectionContext.Provider>
);
wrapper.find(RowAggregator).props().selectRow.onRowSelect = jest.fn();
wrapper.find('tr').simulate('click');
});
it('should call selectRow.onRowSelect correctly', () => {
expect(wrapper.find(RowAggregator).props().selectRow.onRowSelect)
.toHaveBeenCalledTimes(0);
});
});
});
describe('if props.expandRow.renderer is defined', () => {
describe('but expandable props is false', () => {
const expandRow = { renderer: jest.fn(), nonExpandable: [row[keyField]] };
beforeEach(() => {
wrapper = mount(
<ExpansionContext.Provider data={ data } keyField={ keyField } expandRow={ expandRow }>
<RowAggregatorWithExpansion { ...getBaseProps() } />
</ExpansionContext.Provider>
);
wrapper.find(RowAggregator).props().expandRow.onRowExpand = jest.fn();
wrapper.find('tr').simulate('click');
});
it('should call expandRow.onRowExpand correctly', () => {
expect(wrapper.find(RowAggregator).props().expandRow.onRowExpand)
.toHaveBeenCalledTimes(0);
});
});
});
describe('if props.expandRow.renderer is defined', () => {
const expandRow = { renderer: jest.fn() };
beforeEach(() => {
wrapper = mount(
<ExpansionContext.Provider data={ data } keyField={ keyField } expandRow={ expandRow }>
<RowAggregatorWithExpansion { ...getBaseProps() } />
</ExpansionContext.Provider>
);
wrapper.find(RowAggregator).props().expandRow.onRowExpand = jest.fn();
wrapper.find('tr').simulate('click');
});
it('should call expandRow.onRowExpand correctly', () => {
expect(wrapper.find(RowAggregator).props().expandRow.onRowExpand).toHaveBeenCalledTimes(1);
});
});
describe('if props.attrs.onClick and props.expandRow.renderer both are defined', () => {
const attrs = { onClick: jest.fn() };
const expandRow = { renderer: jest.fn() };
beforeEach(() => {
wrapper = mount(
<ExpansionContext.Provider data={ data } keyField={ keyField } expandRow={ expandRow }>
<RowAggregatorWithExpansion { ...getBaseProps() } attrs={ attrs } />
</ExpansionContext.Provider>
);
wrapper.find(RowAggregator).props().expandRow.onRowExpand = jest.fn();
wrapper.find('tr').simulate('click');
});
it('should call attrs.onClick and expandRow.onRowExpand correctly', () => {
expect(attrs.onClick).toHaveBeenCalledTimes(1);
expect(wrapper.find(RowAggregator).props().expandRow.onRowExpand).toHaveBeenCalledTimes(1);
});
});
describe('if props.attrs.onClick and props.selectRow.clickToSelect both are defined', () => {
const attrs = { onClick: jest.fn() };
const selectRow = { mode: 'radio', clickToSelect: true };
beforeEach(() => {
wrapper = mount(
<SelectionContext.Provider data={ data } keyField={ keyField } selectRow={ selectRow }>
<RowAggregatorWithSelection { ...getBaseProps() } attrs={ attrs } />
</SelectionContext.Provider>
);
wrapper.find(RowAggregator).props().selectRow.onRowSelect = jest.fn();
wrapper.find('tr').simulate('click');
});
it('should call attrs.onClick and selectRow.onRowSelect correctly', () => {
expect(attrs.onClick).toHaveBeenCalledTimes(1);
expect(wrapper.find(RowAggregator).props().selectRow.onRowSelect).toHaveBeenCalledTimes(1);
});
});
});
});

View File

@@ -1,414 +0,0 @@
import 'jsdom-global/register';
import React from 'react';
import { mount } from 'enzyme';
import SelectionContext from '../../src/contexts/selection-context';
import bindSelection from '../../src/row-selection/row-binder';
describe('Selection Row Binder', () => {
let wrapper;
let selectRow;
const BaseComponent = () => null;
const WithSelectionComponent = bindSelection(props => <BaseComponent { ...props } />);
const data = [{
id: 1,
name: 'A'
}, {
id: 2,
name: 'B'
}, {
id: 3,
name: 'C'
}];
const rowIndex = 1;
const row = data[rowIndex];
const keyField = 'id';
const value = row[keyField];
describe('if current row is selected', () => {
beforeEach(() => {
selectRow = { mode: 'checkbox', selected: [data[rowIndex][keyField]] };
wrapper = mount(
<SelectionContext.Provider data={ data } keyField={ keyField } selectRow={ selectRow }>
<WithSelectionComponent
row={ row }
value={ value }
keyField={ keyField }
rowIndex={ rowIndex }
/>
</SelectionContext.Provider>
);
});
it('should inject selected prop as true to target component', () => {
expect(wrapper.find(BaseComponent)).toHaveLength(1);
expect(wrapper.find(BaseComponent).prop('selected')).toBeTruthy();
});
});
describe('if current row is not selected', () => {
beforeEach(() => {
selectRow = { mode: 'checkbox', selected: [] };
wrapper = mount(
<SelectionContext.Provider data={ data } keyField={ keyField } selectRow={ selectRow }>
<WithSelectionComponent
row={ row }
value={ value }
keyField={ keyField }
rowIndex={ rowIndex }
/>
</SelectionContext.Provider>
);
});
it('should inject selected prop as false to target component', () => {
expect(wrapper.find(BaseComponent)).toHaveLength(1);
expect(wrapper.find(BaseComponent).prop('selected')).toBeFalsy();
});
});
describe('if current row is selectable', () => {
beforeEach(() => {
selectRow = { mode: 'checkbox', nonSelectable: [] };
wrapper = mount(
<SelectionContext.Provider data={ data } keyField={ keyField } selectRow={ selectRow }>
<WithSelectionComponent
row={ row }
value={ value }
keyField={ keyField }
rowIndex={ rowIndex }
/>
</SelectionContext.Provider>
);
});
it('should inject selectable prop as true to target component', () => {
expect(wrapper.find(BaseComponent)).toHaveLength(1);
expect(wrapper.find(BaseComponent).prop('selectable')).toBeTruthy();
});
});
describe('if current row is non selectable', () => {
beforeEach(() => {
selectRow = { mode: 'checkbox', nonSelectable: [data[rowIndex][keyField]] };
wrapper = mount(
<SelectionContext.Provider data={ data } keyField={ keyField } selectRow={ selectRow }>
<WithSelectionComponent
row={ row }
value={ value }
keyField={ keyField }
rowIndex={ rowIndex }
/>
</SelectionContext.Provider>
);
});
it('should inject selectable prop as false to target component', () => {
expect(wrapper.find(BaseComponent)).toHaveLength(1);
expect(wrapper.find(BaseComponent).prop('selectable')).toBeFalsy();
});
});
describe('if current row is selected', () => {
const selectedStyle = { backgroundColor: 'green', fontWeight: 'bold' };
describe('when selectRow.style is defined as an object', () => {
beforeEach(() => {
selectRow = { mode: 'checkbox', selected: [data[rowIndex][keyField]], style: selectedStyle };
wrapper = mount(
<SelectionContext.Provider data={ data } keyField={ keyField } selectRow={ selectRow }>
<WithSelectionComponent
row={ row }
value={ value }
keyField={ keyField }
rowIndex={ rowIndex }
/>
</SelectionContext.Provider>
);
});
it('should inject style prop correctly', () => {
expect(wrapper.find(BaseComponent)).toHaveLength(1);
expect(wrapper.find(BaseComponent).prop('style')).toEqual(selectedStyle);
});
describe('and props.style is also defined', () => {
const componentStype = { fontSize: '16px' };
beforeEach(() => {
wrapper = mount(
<SelectionContext.Provider data={ data } keyField={ keyField } selectRow={ selectRow }>
<WithSelectionComponent
row={ row }
value={ value }
keyField={ keyField }
rowIndex={ rowIndex }
style={ componentStype }
/>
</SelectionContext.Provider>
);
});
it('should inject style prop correctly', () => {
expect(wrapper.find(BaseComponent)).toHaveLength(1);
expect(wrapper.find(BaseComponent).prop('style')).toEqual({
...selectedStyle,
...componentStype
});
});
});
describe('and selectRow.bgColor is also defined as an object', () => {
beforeEach(() => {
selectRow.bgColor = 'gray';
wrapper = mount(
<SelectionContext.Provider data={ data } keyField={ keyField } selectRow={ selectRow }>
<WithSelectionComponent
row={ row }
value={ value }
keyField={ keyField }
rowIndex={ rowIndex }
/>
</SelectionContext.Provider>
);
});
it('should inject style prop with correct backgroundColor', () => {
expect(wrapper.find(BaseComponent)).toHaveLength(1);
expect(wrapper.find(BaseComponent).prop('style')).toEqual({
...selectedStyle,
backgroundColor: selectRow.bgColor
});
});
});
describe('and selectRow.bgColor is also defined as a function', () => {
const color = 'gray';
beforeEach(() => {
selectRow.bgColor = jest.fn().mockReturnValue(color);
wrapper = mount(
<SelectionContext.Provider data={ data } keyField={ keyField } selectRow={ selectRow }>
<WithSelectionComponent
row={ row }
value={ value }
keyField={ keyField }
rowIndex={ rowIndex }
/>
</SelectionContext.Provider>
);
});
it('should inject style prop with correct backgroundColor', () => {
expect(wrapper.find(BaseComponent)).toHaveLength(1);
expect(wrapper.find(BaseComponent).prop('style')).toEqual({
...selectedStyle,
backgroundColor: color
});
});
it('should call selectRow.bgColor function correctly', () => {
expect(selectRow.bgColor).toHaveBeenCalledTimes(1);
expect(selectRow.bgColor).toHaveBeenCalledWith(row, rowIndex);
});
});
});
describe('when selectRow.style is defined as a function', () => {
beforeEach(() => {
selectRow = { mode: 'checkbox', selected: [data[rowIndex][keyField]], style: jest.fn().mockReturnValue(selectedStyle) };
wrapper = mount(
<SelectionContext.Provider data={ data } keyField={ keyField } selectRow={ selectRow }>
<WithSelectionComponent
row={ row }
value={ value }
keyField={ keyField }
rowIndex={ rowIndex }
/>
</SelectionContext.Provider>
);
});
it('should inject style prop correctly', () => {
expect(wrapper.find(BaseComponent)).toHaveLength(1);
expect(wrapper.find(BaseComponent).prop('style')).toEqual(selectedStyle);
});
it('should call selectRow.style function correctly', () => {
expect(selectRow.style).toHaveBeenCalledTimes(1);
expect(selectRow.style).toHaveBeenCalledWith(row, rowIndex);
});
describe('and props.style is also defined', () => {
const componentStype = { fontSize: '16px' };
beforeEach(() => {
wrapper = mount(
<SelectionContext.Provider data={ data } keyField={ keyField } selectRow={ selectRow }>
<WithSelectionComponent
row={ row }
value={ value }
keyField={ keyField }
rowIndex={ rowIndex }
style={ componentStype }
/>
</SelectionContext.Provider>
);
});
it('should inject style prop correctly', () => {
expect(wrapper.find(BaseComponent)).toHaveLength(1);
expect(wrapper.find(BaseComponent).prop('style')).toEqual({
...selectedStyle,
...componentStype
});
});
});
describe('and selectRow.bgColor is also defined as an object', () => {
beforeEach(() => {
selectRow.bgColor = 'gray';
wrapper = mount(
<SelectionContext.Provider data={ data } keyField={ keyField } selectRow={ selectRow }>
<WithSelectionComponent
row={ row }
value={ value }
keyField={ keyField }
rowIndex={ rowIndex }
/>
</SelectionContext.Provider>
);
});
it('should inject style prop with correct backgroundColor', () => {
expect(wrapper.find(BaseComponent)).toHaveLength(1);
expect(wrapper.find(BaseComponent).prop('style')).toEqual({
...selectedStyle,
backgroundColor: selectRow.bgColor
});
});
});
describe('and selectRow.bgColor is also defined as a function', () => {
const color = 'gray';
beforeEach(() => {
selectRow.bgColor = jest.fn().mockReturnValue(color);
wrapper = mount(
<SelectionContext.Provider data={ data } keyField={ keyField } selectRow={ selectRow }>
<WithSelectionComponent
row={ row }
value={ value }
keyField={ keyField }
rowIndex={ rowIndex }
/>
</SelectionContext.Provider>
);
});
it('should inject style prop with correct backgroundColor', () => {
expect(wrapper.find(BaseComponent)).toHaveLength(1);
expect(wrapper.find(BaseComponent).prop('style')).toEqual({
...selectedStyle,
backgroundColor: color
});
});
it('should call selectRow.bgColor function correctly', () => {
expect(selectRow.bgColor).toHaveBeenCalledTimes(1);
expect(selectRow.bgColor).toHaveBeenCalledWith(row, rowIndex);
});
});
});
});
describe('if current row is selected', () => {
const selectedClassName = 'select-classname';
describe('when selectRow.style is defined as an object', () => {
beforeEach(() => {
selectRow = { mode: 'checkbox', selected: [data[rowIndex][keyField]], classes: selectedClassName };
wrapper = mount(
<SelectionContext.Provider data={ data } keyField={ keyField } selectRow={ selectRow }>
<WithSelectionComponent
row={ row }
value={ value }
keyField={ keyField }
rowIndex={ rowIndex }
/>
</SelectionContext.Provider>
);
});
it('should inject className prop correctly', () => {
expect(wrapper.find(BaseComponent)).toHaveLength(1);
expect(wrapper.find(BaseComponent).prop('className')).toEqual(selectedClassName);
});
describe('and props.className is also defined', () => {
const componentClassName = 'component-classname';
beforeEach(() => {
wrapper = mount(
<SelectionContext.Provider data={ data } keyField={ keyField } selectRow={ selectRow }>
<WithSelectionComponent
row={ row }
value={ value }
keyField={ keyField }
rowIndex={ rowIndex }
className={ componentClassName }
/>
</SelectionContext.Provider>
);
});
it('should inject style prop correctly', () => {
expect(wrapper.find(BaseComponent)).toHaveLength(1);
expect(wrapper.find(BaseComponent).prop('className')).toEqual(`${componentClassName} ${selectedClassName}`);
});
});
});
describe('when selectRow.style is defined as a function', () => {
beforeEach(() => {
selectRow = { mode: 'checkbox', selected: [data[rowIndex][keyField]], classes: jest.fn().mockReturnValue(selectedClassName) };
wrapper = mount(
<SelectionContext.Provider data={ data } keyField={ keyField } selectRow={ selectRow }>
<WithSelectionComponent
row={ row }
value={ value }
keyField={ keyField }
rowIndex={ rowIndex }
/>
</SelectionContext.Provider>
);
});
it('should inject className prop correctly', () => {
expect(wrapper.find(BaseComponent)).toHaveLength(1);
expect(wrapper.find(BaseComponent).prop('className')).toEqual(selectedClassName);
});
it('should call selectRow.classes function correctly', () => {
expect(selectRow.classes).toHaveBeenCalledTimes(1);
expect(selectRow.classes).toHaveBeenCalledWith(row, rowIndex);
});
describe('and props.className is also defined', () => {
const componentClassName = 'component-classname';
beforeEach(() => {
wrapper = mount(
<SelectionContext.Provider data={ data } keyField={ keyField } selectRow={ selectRow }>
<WithSelectionComponent
row={ row }
value={ value }
keyField={ keyField }
rowIndex={ rowIndex }
className={ componentClassName }
/>
</SelectionContext.Provider>
);
});
it('should inject style prop correctly', () => {
expect(wrapper.find(BaseComponent)).toHaveLength(1);
expect(wrapper.find(BaseComponent).prop('className')).toEqual(`${componentClassName} ${selectedClassName}`);
});
});
});
});
});

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;

View File

@@ -4,6 +4,8 @@ import { shallow } from 'enzyme';
import Cell from '../src/cell'; import Cell from '../src/cell';
import Row from '../src/row'; import Row from '../src/row';
import Const from '../src/const';
import SelectionCell from '../src//row-selection/selection-cell';
import mockBodyResolvedProps from './test-helpers/mock/body-resolved-props'; import mockBodyResolvedProps from './test-helpers/mock/body-resolved-props';
let defaultColumns = [{ let defaultColumns = [{
@@ -100,50 +102,395 @@ describe('Row', () => {
}); });
}); });
describe('when CellComponent prop is defined', () => { describe('when cellEdit prop is defined', () => {
const CellComponent = () => null; let columns;
let cellEdit;
beforeEach(() => { beforeEach(() => {
columns = defaultColumns;
cellEdit = {
mode: 'click',
CLICK_TO_CELL_EDIT: 'click',
DBCLICK_TO_CELL_EDIT: 'dbclick'
};
wrapper = shallow( wrapper = shallow(
<Row <Row
{ ...mockBodyResolvedProps } { ...mockBodyResolvedProps }
rowIndex={ rowIndex }
columns={ defaultColumns }
row={ row } row={ row }
CellComponent={ CellComponent }
/>);
});
it('should render CellComponent successfully', () => {
expect(wrapper.length).toBe(1);
expect(wrapper.find(CellComponent)).toHaveLength(defaultColumns.length);
});
});
describe('when editingRowIdx and editingColIdx prop is defined', () => {
const editingRowIdx = rowIndex;
const editingColIdx = 1;
const EditingCellComponent = () => null;
beforeEach(() => {
wrapper = shallow(
<Row
{ ...mockBodyResolvedProps }
rowIndex={ rowIndex } rowIndex={ rowIndex }
columns={ defaultColumns } columns={ columns }
row={ row } keyField={ keyField }
EditingCellComponent={ EditingCellComponent } cellEdit={ cellEdit }
editingRowIdx={ editingRowIdx } />
editingColIdx={ editingColIdx } );
/>);
}); });
it('should render EditingCell component correctly', () => { afterEach(() => {
const EditingCell = wrapper.find(EditingCellComponent); columns = undefined;
cellEdit = undefined;
});
it('Cell component should receive correct editable props', () => {
expect(wrapper.length).toBe(1); expect(wrapper.length).toBe(1);
expect(EditingCell).toHaveLength(1); for (let i = 0; i < columns.length; i += 1) {
expect(EditingCell.prop('row')).toEqual(row); const column = columns[i];
expect(EditingCell.prop('rowIndex')).toEqual(editingRowIdx); if (column.dataField === keyField) {
expect(EditingCell.prop('column')).toEqual(defaultColumns[editingColIdx]); expect(wrapper.find(Cell).get(i).props.editable).toBeFalsy();
expect(EditingCell.prop('columnIndex')).toEqual(editingColIdx); } else {
expect(wrapper.find(Cell).get(i).props.editable).toBeTruthy();
}
}
});
it('Cell component should receive correct clickToEdit props', () => {
expect(wrapper.length).toBe(1);
for (let i = 0; i < columns.length; i += 1) {
expect(wrapper.find(Cell).get(i).props.clickToEdit).toBeTruthy();
}
});
it('Cell component should receive correct dbclickToEdit props', () => {
expect(wrapper.length).toBe(1);
for (let i = 0; i < columns.length; i += 1) {
expect(wrapper.find(Cell).get(i).props.dbclickToEdit).toBeFalsy();
}
});
describe('when props.cellEdit.mode is dbclick', () => {
beforeEach(() => {
cellEdit.mode = cellEdit.DBCLICK_TO_CELL_EDIT;
wrapper = shallow(
<Row
{ ...mockBodyResolvedProps }
row={ row }
rowIndex={ rowIndex }
columns={ columns }
keyField={ keyField }
cellEdit={ cellEdit }
/>
);
});
it('Cell component should receive correct clickToEdit props', () => {
expect(wrapper.length).toBe(1);
for (let i = 0; i < columns.length; i += 1) {
expect(wrapper.find(Cell).get(i).props.clickToEdit).toBeFalsy();
}
});
it('Cell component should receive correct dbclickToEdit props', () => {
expect(wrapper.length).toBe(1);
for (let i = 0; i < columns.length; i += 1) {
expect(wrapper.find(Cell).get(i).props.dbclickToEdit).toBeTruthy();
}
});
});
describe('and column.editable defined false', () => {
const nonEditableColIndex = 1;
beforeEach(() => {
columns[nonEditableColIndex].editable = false;
wrapper = shallow(
<Row
{ ...mockBodyResolvedProps }
row={ row }
rowIndex={ rowIndex }
columns={ columns }
keyField={ keyField }
cellEdit={ cellEdit }
/>
);
});
it('Cell component should receive correct editable props', () => {
expect(wrapper.length).toBe(1);
for (let i = 0; i < columns.length; i += 1) {
const column = columns[i];
if (i === nonEditableColIndex || column.dataField === keyField) {
expect(wrapper.find(Cell).get(i).props.editable).toBeFalsy();
} else {
expect(wrapper.find(Cell).get(i).props.editable).toBeTruthy();
}
}
});
});
describe('and column.editable defined as function', () => {
const nonEditableColIndex = 1;
let editableCallBack;
afterEach(() => {
editableCallBack.reset();
});
describe('which return false', () => {
beforeEach(() => {
editableCallBack = sinon.stub().returns(false);
columns[nonEditableColIndex].editable = editableCallBack;
wrapper = shallow(
<Row
{ ...mockBodyResolvedProps }
row={ row }
rowIndex={ rowIndex }
columns={ columns }
keyField={ keyField }
cellEdit={ cellEdit }
/>
);
});
it('column.editable callback function should be called once', () => {
expect(editableCallBack.callCount).toBe(1);
});
it('Cell component should receive correct editable props', () => {
expect(wrapper.length).toBe(1);
for (let i = 0; i < columns.length; i += 1) {
const column = columns[i];
if (i === nonEditableColIndex || column.dataField === keyField) {
expect(wrapper.find(Cell).get(i).props.editable).toBeFalsy();
} else {
expect(wrapper.find(Cell).get(i).props.editable).toBeTruthy();
}
}
});
});
describe('which return true', () => {
beforeEach(() => {
editableCallBack = sinon.stub().returns(true);
columns[nonEditableColIndex].editable = editableCallBack;
wrapper = shallow(
<Row
{ ...mockBodyResolvedProps }
row={ row }
rowIndex={ rowIndex }
columns={ columns }
keyField={ keyField }
cellEdit={ cellEdit }
/>
);
});
it('column.editable callback function should be called once', () => {
expect(editableCallBack.callCount).toBe(1);
});
it('Cell component should receive correct editable props', () => {
expect(wrapper.length).toBe(1);
for (let i = 0; i < columns.length; i += 1) {
const column = columns[i];
if (column.dataField === keyField) {
expect(wrapper.find(Cell).get(i).props.editable).toBeFalsy();
} else {
expect(wrapper.find(Cell).get(i).props.editable).toBeTruthy();
}
}
});
});
});
// Means user defined cellEdit.nonEditableRows
// and some rows will be treated as noneditable by this rules
describe('when editable prop is false', () => {
beforeEach(() => {
wrapper = shallow(
<Row
{ ...mockBodyResolvedProps }
row={ row }
rowIndex={ rowIndex }
columns={ columns }
keyField={ keyField }
cellEdit={ cellEdit }
editable={ false }
/>
);
});
it('All the Cell components should be noneditable', () => {
expect(wrapper.length).toBe(1);
for (let i = 0; i < columns.length; i += 1) {
expect(wrapper.find(Cell).get(i).props.editable).toBeFalsy();
}
});
});
// Means a cell now is undering editing
describe('when cellEdit.ridx and cellEdit.cidx is defined', () => {
const EditingCell = () => null;
describe('and cellEdit.ridx is match to current row index', () => {
const editingColIndex = 1;
beforeEach(() => {
cellEdit.ridx = rowIndex;
cellEdit.cidx = editingColIndex;
cellEdit.onUpdate = sinon.stub();
cellEdit.onEscape = sinon.stub();
cellEdit.EditingCell = EditingCell;
wrapper = shallow(
<Row
{ ...mockBodyResolvedProps }
row={ row }
rowIndex={ rowIndex }
columns={ columns }
keyField={ keyField }
cellEdit={ cellEdit }
editable={ false }
/>
);
});
it('should render EditingCell correctly', () => {
const complexComponents = wrapper.find('tr').children().findWhere(
n => n.type().name === 'Cell' || n.type().name === 'EditingCell');
expect(wrapper.length).toBe(1);
expect(wrapper.find(EditingCell).length).toBe(1);
expect(complexComponents.at(editingColIndex).type()).toEqual(EditingCell);
});
describe('if column.editCellStyle defined as object', () => {
const definedStyleColIndex = editingColIndex;
beforeEach(() => {
columns[definedStyleColIndex].editCellStyle = { backgroundColor: 'red' };
wrapper = shallow(
<Row
{ ...mockBodyResolvedProps }
row={ row }
rowIndex={ rowIndex }
columns={ columns }
keyField={ keyField }
cellEdit={ cellEdit }
/>
);
});
it('should also rendering EditingCell with correct style object', () => {
expect(wrapper.find(EditingCell).length).toBe(1);
expect(wrapper.find(EditingCell).props().style)
.toEqual(columns[definedStyleColIndex].editCellStyle);
});
});
describe('if column.editCellStyle defined as function', () => {
const definedStyleColIndex = editingColIndex;
const customStyle = { backgroundColor: 'red' };
let editCellStyleCallBack;
beforeEach(() => {
editCellStyleCallBack = sinon.stub().returns(customStyle);
columns[definedStyleColIndex].editCellStyle = editCellStyleCallBack;
wrapper = shallow(
<Row
{ ...mockBodyResolvedProps }
row={ row }
rowIndex={ rowIndex }
columns={ columns }
keyField={ keyField }
cellEdit={ cellEdit }
/>
);
});
it('should calling custom column.editCellStyle callback correctly', () => {
expect(editCellStyleCallBack.callCount).toBe(1);
expect(
editCellStyleCallBack.calledWith(
row[columns[editingColIndex].dataField], row, rowIndex, editingColIndex)
).toBe(true);
});
it('should also rendering EditingCell with correct style object', () => {
expect(wrapper.find(EditingCell).length).toBe(1);
expect(wrapper.find(EditingCell).props().style).toEqual(customStyle);
});
});
describe('if column.editCellClasses defined as string', () => {
const definedStyleColIndex = editingColIndex;
beforeEach(() => {
columns[definedStyleColIndex].editCellClasses = 'custom-class';
wrapper = shallow(
<Row
{ ...mockBodyResolvedProps }
row={ row }
rowIndex={ rowIndex }
columns={ columns }
keyField={ keyField }
cellEdit={ cellEdit }
/>
);
});
it('should also rendering EditingCell with correct class', () => {
expect(wrapper.find(EditingCell).length).toBe(1);
expect(wrapper.find(EditingCell).props().className)
.toEqual(columns[definedStyleColIndex].editCellClasses);
});
});
describe('if column.editCellClasses defined as function', () => {
const definedStyleColIndex = editingColIndex;
const customClass = 'custom-class';
let editCellClassesCallBack;
beforeEach(() => {
editCellClassesCallBack = sinon.stub().returns(customClass);
columns[definedStyleColIndex].editCellClasses = editCellClassesCallBack;
wrapper = shallow(
<Row
{ ...mockBodyResolvedProps }
row={ row }
rowIndex={ rowIndex }
columns={ columns }
keyField={ keyField }
cellEdit={ cellEdit }
/>
);
});
it('should calling custom column.editCellStyle callback correctly', () => {
expect(editCellClassesCallBack.callCount).toBe(1);
expect(
editCellClassesCallBack.calledWith(
row[columns[editingColIndex].dataField], row, rowIndex, editingColIndex)
).toBe(true);
});
it('should also rendering EditingCell with correct class', () => {
expect(wrapper.find(EditingCell).length).toBe(1);
expect(wrapper.find(EditingCell).props().className).toEqual(customClass);
});
});
});
describe('and cellEdit.ridx is not match to current row index', () => {
const editingColIndex = 1;
beforeEach(() => {
cellEdit.ridx = 3;
cellEdit.cidx = editingColIndex;
cellEdit.onUpdate = sinon.stub();
cellEdit.onEscape = sinon.stub();
wrapper = shallow(
<Row
{ ...mockBodyResolvedProps }
row={ row }
rowIndex={ 1 }
columns={ columns }
keyField={ keyField }
cellEdit={ cellEdit }
editable={ false }
/>
);
});
it('should not render any EditingCell component', () => {
expect(wrapper.length).toBe(1);
expect(wrapper.find(EditingCell).length).toBe(0);
expect(wrapper.find(Cell).length).toBe(columns.length);
});
});
}); });
}); });
@@ -195,6 +542,348 @@ describe('Row', () => {
}); });
}); });
describe('selectRow', () => {
let selectRow;
describe('when selectRow.mode is ROW_SELECT_DISABLED (row is not able to select)', () => {
beforeEach(() => {
wrapper = shallow(
<Row
{ ...mockBodyResolvedProps }
rowIndex={ rowIndex }
columns={ defaultColumns }
row={ row }
/>
);
});
it('should not render <SelectionCell />', () => {
expect(wrapper.find(SelectionCell).length).toBe(0);
});
});
describe('when selectRow.mode was defined (single or multiple selection)', () => {
describe('if selectRow.mode is radio (single selection)', () => {
beforeEach(() => {
selectRow = { mode: 'radio' };
wrapper = shallow(
<Row
{ ...mockBodyResolvedProps }
rowIndex={ rowIndex }
columns={ defaultColumns }
row={ row }
selectRow={ selectRow }
selected
selectable
/>);
});
it('should render <SelectionCell />', () => {
expect(wrapper.find(SelectionCell).length).toBe(1);
});
it('should render <SelectionCell /> with correct props', () => {
expect(wrapper.find(SelectionCell).props().selected).toBeTruthy();
expect(wrapper.find(SelectionCell).props().disabled).toBeFalsy();
expect(wrapper.find(SelectionCell).props().mode).toEqual(selectRow.mode);
});
describe('when selectRow.hideSelectColumn is true', () => {
beforeEach(() => {
selectRow = { mode: 'radio', hideSelectColumn: true };
wrapper = shallow(
<Row
{ ...mockBodyResolvedProps }
rowIndex={ rowIndex }
columns={ defaultColumns }
row={ row }
selectRow={ selectRow }
/>);
});
it('should not render <SelectionCell />', () => {
expect(wrapper.find(SelectionCell).length).toBe(0);
});
});
});
describe('if selectRow.mode is checkbox (multiple selection)', () => {
beforeEach(() => {
selectRow = { mode: 'checkbox' };
wrapper = shallow(
<Row
{ ...mockBodyResolvedProps }
rowIndex={ rowIndex }
columns={ defaultColumns }
row={ row }
selectRow={ selectRow }
selected
selectable
/>);
});
it('should render <SelectionCell />', () => {
expect(wrapper.find(SelectionCell).length).toBe(1);
});
it('should render <SelectionCell /> with correct props', () => {
expect(wrapper.find(SelectionCell).props().selected).toBeTruthy();
expect(wrapper.find(SelectionCell).props().disabled).toBeFalsy();
expect(wrapper.find(SelectionCell).props().mode).toEqual(selectRow.mode);
});
describe('when selectRow.hideSelectColumn is true', () => {
beforeEach(() => {
selectRow = { mode: 'checkbox', hideSelectColumn: true };
wrapper = shallow(
<Row
{ ...mockBodyResolvedProps }
rowIndex={ rowIndex }
columns={ defaultColumns }
row={ row }
selectRow={ selectRow }
/>);
});
it('should not render <SelectionCell />', () => {
expect(wrapper.find(SelectionCell).length).toBe(0);
});
});
});
describe('if selectable prop is false', () => {
beforeEach(() => {
selectRow = { mode: 'checkbox' };
wrapper = shallow(
<Row
{ ...mockBodyResolvedProps }
rowIndex={ rowIndex }
columns={ defaultColumns }
row={ row }
keyField={ keyField }
selectRow={ selectRow }
selectable={ false }
/>);
});
it('should render SelectionCell component with correct disable prop correctly', () => {
expect(wrapper.find(SelectionCell).length).toBe(1);
expect(wrapper.find(SelectionCell).prop('disabled')).toBeTruthy();
});
});
describe('if selectable prop is true', () => {
beforeEach(() => {
selectRow = { mode: 'checkbox' };
wrapper = shallow(
<Row
{ ...mockBodyResolvedProps }
rowIndex={ rowIndex }
columns={ defaultColumns }
row={ row }
keyField={ keyField }
selectRow={ selectRow }
selectable
/>);
});
it('should render SelectionCell component with correct disable prop correctly', () => {
expect(wrapper.find(SelectionCell).length).toBe(1);
expect(wrapper.find(SelectionCell).prop('disabled')).toBeFalsy();
});
});
describe('if selectRow.clickToSelect is true', () => {
beforeEach(() => {
selectRow = { mode: 'checkbox' };
selectRow.clickToSelect = true;
wrapper = shallow(
<Row
{ ...mockBodyResolvedProps }
rowIndex={ rowIndex }
columns={ defaultColumns }
row={ row }
selectRow={ selectRow }
selected
selectable
/>);
});
it('should render Row component successfully with onClick event', () => {
expect(wrapper.length).toBe(1);
expect(wrapper.find('tr').prop('onClick')).toBeDefined();
});
});
});
});
describe('handleRowClick', () => {
let selectRow;
let onRowSelectCallBack;
describe('selectable prop is false', () => {
beforeEach(() => {
onRowSelectCallBack = sinon.stub();
selectRow = {
mode: 'checkbox',
clickToSelect: true,
onRowSelect: onRowSelectCallBack
};
wrapper = shallow(
<Row
{ ...mockBodyResolvedProps }
rowIndex={ rowIndex }
columns={ defaultColumns }
row={ row }
selectRow={ selectRow }
selected
selectable={ false }
/>);
wrapper.find('tr').simulate('click');
});
it('should not calling selectRow.onRowSelect callback', () => {
expect(onRowSelectCallBack.callCount).toEqual(0);
});
});
describe('selectable prop is true', () => {
describe('and selected prop is true', () => {
beforeEach(() => {
onRowSelectCallBack = sinon.stub();
selectRow = {
mode: 'checkbox',
clickToSelect: true,
onRowSelect: onRowSelectCallBack
};
wrapper = shallow(
<Row
{ ...mockBodyResolvedProps }
keyField={ keyField }
rowIndex={ rowIndex }
columns={ defaultColumns }
row={ row }
selectRow={ selectRow }
selected
selectable
/>);
wrapper.find('tr').simulate('click');
});
it('should calling selectRow.onRowSelect callback', () => {
expect(onRowSelectCallBack.callCount).toEqual(1);
});
it('should calling selectRow.onRowSelect with correct argument', () => {
expect(onRowSelectCallBack.calledWith(row[keyField], false, rowIndex)).toBeTruthy();
});
});
describe('and selected prop is false', () => {
beforeEach(() => {
onRowSelectCallBack = sinon.stub();
selectRow = {
mode: 'checkbox',
clickToSelect: true,
onRowSelect: onRowSelectCallBack
};
wrapper = shallow(
<Row
{ ...mockBodyResolvedProps }
keyField={ keyField }
rowIndex={ rowIndex }
columns={ defaultColumns }
row={ row }
selectRow={ selectRow }
selected={ false }
selectable
/>);
wrapper.find('tr').simulate('click');
});
it('should calling selectRow.onRowSelect callback', () => {
expect(onRowSelectCallBack.callCount).toEqual(1);
});
it('should calling selectRow.onRowSelect with correct argument', () => {
expect(onRowSelectCallBack.calledWith(row[keyField], true, rowIndex)).toBeTruthy();
});
});
});
describe('if cellEdit.mode is dbclick and selectRow.clickToEdit is true', () => {
beforeEach(() => {
onRowSelectCallBack = sinon.stub();
const cellEdit = {
mode: Const.DBCLICK_TO_CELL_EDIT,
ridx: undefined,
cidx: undefined,
onStart: sinon.stub()
};
selectRow = {
mode: 'checkbox',
clickToSelect: true,
clickToEdit: true,
onRowSelect: onRowSelectCallBack
};
wrapper = shallow(
<Row
{ ...mockBodyResolvedProps }
keyField={ keyField }
rowIndex={ rowIndex }
columns={ defaultColumns }
row={ row }
selectRow={ selectRow }
cellEdit={ cellEdit }
selected
selectable
/>);
// console.log(wrapper.instance());
const rowClick = wrapper.instance().createClickEventHandler();
rowClick();
rowClick();
});
it('should increase clickNum as 2', () => {
expect(wrapper.instance().clickNum).toEqual(2);
});
});
describe('when attrs.onClick prop is defined', () => {
const customClickCallBack = sinon.stub();
const attrs = { onClick: customClickCallBack };
beforeEach(() => {
onRowSelectCallBack = sinon.stub();
selectRow = {
mode: 'checkbox',
clickToSelect: true,
onRowSelect: onRowSelectCallBack
};
wrapper = shallow(
<Row
{ ...mockBodyResolvedProps }
rowIndex={ rowIndex }
columns={ defaultColumns }
row={ row }
selectRow={ selectRow }
attrs={ attrs }
selected
selectable
/>);
wrapper.find('tr').simulate('click');
});
it('should calling attrs.onClick callback', () => {
expect(customClickCallBack.callCount).toEqual(1);
});
it('should calling selectRow.onRowSelect callback', () => {
expect(onRowSelectCallBack.callCount).toEqual(1);
});
});
});
describe('when column.style prop is defined', () => { describe('when column.style prop is defined', () => {
let columns; let columns;
const columnIndex = 1; const columnIndex = 1;

View File

@@ -1,25 +1,16 @@
import Const from '../../../src/const'; import Const from '../../../src/const';
const { ROW_SELECT_DISABLED } = Const; const { ROW_SELECT_DISABLED, UNABLE_TO_CELL_EDIT } = Const;
export const rowSelectionResolvedProps = { export const rowSelectionResolvedProps = {
mode: ROW_SELECT_DISABLED, mode: ROW_SELECT_DISABLED
selected: [],
hideSelectColumn: true
};
export const expandRowResolvedProps = {
renderer: undefined,
expanded: []
}; };
export const cellEditResolvedProps = { export const cellEditResolvedProps = {
mode: null, mode: UNABLE_TO_CELL_EDIT
nonEditableRows: []
}; };
export default { export default {
cellEdit: cellEditResolvedProps, cellEdit: cellEditResolvedProps,
expandRow: expandRowResolvedProps,
selectRow: rowSelectionResolvedProps selectRow: rowSelectionResolvedProps
}; };

View File

@@ -3,17 +3,9 @@ import Const from '../../../src/const';
const { ROW_SELECT_DISABLED } = Const; const { ROW_SELECT_DISABLED } = Const;
export const rowSelectionResolvedProps = { export const rowSelectionResolvedProps = {
mode: ROW_SELECT_DISABLED, mode: ROW_SELECT_DISABLED
selected: [],
hideSelectColumn: true
};
export const expandRowResolvedProps = {
renderer: undefined,
expanded: []
}; };
export default { export default {
selectRow: rowSelectionResolvedProps, selectRow: rowSelectionResolvedProps
expandRow: expandRowResolvedProps
}; };

View File

@@ -332,14 +332,6 @@ array-unique@^0.3.2:
version "0.3.2" version "0.3.2"
resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
array.prototype.flat@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.1.tgz#812db8f02cad24d3fab65dd67eabe3b8903494a4"
dependencies:
define-properties "^1.1.2"
es-abstract "^1.10.0"
function-bind "^1.1.1"
arrify@^1.0.0, arrify@^1.0.1: arrify@^1.0.0, arrify@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
@@ -2700,26 +2692,24 @@ entities@^1.1.1, entities@~1.1.1:
version "1.1.1" version "1.1.1"
resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0"
enzyme-adapter-react-16.3@1.0.0: enzyme-adapter-react-16@1.1.1:
version "1.0.0" version "1.1.1"
resolved "https://registry.yarnpkg.com/enzyme-adapter-react-16.3/-/enzyme-adapter-react-16.3-1.0.0.tgz#d3992301aba46c8cceab21c1d201e85f01c93bfc" resolved "https://registry.yarnpkg.com/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.1.1.tgz#a8f4278b47e082fbca14f5bfb1ee50ee650717b4"
dependencies: dependencies:
enzyme-adapter-utils "^1.5.0" enzyme-adapter-utils "^1.3.0"
function.prototype.name "^1.1.0" lodash "^4.17.4"
object.assign "^4.1.0" object.assign "^4.0.4"
object.values "^1.0.4" object.values "^1.0.4"
prop-types "^15.6.2" prop-types "^15.6.0"
react-is "^16.4.1"
react-reconciler "^0.7.0" react-reconciler "^0.7.0"
react-test-renderer "~16.3.0-0" react-test-renderer "^16.0.0-0"
enzyme-adapter-utils@^1.5.0: enzyme-adapter-utils@^1.3.0:
version "1.5.0" version "1.4.0"
resolved "https://registry.yarnpkg.com/enzyme-adapter-utils/-/enzyme-adapter-utils-1.5.0.tgz#a020ab3ae79bb1c85e1d51f48f35e995e0eed810" resolved "https://registry.yarnpkg.com/enzyme-adapter-utils/-/enzyme-adapter-utils-1.4.0.tgz#c403b81e8eb9953658569e539780964bdc98de62"
dependencies: dependencies:
function.prototype.name "^1.1.0"
object.assign "^4.1.0" object.assign "^4.1.0"
prop-types "^15.6.2" prop-types "^15.6.0"
enzyme-to-json@3.3.4: enzyme-to-json@3.3.4:
version "3.3.4" version "3.3.4"
@@ -2727,21 +2717,20 @@ enzyme-to-json@3.3.4:
dependencies: dependencies:
lodash "^4.17.4" lodash "^4.17.4"
enzyme@3.4.0: enzyme@3.3.0:
version "3.4.0" version "3.3.0"
resolved "https://registry.yarnpkg.com/enzyme/-/enzyme-3.4.0.tgz#085c66fe647d8c9c4becd1fee3042c040cda88a6" resolved "https://registry.yarnpkg.com/enzyme/-/enzyme-3.3.0.tgz#0971abd167f2d4bf3f5bd508229e1c4b6dc50479"
dependencies: dependencies:
array.prototype.flat "^1.2.1"
cheerio "^1.0.0-rc.2" cheerio "^1.0.0-rc.2"
function.prototype.name "^1.1.0" function.prototype.name "^1.0.3"
has "^1.0.3" has "^1.0.1"
is-boolean-object "^1.0.0" is-boolean-object "^1.0.0"
is-callable "^1.1.4" is-callable "^1.1.3"
is-number-object "^1.0.3" is-number-object "^1.0.3"
is-string "^1.0.4" is-string "^1.0.4"
is-subset "^0.1.1" is-subset "^0.1.1"
lodash "^4.17.4" lodash "^4.17.4"
object-inspect "^1.6.0" object-inspect "^1.5.0"
object-is "^1.0.1" object-is "^1.0.1"
object.assign "^4.1.0" object.assign "^4.1.0"
object.entries "^1.0.4" object.entries "^1.0.4"
@@ -2761,16 +2750,6 @@ error-ex@^1.2.0, error-ex@^1.3.1:
dependencies: dependencies:
is-arrayish "^0.2.1" is-arrayish "^0.2.1"
es-abstract@^1.10.0:
version "1.12.0"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.12.0.tgz#9dbbdd27c6856f0001421ca18782d786bf8a6165"
dependencies:
es-to-primitive "^1.1.1"
function-bind "^1.1.1"
has "^1.0.1"
is-callable "^1.1.3"
is-regex "^1.0.4"
es-abstract@^1.6.1, es-abstract@^1.7.0: es-abstract@^1.6.1, es-abstract@^1.7.0:
version "1.10.0" version "1.10.0"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.10.0.tgz#1ecb36c197842a00d8ee4c2dfd8646bb97d60864" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.10.0.tgz#1ecb36c197842a00d8ee4c2dfd8646bb97d60864"
@@ -3520,7 +3499,7 @@ function-bind@^1.0.2, function-bind@^1.1.0, function-bind@^1.1.1:
version "1.1.1" version "1.1.1"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
function.prototype.name@^1.1.0: function.prototype.name@^1.0.3:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.0.tgz#8bd763cc0af860a859cc5d49384d74b932cd2327" resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.0.tgz#8bd763cc0af860a859cc5d49384d74b932cd2327"
dependencies: dependencies:
@@ -3994,12 +3973,6 @@ has@^1.0.1:
dependencies: dependencies:
function-bind "^1.0.2" function-bind "^1.0.2"
has@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
dependencies:
function-bind "^1.1.1"
hash-base@^2.0.0: hash-base@^2.0.0:
version "2.0.2" version "2.0.2"
resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-2.0.2.tgz#66ea1d856db4e8a5470cadf6fce23ae5244ef2e1" resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-2.0.2.tgz#66ea1d856db4e8a5470cadf6fce23ae5244ef2e1"
@@ -4350,10 +4323,6 @@ is-callable@^1.1.1, is-callable@^1.1.3:
version "1.1.3" version "1.1.3"
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.3.tgz#86eb75392805ddc33af71c92a0eedf74ee7604b2" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.3.tgz#86eb75392805ddc33af71c92a0eedf74ee7604b2"
is-callable@^1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75"
is-ci@^1.0.10: is-ci@^1.0.10:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.1.0.tgz#247e4162e7860cebbdaf30b774d6b0ac7dcfe7a5" resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.1.0.tgz#247e4162e7860cebbdaf30b774d6b0ac7dcfe7a5"
@@ -6033,7 +6002,7 @@ object-hash@^1.1.4:
version "1.2.0" version "1.2.0"
resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-1.2.0.tgz#e96af0e96981996a1d47f88ead8f74f1ebc4422b" resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-1.2.0.tgz#e96af0e96981996a1d47f88ead8f74f1ebc4422b"
object-inspect@^1.6.0: object-inspect@^1.5.0:
version "1.6.0" version "1.6.0"
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.6.0.tgz#c70b6cbf72f274aab4c34c0c82f5167bf82cf15b" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.6.0.tgz#c70b6cbf72f274aab4c34c0c82f5167bf82cf15b"
@@ -6792,13 +6761,6 @@ prop-types@^15.6.0:
loose-envify "^1.3.1" loose-envify "^1.3.1"
object-assign "^4.1.1" object-assign "^4.1.1"
prop-types@^15.6.2:
version "15.6.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102"
dependencies:
loose-envify "^1.3.1"
object-assign "^4.1.1"
proxy-addr@~2.0.2: proxy-addr@~2.0.2:
version "2.0.2" version "2.0.2"
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.2.tgz#6571504f47bb988ec8180253f85dd7e14952bdec" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.2.tgz#6571504f47bb988ec8180253f85dd7e14952bdec"
@@ -6967,10 +6929,6 @@ react-dom@16.3.2:
object-assign "^4.1.1" object-assign "^4.1.1"
prop-types "^15.6.0" prop-types "^15.6.0"
react-is@^16.3.2, react-is@^16.4.1:
version "16.4.2"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.4.2.tgz#84891b56c2b6d9efdee577cc83501dfc5ecead88"
react-reconciler@^0.7.0: react-reconciler@^0.7.0:
version "0.7.0" version "0.7.0"
resolved "https://registry.yarnpkg.com/react-reconciler/-/react-reconciler-0.7.0.tgz#9614894103e5f138deeeb5eabaf3ee80eb1d026d" resolved "https://registry.yarnpkg.com/react-reconciler/-/react-reconciler-0.7.0.tgz#9614894103e5f138deeeb5eabaf3ee80eb1d026d"
@@ -6987,14 +6945,13 @@ react-test-renderer@16.0.0:
fbjs "^0.8.16" fbjs "^0.8.16"
object-assign "^4.1.1" object-assign "^4.1.1"
react-test-renderer@~16.3.0-0: react-test-renderer@^16.0.0-0:
version "16.3.2" version "16.2.0"
resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.3.2.tgz#3d1ed74fda8db42521fdf03328e933312214749a" resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.2.0.tgz#bddf259a6b8fcd8555f012afc8eacc238872a211"
dependencies: dependencies:
fbjs "^0.8.16" fbjs "^0.8.16"
object-assign "^4.1.1" object-assign "^4.1.1"
prop-types "^15.6.0" prop-types "^15.6.0"
react-is "^16.3.2"
react@16.3.2: react@16.3.2:
version "16.3.2" version "16.3.2"