diff --git a/lib/DataSheet.js b/lib/DataSheet.js index aaf063f..c767f9d 100644 --- a/lib/DataSheet.js +++ b/lib/DataSheet.js @@ -628,9 +628,16 @@ var DataSheet = function (_PureComponent) { var isNowEditingSameCell = !isEmpty(this.state.editing) && this.state.editing.i === i && this.state.editing.j === j; var editing = isEmpty(this.state.editing) || this.state.editing.i !== i || this.state.editing.j !== j ? {} : this.state.editing; + var _getState8 = this.getState(), + start = _getState8.start; + + if (!e.shiftKey) { + start = { i: i, j: j }; + } + this._setState({ selecting: !isNowEditingSameCell, - start: e.shiftKey ? this.state.start : { i: i, j: j }, + start: start, end: { i: i, j: j }, editing: editing, forceEdit: !!isNowEditingSameCell @@ -702,9 +709,9 @@ var DataSheet = function (_PureComponent) { }, { key: 'isSelected', value: function isSelected(i, j) { - var _getState8 = this.getState(), - start = _getState8.start, - end = _getState8.end; + var _getState9 = this.getState(), + start = _getState9.start, + end = _getState9.end; var posX = j >= start.j && j <= end.j; var negX = j <= start.j && j >= end.j; @@ -846,4 +853,4 @@ DataSheet.defaultProps = { cellRenderer: _Cell2.default, valueViewer: _ValueViewer2.default, dataEditor: _DataEditor2.default -}; \ No newline at end of file +}; diff --git a/src/DataSheet.js b/src/DataSheet.js index 44c8a65..fcaf74d 100644 --- a/src/DataSheet.js +++ b/src/DataSheet.js @@ -543,9 +543,14 @@ export default class DataSheet extends PureComponent { ? {} : this.state.editing; + let { start } = this.getState(); + if (!e.shiftKey) { + start = { i, j }; + } + this._setState({ selecting: !isNowEditingSameCell, - start: e.shiftKey ? this.state.start : { i, j }, + start: start, end: { i, j }, editing: editing, forceEdit: !!isNowEditingSameCell, diff --git a/test/Datasheet.js b/test/Datasheet.js index cd0ab3a..9b72d2a 100644 --- a/test/Datasheet.js +++ b/test/Datasheet.js @@ -834,6 +834,73 @@ describe('Component', () => { expect(wrapper.state('selecting')).toEqual(false); }); + it('selects multiple field properly 2x2 (click and shift click)', () => { + expect(wrapper.find('td.cell.selected').length).toEqual(0); + wrapper.find('td').at(0).simulate('mouseDown'); + wrapper.find('td').at(0).simulate('mouseUp'); + wrapper.find('td').at(3).simulate('mouseDown', { + shiftKey: true, + }); + wrapper.find('td').at(3).simulate('mouseUp', { + shiftKey: true, + }); + expect(wrapper.find('td.cell.selected').length).toEqual(4); + expect( + wrapper.find('td.cell.selected span').nodes.map(n => n.innerHTML), + ).toEqual(['4', '2', '0', '5']); + + expect(wrapper.state('selecting')).toEqual(true); + expect(wrapper.state('editing')).toEqual({}); + expect(wrapper.state('start')).toEqual({ + i: 0, + j: 0, + }); + expect(wrapper.state('end')).toEqual({ + i: 1, + j: 1, + }); + }); + + it('selects multiple field properly 2x2 (click and shift click) and the selection is controlled', () => { + customWrapper = mount( + customWrapper.setProps({ selected })} + valueRenderer={cell => cell.data} + />, + ); + expect(customWrapper.find('td.cell.selected').length).toEqual(0); + customWrapper.find('td').at(0).simulate('mouseDown'); + customWrapper.find('td').at(0).simulate('mouseUp'); + customWrapper.find('td').at(3).simulate('mouseDown', { + shiftKey: true, + }); + customWrapper.find('td').at(3).simulate('mouseUp', { + shiftKey: true, + }); + expect(customWrapper.find('td.cell.selected').length).toEqual(4); + expect( + customWrapper + .find('td.cell.selected span') + .nodes.map(n => n.innerHTML), + ).toEqual(['4', '2', '0', '5']); + + expect(customWrapper.state('selecting')).toEqual(true); + expect(customWrapper.state('editing')).toEqual({}); + // Start and end are stored in props for a controlled component + expect(customWrapper.state('start')).toEqual({}); + expect(customWrapper.state('end')).toEqual({}); + expect(customWrapper.props().selected.start).toEqual({ + i: 0, + j: 0, + }); + expect(customWrapper.props().selected.end).toEqual({ + i: 1, + j: 1, + }); + }); + it('calls onSelect prop when a new element is selected', done => { customWrapper = mount(