@deephaven/grid 0.4.1-modules.0 → 0.5.2-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/dist/CellInputField.js +88 -40
  2. package/dist/CellInputField.js.map +1 -1
  3. package/dist/Grid.js +1484 -1449
  4. package/dist/Grid.js.map +1 -1
  5. package/dist/GridColorUtils.js +51 -18
  6. package/dist/GridColorUtils.js.map +1 -1
  7. package/dist/GridMetricCalculator.js +994 -1017
  8. package/dist/GridMetricCalculator.js.map +1 -1
  9. package/dist/GridModel.js +286 -171
  10. package/dist/GridModel.js.map +1 -1
  11. package/dist/GridMouseHandler.js +59 -39
  12. package/dist/GridMouseHandler.js.map +1 -1
  13. package/dist/GridRange.js +630 -572
  14. package/dist/GridRange.js.map +1 -1
  15. package/dist/GridRenderer.d.ts.map +1 -1
  16. package/dist/GridRenderer.js +1564 -1650
  17. package/dist/GridRenderer.js.map +1 -1
  18. package/dist/GridTestUtils.js +29 -15
  19. package/dist/GridTestUtils.js.map +1 -1
  20. package/dist/GridUtils.js +717 -679
  21. package/dist/GridUtils.js.map +1 -1
  22. package/dist/KeyHandler.js +18 -6
  23. package/dist/KeyHandler.js.map +1 -1
  24. package/dist/MockGridModel.js +210 -105
  25. package/dist/MockGridModel.js.map +1 -1
  26. package/dist/MockTreeGridModel.js +183 -113
  27. package/dist/MockTreeGridModel.js.map +1 -1
  28. package/dist/errors/PasteError.js +44 -5
  29. package/dist/errors/PasteError.js.map +1 -1
  30. package/dist/errors/index.js +1 -1
  31. package/dist/errors/index.js.map +1 -1
  32. package/dist/index.js +15 -15
  33. package/dist/index.js.map +1 -1
  34. package/dist/key-handlers/EditKeyHandler.js +75 -42
  35. package/dist/key-handlers/EditKeyHandler.js.map +1 -1
  36. package/dist/key-handlers/PasteKeyHandler.js +78 -42
  37. package/dist/key-handlers/PasteKeyHandler.js.map +1 -1
  38. package/dist/key-handlers/SelectionKeyHandler.js +234 -220
  39. package/dist/key-handlers/SelectionKeyHandler.js.map +1 -1
  40. package/dist/key-handlers/TreeKeyHandler.js +72 -42
  41. package/dist/key-handlers/TreeKeyHandler.js.map +1 -1
  42. package/dist/key-handlers/index.js +4 -4
  43. package/dist/key-handlers/index.js.map +1 -1
  44. package/dist/memoizeClear.js +1 -1
  45. package/dist/memoizeClear.js.map +1 -1
  46. package/dist/mouse-handlers/EditMouseHandler.js +50 -18
  47. package/dist/mouse-handlers/EditMouseHandler.js.map +1 -1
  48. package/dist/mouse-handlers/GridColumnMoveMouseHandler.js +163 -141
  49. package/dist/mouse-handlers/GridColumnMoveMouseHandler.js.map +1 -1
  50. package/dist/mouse-handlers/GridColumnSeparatorMouseHandler.js +86 -47
  51. package/dist/mouse-handlers/GridColumnSeparatorMouseHandler.js.map +1 -1
  52. package/dist/mouse-handlers/GridHorizontalScrollBarMouseHandler.d.ts.map +1 -1
  53. package/dist/mouse-handlers/GridHorizontalScrollBarMouseHandler.js +171 -143
  54. package/dist/mouse-handlers/GridHorizontalScrollBarMouseHandler.js.map +1 -1
  55. package/dist/mouse-handlers/GridRowMoveMouseHandler.js +147 -125
  56. package/dist/mouse-handlers/GridRowMoveMouseHandler.js.map +1 -1
  57. package/dist/mouse-handlers/GridRowSeparatorMouseHandler.js +86 -47
  58. package/dist/mouse-handlers/GridRowSeparatorMouseHandler.js.map +1 -1
  59. package/dist/mouse-handlers/GridRowTreeMouseHandler.js +76 -46
  60. package/dist/mouse-handlers/GridRowTreeMouseHandler.js.map +1 -1
  61. package/dist/mouse-handlers/GridScrollBarCornerMouseHandler.d.ts.map +1 -1
  62. package/dist/mouse-handlers/GridScrollBarCornerMouseHandler.js +62 -31
  63. package/dist/mouse-handlers/GridScrollBarCornerMouseHandler.js.map +1 -1
  64. package/dist/mouse-handlers/GridSelectionMouseHandler.js +222 -200
  65. package/dist/mouse-handlers/GridSelectionMouseHandler.js.map +1 -1
  66. package/dist/mouse-handlers/GridSeparatorMouseHandler.js +253 -206
  67. package/dist/mouse-handlers/GridSeparatorMouseHandler.js.map +1 -1
  68. package/dist/mouse-handlers/GridVerticalScrollBarMouseHandler.d.ts.map +1 -1
  69. package/dist/mouse-handlers/GridVerticalScrollBarMouseHandler.js +172 -144
  70. package/dist/mouse-handlers/GridVerticalScrollBarMouseHandler.js.map +1 -1
  71. package/dist/mouse-handlers/index.js +10 -10
  72. package/dist/mouse-handlers/index.js.map +1 -1
  73. package/dist/tsconfig.tsbuildinfo +1 -1
  74. package/package.json +4 -5
package/dist/Grid.js CHANGED
@@ -1,3 +1,5 @@
1
+ function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
2
+
1
3
  function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
2
4
 
3
5
  function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
@@ -6,6 +8,38 @@ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (O
6
8
 
7
9
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
8
10
 
11
+ function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
12
+
13
+ function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
14
+
15
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
16
+
17
+ function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter); }
18
+
19
+ function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
20
+
21
+ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
22
+
23
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
24
+
25
+ function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
26
+
27
+ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
28
+
29
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
30
+
31
+ function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
32
+
33
+ function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
34
+
35
+ function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
36
+
37
+ function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
38
+
39
+ function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
40
+
41
+ function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
42
+
9
43
  function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
10
44
 
11
45
  /* eslint react/no-did-update-set-state: "off" */
@@ -14,19 +48,19 @@ import classNames from 'classnames';
14
48
  import memoize from 'memoize-one';
15
49
  import PropTypes from 'prop-types';
16
50
  import clamp from 'lodash.clamp';
17
- import GridMetricCalculator from "./GridMetricCalculator.js";
18
- import GridModel from "./GridModel.js";
19
- import GridMouseHandler from "./GridMouseHandler.js";
20
- import GridTheme from "./GridTheme.js";
21
- import GridRange from "./GridRange.js";
22
- import GridRenderer from "./GridRenderer.js";
23
- import GridUtils from "./GridUtils.js";
24
- import { GridSelectionMouseHandler, GridColumnMoveMouseHandler, GridColumnSeparatorMouseHandler, GridHorizontalScrollBarMouseHandler, GridRowMoveMouseHandler, GridRowSeparatorMouseHandler, GridRowTreeMouseHandler, GridScrollBarCornerMouseHandler, GridVerticalScrollBarMouseHandler, EditMouseHandler } from "./mouse-handlers/index.js";
51
+ import GridMetricCalculator from './GridMetricCalculator';
52
+ import GridModel from './GridModel';
53
+ import GridMouseHandler from './GridMouseHandler';
54
+ import GridTheme from './GridTheme';
55
+ import GridRange from './GridRange';
56
+ import GridRenderer from './GridRenderer';
57
+ import GridUtils from './GridUtils';
58
+ import { GridSelectionMouseHandler, GridColumnMoveMouseHandler, GridColumnSeparatorMouseHandler, GridHorizontalScrollBarMouseHandler, GridRowMoveMouseHandler, GridRowSeparatorMouseHandler, GridRowTreeMouseHandler, GridScrollBarCornerMouseHandler, GridVerticalScrollBarMouseHandler, EditMouseHandler } from './mouse-handlers';
25
59
  import "./Grid.css";
26
- import KeyHandler from "./KeyHandler.js";
27
- import { EditKeyHandler, PasteKeyHandler, SelectionKeyHandler, TreeKeyHandler } from "./key-handlers/index.js";
28
- import CellInputField from "./CellInputField.js";
29
- import PasteError from "./errors/PasteError.js";
60
+ import KeyHandler from './KeyHandler';
61
+ import { EditKeyHandler, PasteKeyHandler, SelectionKeyHandler, TreeKeyHandler } from './key-handlers';
62
+ import CellInputField from './CellInputField';
63
+ import PasteError from './errors/PasteError';
30
64
  /**
31
65
  * High performance, extendible, themeable grid component.
32
66
  * Architectured to be fast and handle billions of rows/columns by default.
@@ -42,65 +76,67 @@ import PasteError from "./errors/PasteError.js";
42
76
  * Can also add onClick and onContextMenu handlers to add custom functionality and menus.
43
77
  */
44
78
 
45
- class Grid extends PureComponent {
46
- // use same constant as chrome source for windows
47
- // https://github.com/chromium/chromium/blob/973af9d461b6b5dc60208c8d3d66adc27e53da78/ui/events/blink/web_input_event_builders_win.cc#L285
48
- static getScale(context) {
49
- var devicePixelRatio = window.devicePixelRatio || 1;
50
- var backingStorePixelRatio = context.webkitBackingStorePixelRatio || context.mozBackingStorePixelRatio || context.msBackingStorePixelRatio || context.oBackingStorePixelRatio || context.backingStorePixelRatio || 1;
51
- return devicePixelRatio / backingStorePixelRatio;
52
- }
79
+ var Grid = /*#__PURE__*/function (_PureComponent) {
80
+ _inherits(Grid, _PureComponent);
53
81
 
54
- static getCursorClassName(cursor) {
55
- return cursor ? "grid-cursor-".concat(cursor) : null;
56
- }
82
+ var _super = _createSuper(Grid);
83
+
84
+ function Grid(props) {
85
+ var _this;
86
+
87
+ _classCallCheck(this, Grid);
88
+
89
+ _this = _super.call(this, props);
90
+
91
+ _defineProperty(_assertThisInitialized(_this), "getCachedKeyHandlers", memoize(function (keyHandlers) {
92
+ return [].concat(_toConsumableArray(keyHandlers), _toConsumableArray(_this.keyHandlers)).sort(function (a, b) {
93
+ return a.order - b.order;
94
+ });
95
+ }));
96
+
97
+ _defineProperty(_assertThisInitialized(_this), "getCachedMouseHandlers", memoize(function (mouseHandlers) {
98
+ return [].concat(_toConsumableArray(mouseHandlers), _toConsumableArray(_this.mouseHandlers)).sort(function (a, b) {
99
+ return a.order - b.order;
100
+ });
101
+ }));
57
102
 
58
- constructor(props) {
59
- super(props);
60
-
61
- _defineProperty(this, "getCachedKeyHandlers", memoize(keyHandlers => [...keyHandlers, ...this.keyHandlers].sort((a, b) => a.order - b.order)));
62
-
63
- _defineProperty(this, "getCachedMouseHandlers", memoize(mouseHandlers => [...mouseHandlers, ...this.mouseHandlers].sort((a, b) => a.order - b.order)));
64
-
65
- this.handleClick = this.handleClick.bind(this);
66
- this.handleContextMenu = this.handleContextMenu.bind(this);
67
- this.handleEditCellCancel = this.handleEditCellCancel.bind(this);
68
- this.handleEditCellChange = this.handleEditCellChange.bind(this);
69
- this.handleEditCellCommit = this.handleEditCellCommit.bind(this);
70
- this.handleDoubleClick = this.handleDoubleClick.bind(this);
71
- this.handleKeyDown = this.handleKeyDown.bind(this);
72
- this.handleMouseDown = this.handleMouseDown.bind(this);
73
- this.handleMouseDrag = this.handleMouseDrag.bind(this);
74
- this.handleMouseMove = this.handleMouseMove.bind(this);
75
- this.handleMouseLeave = this.handleMouseLeave.bind(this);
76
- this.handleMouseUp = this.handleMouseUp.bind(this);
77
- this.handleResize = this.handleResize.bind(this);
78
- this.handleWheel = this.handleWheel.bind(this);
79
- var {
80
- metricCalculator,
81
- movedColumns,
82
- movedRows,
83
- renderer
84
- } = props;
85
- this.renderer = renderer || new GridRenderer();
86
- this.metricCalculator = metricCalculator || new GridMetricCalculator();
87
- this.canvas = null;
88
- this.canvasContext = null;
89
- this.animationFrame = null;
90
- this.prevMetrics = null;
91
- this.metrics = null;
92
- this.isStuckToBottom = false;
93
- this.isStuckToRight = false; // Track the cursor that is currently added to the document
103
+ _this.handleClick = _this.handleClick.bind(_assertThisInitialized(_this));
104
+ _this.handleContextMenu = _this.handleContextMenu.bind(_assertThisInitialized(_this));
105
+ _this.handleEditCellCancel = _this.handleEditCellCancel.bind(_assertThisInitialized(_this));
106
+ _this.handleEditCellChange = _this.handleEditCellChange.bind(_assertThisInitialized(_this));
107
+ _this.handleEditCellCommit = _this.handleEditCellCommit.bind(_assertThisInitialized(_this));
108
+ _this.handleDoubleClick = _this.handleDoubleClick.bind(_assertThisInitialized(_this));
109
+ _this.handleKeyDown = _this.handleKeyDown.bind(_assertThisInitialized(_this));
110
+ _this.handleMouseDown = _this.handleMouseDown.bind(_assertThisInitialized(_this));
111
+ _this.handleMouseDrag = _this.handleMouseDrag.bind(_assertThisInitialized(_this));
112
+ _this.handleMouseMove = _this.handleMouseMove.bind(_assertThisInitialized(_this));
113
+ _this.handleMouseLeave = _this.handleMouseLeave.bind(_assertThisInitialized(_this));
114
+ _this.handleMouseUp = _this.handleMouseUp.bind(_assertThisInitialized(_this));
115
+ _this.handleResize = _this.handleResize.bind(_assertThisInitialized(_this));
116
+ _this.handleWheel = _this.handleWheel.bind(_assertThisInitialized(_this));
117
+ var metricCalculator = props.metricCalculator,
118
+ movedColumns = props.movedColumns,
119
+ movedRows = props.movedRows,
120
+ renderer = props.renderer;
121
+ _this.renderer = renderer || new GridRenderer();
122
+ _this.metricCalculator = metricCalculator || new GridMetricCalculator();
123
+ _this.canvas = null;
124
+ _this.canvasContext = null;
125
+ _this.animationFrame = null;
126
+ _this.prevMetrics = null;
127
+ _this.metrics = null;
128
+ _this.isStuckToBottom = false;
129
+ _this.isStuckToRight = false; // Track the cursor that is currently added to the document
94
130
  // Add to document so that when dragging the cursor stays, even if mouse leaves the canvas
95
131
  // Note: on document, not body so that cursor styling can be combined with
96
132
  // blocked pointer events that would otherwise prevent cursor styling from showing
97
133
 
98
- this.documentCursor = null;
99
- this.dragTimer = null; // specify handler ordering, such that any extensions can insert handlers in between
134
+ _this.documentCursor = null;
135
+ _this.dragTimer = null; // specify handler ordering, such that any extensions can insert handlers in between
100
136
 
101
- this.keyHandlers = [new EditKeyHandler(400), new PasteKeyHandler(450), new SelectionKeyHandler(500), new TreeKeyHandler(900)];
102
- this.mouseHandlers = [new GridRowSeparatorMouseHandler(100), new GridColumnSeparatorMouseHandler(200), new GridRowMoveMouseHandler(300), new GridColumnMoveMouseHandler(400), new EditMouseHandler(450), new GridVerticalScrollBarMouseHandler(500), new GridHorizontalScrollBarMouseHandler(600), new GridScrollBarCornerMouseHandler(700), new GridRowTreeMouseHandler(800), new GridSelectionMouseHandler(900)];
103
- this.state = {
137
+ _this.keyHandlers = [new EditKeyHandler(400), new PasteKeyHandler(450), new SelectionKeyHandler(500), new TreeKeyHandler(900)];
138
+ _this.mouseHandlers = [new GridRowSeparatorMouseHandler(100), new GridColumnSeparatorMouseHandler(200), new GridRowMoveMouseHandler(300), new GridColumnMoveMouseHandler(400), new EditMouseHandler(450), new GridVerticalScrollBarMouseHandler(500), new GridHorizontalScrollBarMouseHandler(600), new GridScrollBarCornerMouseHandler(700), new GridRowTreeMouseHandler(800), new GridSelectionMouseHandler(900)];
139
+ _this.state = {
104
140
  // Top/left visible cell in the grid. Note that it's visible row/column index, not the model index (ie. if columns are re-ordered)
105
141
  top: 0,
106
142
  left: 0,
@@ -125,8 +161,8 @@ class Grid extends PureComponent {
125
161
  mouseX: null,
126
162
  mouseY: null,
127
163
  // Move operations the user has performed on this grids columns/rows
128
- movedColumns,
129
- movedRows,
164
+ movedColumns: movedColumns,
165
+ movedRows: movedRows,
130
166
  // Cursor (highlighted cell) location and active selected range
131
167
  cursorRow: null,
132
168
  cursorColumn: null,
@@ -145,1553 +181,1552 @@ class Grid extends PureComponent {
145
181
  // The cell that is currently being edited
146
182
  editingCell: null
147
183
  };
184
+ return _this;
148
185
  }
149
186
 
150
- componentDidMount() {
151
- this.initContext(); // Need to explicitly add wheel event to canvas so we can preventDefault/avoid passive listener issue
152
- // Otherwise React attaches listener at doc level and you can't prevent default
153
- // https://github.com/facebook/react/issues/14856
154
-
155
- this.canvas.addEventListener('wheel', this.handleWheel, {
156
- passive: false
157
- });
158
- window.addEventListener('resize', this.handleResize);
159
- this.updateCanvasScale();
160
- this.updateCanvas();
161
- }
162
-
163
- componentDidUpdate(prevProps, prevState) {
164
- var {
165
- isStickyBottom,
166
- isStickyRight,
167
- movedColumns,
168
- movedRows,
169
- onMovedColumnsChanged,
170
- onMoveColumnComplete
171
- } = this.props;
172
- var {
173
- isStickyBottom: prevIsStickyBottom,
174
- isStickyRight: prevIsStickyRight,
175
- movedColumns: prevPropMovedColumns,
176
- movedRows: prevMovedRows
177
- } = prevProps;
178
- var {
179
- movedColumns: prevStateMovedColumns
180
- } = prevState;
181
- var {
182
- draggingColumn,
183
- movedColumns: currentStateMovedColumns
184
- } = this.state;
185
-
186
- if (prevPropMovedColumns !== movedColumns) {
187
- this.setState({
188
- movedColumns
189
- });
190
- }
187
+ _createClass(Grid, [{
188
+ key: "componentDidMount",
189
+ value: function componentDidMount() {
190
+ this.initContext(); // Need to explicitly add wheel event to canvas so we can preventDefault/avoid passive listener issue
191
+ // Otherwise React attaches listener at doc level and you can't prevent default
192
+ // https://github.com/facebook/react/issues/14856
191
193
 
192
- if (prevMovedRows !== movedRows) {
193
- this.setState({
194
- movedRows
194
+ this.canvas.addEventListener('wheel', this.handleWheel, {
195
+ passive: false
195
196
  });
197
+ window.addEventListener('resize', this.handleResize);
198
+ this.updateCanvasScale();
199
+ this.updateCanvas();
196
200
  }
197
-
198
- if (prevStateMovedColumns !== currentStateMovedColumns) {
199
- onMovedColumnsChanged(currentStateMovedColumns);
200
- }
201
-
202
- if (prevState.draggingColumn != null && draggingColumn == null) {
203
- onMoveColumnComplete(currentStateMovedColumns);
204
- }
205
-
206
- if (isStickyBottom !== prevIsStickyBottom) {
207
- this.isStuckToBottom = false;
208
- }
209
-
210
- if (isStickyRight !== prevIsStickyRight) {
211
- this.isStuckToRight = false;
212
- }
213
-
214
- this.updateMetrics();
215
- this.requestUpdateCanvas();
216
-
217
- if (!this.metrics || !this.prevMetrics) {
218
- return;
219
- }
220
-
221
- var {
222
- bottomVisible,
223
- rightVisible,
224
- rowCount,
225
- columnCount,
226
- top,
227
- left,
228
- height,
229
- width
230
- } = this.metrics;
231
- var {
232
- rowCount: prevRowCount,
233
- columnCount: prevColumnCount,
234
- height: prevHeight,
235
- width: prevWidth
236
- } = this.prevMetrics;
237
- var metricState = this.getMetricState();
238
-
239
- if (prevRowCount !== rowCount || height !== prevHeight) {
240
- var lastTop = this.metricCalculator.getLastTop(metricState);
241
-
242
- if (this.isStuckToBottom && bottomVisible < rowCount - 1 && bottomVisible > 0 && top > 0 || top > lastTop) {
201
+ }, {
202
+ key: "componentDidUpdate",
203
+ value: function componentDidUpdate(prevProps, prevState) {
204
+ var _this$props = this.props,
205
+ isStickyBottom = _this$props.isStickyBottom,
206
+ isStickyRight = _this$props.isStickyRight,
207
+ movedColumns = _this$props.movedColumns,
208
+ movedRows = _this$props.movedRows,
209
+ onMovedColumnsChanged = _this$props.onMovedColumnsChanged,
210
+ onMoveColumnComplete = _this$props.onMoveColumnComplete;
211
+ var prevIsStickyBottom = prevProps.isStickyBottom,
212
+ prevIsStickyRight = prevProps.isStickyRight,
213
+ prevPropMovedColumns = prevProps.movedColumns,
214
+ prevMovedRows = prevProps.movedRows;
215
+ var prevStateMovedColumns = prevState.movedColumns;
216
+ var _this$state = this.state,
217
+ draggingColumn = _this$state.draggingColumn,
218
+ currentStateMovedColumns = _this$state.movedColumns;
219
+
220
+ if (prevPropMovedColumns !== movedColumns) {
243
221
  this.setState({
244
- top: lastTop
222
+ movedColumns: movedColumns
245
223
  });
246
224
  }
247
- }
248
225
 
249
- if (prevColumnCount !== columnCount || width !== prevWidth) {
250
- var lastLeft = this.metricCalculator.getLastLeft(metricState);
251
-
252
- if (this.isStuckToRight && rightVisible < columnCount - 1 && rightVisible > 0 && left > 0 || left > lastLeft) {
226
+ if (prevMovedRows !== movedRows) {
253
227
  this.setState({
254
- left: lastLeft
228
+ movedRows: movedRows
255
229
  });
256
230
  }
257
- }
258
-
259
- if (this.validateSelection()) {
260
- this.checkSelectionChange(prevState);
261
- }
262
- }
263
-
264
- componentWillUnmount() {
265
- if (this.animationFrame != null) {
266
- cancelAnimationFrame(this.animationFrame);
267
- }
268
-
269
- this.canvas.removeEventListener('wheel', this.handleWheel, {
270
- passive: false
271
- });
272
- window.removeEventListener('mousemove', this.handleMouseDrag, true);
273
- window.removeEventListener('mouseup', this.handleMouseUp, true);
274
- window.removeEventListener('resize', this.handleResize);
275
- this.stopDragTimer();
276
- }
277
231
 
278
- getTheme() {
279
- var {
280
- theme
281
- } = this.props;
282
- return Grid.getTheme(theme);
283
- }
284
-
285
- getGridPointFromEvent(event) {
286
- var rect = this.canvas.getBoundingClientRect();
287
- var x = event.clientX - rect.left;
288
- var y = event.clientY - rect.top;
289
- return this.getGridPointFromXY(x, y);
290
- }
232
+ if (prevStateMovedColumns !== currentStateMovedColumns) {
233
+ onMovedColumnsChanged(currentStateMovedColumns);
234
+ }
291
235
 
292
- getGridPointFromXY(x, y) {
293
- return GridUtils.getGridPointFromXY(x, y, this.metrics);
294
- }
236
+ if (prevState.draggingColumn != null && draggingColumn == null) {
237
+ onMoveColumnComplete(currentStateMovedColumns);
238
+ }
295
239
 
296
- getMetricState() {
297
- var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.state;
298
- var theme = this.getTheme();
299
- var {
300
- model,
301
- stateOverride
302
- } = this.props;
303
- var context = this.canvasContext;
304
- var width = this.canvas.clientWidth;
305
- var height = this.canvas.clientHeight;
306
- var {
307
- left,
308
- top,
309
- leftOffset,
310
- topOffset,
311
- movedColumns,
312
- movedRows,
313
- isDraggingHorizontalScrollBar,
314
- isDraggingVerticalScrollBar
315
- } = state;
316
- return _objectSpread({
317
- left,
318
- top,
319
- leftOffset,
320
- topOffset,
321
- width,
322
- height,
323
- context,
324
- theme,
325
- model,
326
- movedColumns,
327
- movedRows,
328
- isDraggingHorizontalScrollBar,
329
- isDraggingVerticalScrollBar
330
- }, stateOverride);
331
- }
240
+ if (isStickyBottom !== prevIsStickyBottom) {
241
+ this.isStuckToBottom = false;
242
+ }
332
243
 
333
- getKeyHandlers() {
334
- var {
335
- keyHandlers
336
- } = this.props;
337
- return this.getCachedKeyHandlers(keyHandlers);
338
- }
244
+ if (isStickyRight !== prevIsStickyRight) {
245
+ this.isStuckToRight = false;
246
+ }
339
247
 
340
- getMouseHandlers() {
341
- var {
342
- mouseHandlers
343
- } = this.props;
344
- return this.getCachedMouseHandlers(mouseHandlers);
345
- }
248
+ this.updateMetrics();
249
+ this.requestUpdateCanvas();
346
250
 
347
- getModelColumn(columnIndex) {
348
- var _this$metrics, _this$metrics$modelCo;
251
+ if (!this.metrics || !this.prevMetrics) {
252
+ return;
253
+ }
349
254
 
350
- return (_this$metrics = this.metrics) === null || _this$metrics === void 0 ? void 0 : (_this$metrics$modelCo = _this$metrics.modelColumns) === null || _this$metrics$modelCo === void 0 ? void 0 : _this$metrics$modelCo.get(columnIndex);
351
- }
255
+ var _this$metrics = this.metrics,
256
+ bottomVisible = _this$metrics.bottomVisible,
257
+ rightVisible = _this$metrics.rightVisible,
258
+ rowCount = _this$metrics.rowCount,
259
+ columnCount = _this$metrics.columnCount,
260
+ top = _this$metrics.top,
261
+ left = _this$metrics.left,
262
+ height = _this$metrics.height,
263
+ width = _this$metrics.width;
264
+ var _this$prevMetrics = this.prevMetrics,
265
+ prevRowCount = _this$prevMetrics.rowCount,
266
+ prevColumnCount = _this$prevMetrics.columnCount,
267
+ prevHeight = _this$prevMetrics.height,
268
+ prevWidth = _this$prevMetrics.width;
269
+ var metricState = this.getMetricState();
270
+
271
+ if (prevRowCount !== rowCount || height !== prevHeight) {
272
+ var lastTop = this.metricCalculator.getLastTop(metricState);
273
+
274
+ if (this.isStuckToBottom && bottomVisible < rowCount - 1 && bottomVisible > 0 && top > 0 || top > lastTop) {
275
+ this.setState({
276
+ top: lastTop
277
+ });
278
+ }
279
+ }
352
280
 
353
- getModelRow(rowIndex) {
354
- var _this$metrics2, _this$metrics2$modelR;
281
+ if (prevColumnCount !== columnCount || width !== prevWidth) {
282
+ var lastLeft = this.metricCalculator.getLastLeft(metricState);
355
283
 
356
- return (_this$metrics2 = this.metrics) === null || _this$metrics2 === void 0 ? void 0 : (_this$metrics2$modelR = _this$metrics2.modelRows) === null || _this$metrics2$modelR === void 0 ? void 0 : _this$metrics2$modelR.get(rowIndex);
357
- }
284
+ if (this.isStuckToRight && rightVisible < columnCount - 1 && rightVisible > 0 && left > 0 || left > lastLeft) {
285
+ this.setState({
286
+ left: lastLeft
287
+ });
288
+ }
289
+ }
358
290
 
359
- toggleRowExpanded(row) {
360
- var {
361
- metrics
362
- } = this;
363
- var {
364
- modelRows
365
- } = metrics;
366
- var modelRow = modelRows.get(row);
367
- var {
368
- model
369
- } = this.props; // We only want to set expansion if the row is expandable
370
- // If it's not, still move the cursor to that position, as it may be outside of the current viewport and we don't know if it's expandable yet
371
-
372
- if (model.isRowExpandable(modelRow)) {
373
- model.setRowExpanded(modelRow, !model.isRowExpanded(modelRow));
291
+ if (this.validateSelection()) {
292
+ this.checkSelectionChange(prevState);
293
+ }
374
294
  }
375
-
376
- this.clearSelectedRanges();
377
- this.commitSelection(); // Need to commit before moving in case we're selecting same row again
378
-
379
- this.moveCursorToPosition(0, row);
380
- this.commitSelection();
381
- this.isStuckToBottom = false;
382
- }
383
- /** Allows the selected range to be set programatically */
384
-
385
-
386
- setSelectedRanges(gridRanges) {
387
- var {
388
- model
389
- } = this.props;
390
- var {
391
- columnCount,
392
- rowCount
393
- } = model;
394
- var {
395
- cursorRow,
396
- cursorColumn,
397
- selectedRanges
398
- } = this.state;
399
- this.setState({
400
- selectedRanges: gridRanges,
401
- lastSelectedRanges: selectedRanges
402
- });
403
-
404
- if (gridRanges.length > 0) {
405
- var range = GridRange.boundedRange(gridRanges[0], columnCount, rowCount);
406
- var newCursorRow = cursorRow;
407
- var newCursorColumn = cursorColumn;
408
-
409
- if (!range.containsCell(cursorColumn, cursorRow)) {
410
- ({
411
- row: newCursorRow,
412
- column: newCursorColumn
413
- } = range.startCell());
295
+ }, {
296
+ key: "componentWillUnmount",
297
+ value: function componentWillUnmount() {
298
+ if (this.animationFrame != null) {
299
+ cancelAnimationFrame(this.animationFrame);
414
300
  }
415
301
 
416
- this.setState({
417
- selectionStartColumn: range.startColumn,
418
- selectionStartRow: range.startRow,
419
- selectionEndColumn: range.endColumn,
420
- selectionEndRow: range.endRow,
421
- cursorColumn: newCursorColumn,
422
- cursorRow: newCursorRow
302
+ this.canvas.removeEventListener('wheel', this.handleWheel, {
303
+ passive: false
423
304
  });
305
+ window.removeEventListener('mousemove', this.handleMouseDrag, true);
306
+ window.removeEventListener('mouseup', this.handleMouseUp, true);
307
+ window.removeEventListener('resize', this.handleResize);
308
+ this.stopDragTimer();
424
309
  }
425
- }
310
+ }, {
311
+ key: "getTheme",
312
+ value: function getTheme() {
313
+ var theme = this.props.theme;
314
+ return Grid.getTheme(theme);
315
+ }
316
+ }, {
317
+ key: "getGridPointFromEvent",
318
+ value: function getGridPointFromEvent(event) {
319
+ var rect = this.canvas.getBoundingClientRect();
320
+ var x = event.clientX - rect.left;
321
+ var y = event.clientY - rect.top;
322
+ return this.getGridPointFromXY(x, y);
323
+ }
324
+ }, {
325
+ key: "getGridPointFromXY",
326
+ value: function getGridPointFromXY(x, y) {
327
+ return GridUtils.getGridPointFromXY(x, y, this.metrics);
328
+ }
329
+ }, {
330
+ key: "getMetricState",
331
+ value: function getMetricState() {
332
+ var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.state;
333
+ var theme = this.getTheme();
334
+ var _this$props2 = this.props,
335
+ model = _this$props2.model,
336
+ stateOverride = _this$props2.stateOverride;
337
+ var context = this.canvasContext;
338
+ var width = this.canvas.clientWidth;
339
+ var height = this.canvas.clientHeight;
340
+ var left = state.left,
341
+ top = state.top,
342
+ leftOffset = state.leftOffset,
343
+ topOffset = state.topOffset,
344
+ movedColumns = state.movedColumns,
345
+ movedRows = state.movedRows,
346
+ isDraggingHorizontalScrollBar = state.isDraggingHorizontalScrollBar,
347
+ isDraggingVerticalScrollBar = state.isDraggingVerticalScrollBar;
348
+ return _objectSpread({
349
+ left: left,
350
+ top: top,
351
+ leftOffset: leftOffset,
352
+ topOffset: topOffset,
353
+ width: width,
354
+ height: height,
355
+ context: context,
356
+ theme: theme,
357
+ model: model,
358
+ movedColumns: movedColumns,
359
+ movedRows: movedRows,
360
+ isDraggingHorizontalScrollBar: isDraggingHorizontalScrollBar,
361
+ isDraggingVerticalScrollBar: isDraggingVerticalScrollBar
362
+ }, stateOverride);
363
+ }
364
+ }, {
365
+ key: "getKeyHandlers",
366
+ value: function getKeyHandlers() {
367
+ var keyHandlers = this.props.keyHandlers;
368
+ return this.getCachedKeyHandlers(keyHandlers);
369
+ }
370
+ }, {
371
+ key: "getMouseHandlers",
372
+ value: function getMouseHandlers() {
373
+ var mouseHandlers = this.props.mouseHandlers;
374
+ return this.getCachedMouseHandlers(mouseHandlers);
375
+ }
376
+ }, {
377
+ key: "getModelColumn",
378
+ value: function getModelColumn(columnIndex) {
379
+ var _this$metrics2, _this$metrics2$modelC;
426
380
 
427
- initContext() {
428
- var {
429
- canvas
430
- } = this;
431
- var {
432
- canvasOptions
433
- } = this.props;
434
- this.canvasContext = canvas.getContext('2d', canvasOptions);
435
- }
381
+ return (_this$metrics2 = this.metrics) === null || _this$metrics2 === void 0 ? void 0 : (_this$metrics2$modelC = _this$metrics2.modelColumns) === null || _this$metrics2$modelC === void 0 ? void 0 : _this$metrics2$modelC.get(columnIndex);
382
+ }
383
+ }, {
384
+ key: "getModelRow",
385
+ value: function getModelRow(rowIndex) {
386
+ var _this$metrics3, _this$metrics3$modelR;
436
387
 
437
- requestUpdateCanvas() {
438
- if (this.animationFrame != null) {
439
- return;
388
+ return (_this$metrics3 = this.metrics) === null || _this$metrics3 === void 0 ? void 0 : (_this$metrics3$modelR = _this$metrics3.modelRows) === null || _this$metrics3$modelR === void 0 ? void 0 : _this$metrics3$modelR.get(rowIndex);
440
389
  }
390
+ }, {
391
+ key: "toggleRowExpanded",
392
+ value: function toggleRowExpanded(row) {
393
+ var metrics = this.metrics;
394
+ var modelRows = metrics.modelRows;
395
+ var modelRow = modelRows.get(row);
396
+ var model = this.props.model; // We only want to set expansion if the row is expandable
397
+ // If it's not, still move the cursor to that position, as it may be outside of the current viewport and we don't know if it's expandable yet
398
+
399
+ if (model.isRowExpandable(modelRow)) {
400
+ model.setRowExpanded(modelRow, !model.isRowExpanded(modelRow));
401
+ }
441
402
 
442
- this.animationFrame = requestAnimationFrame(() => {
443
- this.animationFrame = null;
444
- this.updateCanvas(this.metrics);
445
- });
446
- }
403
+ this.clearSelectedRanges();
404
+ this.commitSelection(); // Need to commit before moving in case we're selecting same row again
447
405
 
448
- updateCanvas() {
449
- var metrics = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.updateMetrics();
450
- this.updateCanvasScale();
451
- var {
452
- onViewChanged
453
- } = this.props;
454
- onViewChanged(metrics);
455
- this.drawCanvas(metrics);
456
- }
406
+ this.moveCursorToPosition(0, row);
407
+ this.commitSelection();
408
+ this.isStuckToBottom = false;
409
+ }
410
+ /** Allows the selected range to be set programatically */
411
+
412
+ }, {
413
+ key: "setSelectedRanges",
414
+ value: function setSelectedRanges(gridRanges) {
415
+ var model = this.props.model;
416
+ var columnCount = model.columnCount,
417
+ rowCount = model.rowCount;
418
+ var _this$state2 = this.state,
419
+ cursorRow = _this$state2.cursorRow,
420
+ cursorColumn = _this$state2.cursorColumn,
421
+ selectedRanges = _this$state2.selectedRanges;
422
+ this.setState({
423
+ selectedRanges: gridRanges,
424
+ lastSelectedRanges: selectedRanges
425
+ });
457
426
 
458
- updateCanvasScale() {
459
- var {
460
- canvas,
461
- canvasContext
462
- } = this;
463
- var scale = Grid.getScale(canvasContext); // the parent wrapper has 100% width/height, and is used for determining size
464
- // we don't want to stretch the canvas to 100%, to avoid fractional pixels.
465
- // A wrapper element must be used for sizing, and canvas size must be
466
- // set manually to a floored value in css and a scaled value in width/height
467
-
468
- var {
469
- width,
470
- height
471
- } = canvas.parentElement.getBoundingClientRect();
472
- canvas.style.width = "".concat(Math.floor(width), "px");
473
- canvas.style.height = "".concat(Math.floor(height), "px");
474
- canvas.width = Math.floor(width) * scale;
475
- canvas.height = Math.floor(height) * scale;
476
- canvasContext.scale(scale, scale);
477
- }
427
+ if (gridRanges.length > 0) {
428
+ var range = GridRange.boundedRange(gridRanges[0], columnCount, rowCount);
429
+ var newCursorRow = cursorRow;
430
+ var newCursorColumn = cursorColumn;
478
431
 
479
- updateMetrics() {
480
- var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.state;
481
- this.prevMetrics = this.metrics;
482
- var {
483
- metricCalculator
484
- } = this;
485
- var metricState = this.getMetricState(state);
486
- this.metrics = metricCalculator.getMetrics(metricState);
487
- return this.metrics;
488
- }
432
+ if (!range.containsCell(cursorColumn, cursorRow)) {
433
+ var _range$startCell = range.startCell();
489
434
 
490
- checkSelectionChange(prevState) {
491
- var {
492
- selectedRanges: oldSelectedRanges
493
- } = prevState;
494
- var {
495
- selectedRanges
496
- } = this.state;
497
-
498
- if (selectedRanges !== oldSelectedRanges) {
499
- var {
500
- onSelectionChanged
501
- } = this.props;
502
- onSelectionChanged(selectedRanges);
503
- }
504
- }
435
+ newCursorRow = _range$startCell.row;
436
+ newCursorColumn = _range$startCell.column;
437
+ }
505
438
 
506
- validateSelection() {
507
- var {
508
- model
509
- } = this.props;
510
- var {
511
- selectedRanges
512
- } = this.state;
513
- var {
514
- columnCount,
515
- rowCount
516
- } = model;
517
-
518
- for (var i = 0; i < selectedRanges.length; i += 1) {
519
- var range = selectedRanges[i];
520
-
521
- if (range.endColumn != null && range.endColumn >= columnCount || range.endRow != null && range.endRow >= rowCount) {
522
- // Just clear the selection rather than trying to trim it.
523
439
  this.setState({
524
- selectedRanges: [],
525
- lastSelectedRanges: []
440
+ selectionStartColumn: range.startColumn,
441
+ selectionStartRow: range.startRow,
442
+ selectionEndColumn: range.endColumn,
443
+ selectionEndRow: range.endRow,
444
+ cursorColumn: newCursorColumn,
445
+ cursorRow: newCursorRow
526
446
  });
527
- return false;
528
447
  }
529
448
  }
449
+ }, {
450
+ key: "initContext",
451
+ value: function initContext() {
452
+ var canvas = this.canvas;
453
+ var canvasOptions = this.props.canvasOptions;
454
+ this.canvasContext = canvas.getContext('2d', canvasOptions);
455
+ }
456
+ }, {
457
+ key: "requestUpdateCanvas",
458
+ value: function requestUpdateCanvas() {
459
+ var _this2 = this;
530
460
 
531
- return true;
532
- }
461
+ if (this.animationFrame != null) {
462
+ return;
463
+ }
533
464
 
534
- clearSelectedRanges() {
535
- var {
536
- selectedRanges
537
- } = this.state;
538
- this.setState({
539
- selectedRanges: [],
540
- lastSelectedRanges: selectedRanges
541
- });
542
- }
543
- /** Clears all but the last selected range */
465
+ this.animationFrame = requestAnimationFrame(function () {
466
+ _this2.animationFrame = null;
467
+
468
+ _this2.updateCanvas(_this2.metrics);
469
+ });
470
+ }
471
+ }, {
472
+ key: "updateCanvas",
473
+ value: function updateCanvas() {
474
+ var metrics = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.updateMetrics();
475
+ this.updateCanvasScale();
476
+ var onViewChanged = this.props.onViewChanged;
477
+ onViewChanged(metrics);
478
+ this.drawCanvas(metrics);
479
+ }
480
+ }, {
481
+ key: "updateCanvasScale",
482
+ value: function updateCanvasScale() {
483
+ var canvas = this.canvas,
484
+ canvasContext = this.canvasContext;
485
+ var scale = Grid.getScale(canvasContext); // the parent wrapper has 100% width/height, and is used for determining size
486
+ // we don't want to stretch the canvas to 100%, to avoid fractional pixels.
487
+ // A wrapper element must be used for sizing, and canvas size must be
488
+ // set manually to a floored value in css and a scaled value in width/height
489
+
490
+ var _canvas$parentElement = canvas.parentElement.getBoundingClientRect(),
491
+ width = _canvas$parentElement.width,
492
+ height = _canvas$parentElement.height;
493
+
494
+ canvas.style.width = "".concat(Math.floor(width), "px");
495
+ canvas.style.height = "".concat(Math.floor(height), "px");
496
+ canvas.width = Math.floor(width) * scale;
497
+ canvas.height = Math.floor(height) * scale;
498
+ canvasContext.scale(scale, scale);
499
+ }
500
+ }, {
501
+ key: "updateMetrics",
502
+ value: function updateMetrics() {
503
+ var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.state;
504
+ this.prevMetrics = this.metrics;
505
+ var metricCalculator = this.metricCalculator;
506
+ var metricState = this.getMetricState(state);
507
+ this.metrics = metricCalculator.getMetrics(metricState);
508
+ return this.metrics;
509
+ }
510
+ }, {
511
+ key: "checkSelectionChange",
512
+ value: function checkSelectionChange(prevState) {
513
+ var oldSelectedRanges = prevState.selectedRanges;
514
+ var selectedRanges = this.state.selectedRanges;
515
+
516
+ if (selectedRanges !== oldSelectedRanges) {
517
+ var onSelectionChanged = this.props.onSelectionChanged;
518
+ onSelectionChanged(selectedRanges);
519
+ }
520
+ }
521
+ }, {
522
+ key: "validateSelection",
523
+ value: function validateSelection() {
524
+ var model = this.props.model;
525
+ var selectedRanges = this.state.selectedRanges;
526
+ var columnCount = model.columnCount,
527
+ rowCount = model.rowCount;
528
+
529
+ for (var i = 0; i < selectedRanges.length; i += 1) {
530
+ var range = selectedRanges[i];
531
+
532
+ if (range.endColumn != null && range.endColumn >= columnCount || range.endRow != null && range.endRow >= rowCount) {
533
+ // Just clear the selection rather than trying to trim it.
534
+ this.setState({
535
+ selectedRanges: [],
536
+ lastSelectedRanges: []
537
+ });
538
+ return false;
539
+ }
540
+ }
544
541
 
542
+ return true;
543
+ }
544
+ }, {
545
+ key: "clearSelectedRanges",
546
+ value: function clearSelectedRanges() {
547
+ var selectedRanges = this.state.selectedRanges;
548
+ this.setState({
549
+ selectedRanges: [],
550
+ lastSelectedRanges: selectedRanges
551
+ });
552
+ }
553
+ /** Clears all but the last selected range */
545
554
 
546
- trimSelectedRanges() {
547
- var {
548
- selectedRanges
549
- } = this.state;
555
+ }, {
556
+ key: "trimSelectedRanges",
557
+ value: function trimSelectedRanges() {
558
+ var selectedRanges = this.state.selectedRanges;
550
559
 
551
- if (selectedRanges.length > 0) {
560
+ if (selectedRanges.length > 0) {
561
+ this.setState({
562
+ selectedRanges: selectedRanges.slice(selectedRanges.length - 1)
563
+ });
564
+ }
565
+ }
566
+ }, {
567
+ key: "beginSelection",
568
+ value: function beginSelection(column, row) {
552
569
  this.setState({
553
- selectedRanges: selectedRanges.slice(selectedRanges.length - 1)
570
+ selectionStartColumn: column,
571
+ selectionStartRow: row,
572
+ selectionEndColumn: column,
573
+ selectionEndRow: row,
574
+ cursorColumn: column,
575
+ cursorRow: row
554
576
  });
555
577
  }
556
- }
578
+ /**
579
+ * Moves the selection to the cell specified
580
+ * @param {number} column The column index to move the cursor to
581
+ * @param {number} row The row index to move the cursor to
582
+ * @param {boolean} extendSelection Whether to extend the current selection (eg. holding Shift)
583
+ * @param {boolean} maximizePreviousRange When true, maximize/add to the previous range only, ignoring where the selection was started.
584
+ */
557
585
 
558
- beginSelection(column, row) {
559
- this.setState({
560
- selectionStartColumn: column,
561
- selectionStartRow: row,
562
- selectionEndColumn: column,
563
- selectionEndRow: row,
564
- cursorColumn: column,
565
- cursorRow: row
566
- });
567
- }
568
- /**
569
- * Moves the selection to the cell specified
570
- * @param {number} column The column index to move the cursor to
571
- * @param {number} row The row index to move the cursor to
572
- * @param {boolean} extendSelection Whether to extend the current selection (eg. holding Shift)
573
- * @param {boolean} maximizePreviousRange When true, maximize/add to the previous range only, ignoring where the selection was started.
574
- */
575
-
576
-
577
- moveSelection(column, row) {
578
- var extendSelection = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
579
- var maximizePreviousRange = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
580
- this.setState(state => {
581
- var {
582
- selectedRanges,
583
- selectionStartRow,
584
- selectionStartColumn
585
- } = state;
586
- var {
587
- theme
588
- } = this.props;
589
- var {
590
- autoSelectRow,
591
- autoSelectColumn
592
- } = theme;
593
-
594
- if (extendSelection && selectedRanges.length > 0) {
595
- var lastSelectedRange = selectedRanges[selectedRanges.length - 1];
596
- var left = null;
597
- var top = null;
598
- var right = null;
599
- var bottom = null;
600
-
601
- if (maximizePreviousRange) {
602
- left = autoSelectRow ? null : Math.min(column, lastSelectedRange.startColumn);
603
- top = autoSelectColumn ? null : Math.min(row, lastSelectedRange.startRow);
604
- right = autoSelectRow ? null : Math.max(column, lastSelectedRange.endColumn);
605
- bottom = autoSelectColumn ? null : Math.max(row, lastSelectedRange.endRow);
606
- } else {
607
- left = lastSelectedRange.startColumn;
608
- top = lastSelectedRange.startRow;
609
-
610
- if (selectionStartColumn != null || selectionStartRow != null) {
611
- if (!autoSelectRow) {
612
- left = selectionStartColumn;
586
+ }, {
587
+ key: "moveSelection",
588
+ value: function moveSelection(column, row) {
589
+ var _this3 = this;
590
+
591
+ var extendSelection = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
592
+ var maximizePreviousRange = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
593
+ this.setState(function (state) {
594
+ var selectedRanges = state.selectedRanges,
595
+ selectionStartRow = state.selectionStartRow,
596
+ selectionStartColumn = state.selectionStartColumn;
597
+ var theme = _this3.props.theme;
598
+ var autoSelectRow = theme.autoSelectRow,
599
+ autoSelectColumn = theme.autoSelectColumn;
600
+
601
+ if (extendSelection && selectedRanges.length > 0) {
602
+ var lastSelectedRange = selectedRanges[selectedRanges.length - 1];
603
+ var left = null;
604
+ var top = null;
605
+ var right = null;
606
+ var bottom = null;
607
+
608
+ if (maximizePreviousRange) {
609
+ left = autoSelectRow ? null : Math.min(column, lastSelectedRange.startColumn);
610
+ top = autoSelectColumn ? null : Math.min(row, lastSelectedRange.startRow);
611
+ right = autoSelectRow ? null : Math.max(column, lastSelectedRange.endColumn);
612
+ bottom = autoSelectColumn ? null : Math.max(row, lastSelectedRange.endRow);
613
+ } else {
614
+ left = lastSelectedRange.startColumn;
615
+ top = lastSelectedRange.startRow;
616
+
617
+ if (selectionStartColumn != null || selectionStartRow != null) {
618
+ if (!autoSelectRow) {
619
+ left = selectionStartColumn;
620
+ }
621
+
622
+ if (!autoSelectColumn) {
623
+ top = selectionStartRow;
624
+ }
613
625
  }
614
626
 
615
- if (!autoSelectColumn) {
616
- top = selectionStartRow;
617
- }
627
+ right = autoSelectRow ? null : column;
628
+ bottom = autoSelectColumn ? null : row;
618
629
  }
619
630
 
620
- right = autoSelectRow ? null : column;
621
- bottom = autoSelectColumn ? null : row;
622
- }
631
+ var selectedRange = GridRange.makeNormalized(left, top, right, bottom);
623
632
 
624
- var selectedRange = GridRange.makeNormalized(left, top, right, bottom);
633
+ if (lastSelectedRange.equals(selectedRange)) {
634
+ return null;
635
+ }
625
636
 
626
- if (lastSelectedRange.equals(selectedRange)) {
627
- return null;
628
- }
637
+ var _newRanges = [].concat(selectedRanges);
629
638
 
630
- var _newRanges = [].concat(selectedRanges);
639
+ _newRanges[_newRanges.length - 1] = selectedRange;
640
+ return {
641
+ selectedRanges: _newRanges,
642
+ selectionEndColumn: column,
643
+ selectionEndRow: row
644
+ };
645
+ }
631
646
 
632
- _newRanges[_newRanges.length - 1] = selectedRange;
647
+ var newRanges = [].concat(selectedRanges);
648
+ var selectedColumn = autoSelectRow ? null : column;
649
+ var selectedRow = autoSelectColumn ? null : row;
650
+ newRanges.push(GridRange.makeNormalized(selectedColumn, selectedRow, selectedColumn, selectedRow));
633
651
  return {
634
- selectedRanges: _newRanges,
652
+ selectedRanges: newRanges,
635
653
  selectionEndColumn: column,
636
654
  selectionEndRow: row
637
655
  };
638
- }
656
+ });
657
+ }
658
+ /**
659
+ * Commits the last selected range to the selected ranges.
660
+ * First checks if the last range is completely contained within another range, and if it
661
+ * is then it blows those ranges apart.
662
+ * Then it consolidates all the selected ranges, reducing them.
663
+ */
639
664
 
640
- var newRanges = [].concat(selectedRanges);
641
- var selectedColumn = autoSelectRow ? null : column;
642
- var selectedRow = autoSelectColumn ? null : row;
643
- newRanges.push(GridRange.makeNormalized(selectedColumn, selectedRow, selectedColumn, selectedRow));
644
- return {
645
- selectedRanges: newRanges,
646
- selectionEndColumn: column,
647
- selectionEndRow: row
648
- };
649
- });
650
- }
651
- /**
652
- * Commits the last selected range to the selected ranges.
653
- * First checks if the last range is completely contained within another range, and if it
654
- * is then it blows those ranges apart.
655
- * Then it consolidates all the selected ranges, reducing them.
656
- */
657
-
658
-
659
- commitSelection() {
660
- this.setState(state => {
661
- var {
662
- theme
663
- } = this.props;
664
- var {
665
- autoSelectRow
666
- } = theme;
667
- var {
668
- selectedRanges,
669
- lastSelectedRanges,
670
- cursorRow,
671
- cursorColumn
672
- } = state;
673
-
674
- if (selectedRanges.length === 1 && (autoSelectRow ? GridRange.rowCount(selectedRanges) === 1 : GridRange.cellCount(selectedRanges) === 1) && GridRange.rangeArraysEqual(selectedRanges, lastSelectedRanges)) {
675
- // If it's the exact same single selection, then deselect.
676
- // For if we click on one cell multiple times.
677
- return {
678
- selectedRanges: [],
679
- lastSelectedRanges: []
680
- };
681
- }
665
+ }, {
666
+ key: "commitSelection",
667
+ value: function commitSelection() {
668
+ var _this4 = this;
669
+
670
+ this.setState(function (state) {
671
+ var theme = _this4.props.theme;
672
+ var autoSelectRow = theme.autoSelectRow;
673
+ var selectedRanges = state.selectedRanges,
674
+ lastSelectedRanges = state.lastSelectedRanges,
675
+ cursorRow = state.cursorRow,
676
+ cursorColumn = state.cursorColumn;
677
+
678
+ if (selectedRanges.length === 1 && (autoSelectRow ? GridRange.rowCount(selectedRanges) === 1 : GridRange.cellCount(selectedRanges) === 1) && GridRange.rangeArraysEqual(selectedRanges, lastSelectedRanges)) {
679
+ // If it's the exact same single selection, then deselect.
680
+ // For if we click on one cell multiple times.
681
+ return {
682
+ selectedRanges: [],
683
+ lastSelectedRanges: []
684
+ };
685
+ }
682
686
 
683
- var newSelectedRanges = selectedRanges.slice();
687
+ var newSelectedRanges = selectedRanges.slice();
684
688
 
685
- if (newSelectedRanges.length > 1) {
686
- // Check if the latest selection is entirely within a previously selected range
687
- // If that's the case, then deselect that section instead
688
- var lastRange = newSelectedRanges[newSelectedRanges.length - 1];
689
+ if (newSelectedRanges.length > 1) {
690
+ // Check if the latest selection is entirely within a previously selected range
691
+ // If that's the case, then deselect that section instead
692
+ var lastRange = newSelectedRanges[newSelectedRanges.length - 1];
689
693
 
690
- for (var i = 0; i < newSelectedRanges.length - 1; i += 1) {
691
- var selectedRange = newSelectedRanges[i];
694
+ for (var i = 0; i < newSelectedRanges.length - 1; i += 1) {
695
+ var selectedRange = newSelectedRanges[i];
692
696
 
693
- if (selectedRange.contains(lastRange)) {
694
- // We found a match, now remove the two matching ranges, and add back
695
- // the remainder of the two
696
- var remainder = selectedRange.subtract(lastRange);
697
- newSelectedRanges.pop();
698
- newSelectedRanges.splice(i, 1);
699
- newSelectedRanges = newSelectedRanges.concat(remainder);
700
- break;
697
+ if (selectedRange.contains(lastRange)) {
698
+ // We found a match, now remove the two matching ranges, and add back
699
+ // the remainder of the two
700
+ var remainder = selectedRange.subtract(lastRange);
701
+ newSelectedRanges.pop();
702
+ newSelectedRanges.splice(i, 1);
703
+ newSelectedRanges = newSelectedRanges.concat(remainder);
704
+ break;
705
+ }
701
706
  }
702
- }
703
-
704
- newSelectedRanges = GridRange.consolidate(newSelectedRanges);
705
- }
706
707
 
707
- var newCursorColumn = cursorColumn;
708
- var newCursorRow = cursorRow;
709
-
710
- if (!GridRange.containsCell(newSelectedRanges, cursorColumn, cursorRow)) {
711
- var {
712
- model
713
- } = this.props;
714
- var {
715
- columnCount,
716
- rowCount
717
- } = model;
718
- var nextCursor = GridRange.nextCell(GridRange.boundedRanges(selectedRanges, columnCount, rowCount));
719
-
720
- if (nextCursor != null) {
721
- ({
722
- column: newCursorColumn,
723
- row: newCursorRow
724
- } = nextCursor);
725
- } else {
726
- newCursorColumn = null;
727
- newCursorRow = null;
708
+ newSelectedRanges = GridRange.consolidate(newSelectedRanges);
728
709
  }
729
- }
730
-
731
- return {
732
- cursorRow: newCursorRow,
733
- cursorColumn: newCursorColumn,
734
- selectedRanges: newSelectedRanges,
735
- lastSelectedRanges: selectedRanges
736
- };
737
- });
738
- }
739
710
 
740
- selectAll() {
741
- var {
742
- model,
743
- theme
744
- } = this.props;
745
- var {
746
- autoSelectRow,
747
- autoSelectColumn
748
- } = theme;
749
- var top = autoSelectColumn ? null : 0;
750
- var bottom = autoSelectColumn ? null : model.rowCount - 1;
751
- var left = autoSelectRow ? null : 0;
752
- var right = autoSelectRow ? null : model.columnCount - 1;
753
- this.setSelectedRanges([new GridRange(left, top, right, bottom)]);
754
- }
711
+ var newCursorColumn = cursorColumn;
712
+ var newCursorRow = cursorRow;
713
+
714
+ if (!GridRange.containsCell(newSelectedRanges, cursorColumn, cursorRow)) {
715
+ var model = _this4.props.model;
716
+ var columnCount = model.columnCount,
717
+ rowCount = model.rowCount;
718
+ var nextCursor = GridRange.nextCell(GridRange.boundedRanges(selectedRanges, columnCount, rowCount));
719
+
720
+ if (nextCursor != null) {
721
+ newCursorColumn = nextCursor.column;
722
+ newCursorRow = nextCursor.row;
723
+ } else {
724
+ newCursorColumn = null;
725
+ newCursorRow = null;
726
+ }
727
+ }
755
728
 
756
- moveCursor(deltaColumn, deltaRow, extendSelection) {
757
- var {
758
- cursorRow,
759
- cursorColumn,
760
- selectionEndColumn,
761
- selectionEndRow
762
- } = this.state;
763
- var column = extendSelection ? selectionEndColumn : cursorColumn;
764
- var row = extendSelection ? selectionEndRow : cursorRow;
765
-
766
- if (row === null || column === null) {
767
- var {
768
- left,
769
- top
770
- } = this.state;
771
- this.moveCursorToPosition(left, top, extendSelection);
772
- } else {
773
- var {
774
- model
775
- } = this.props;
776
- var {
777
- columnCount,
778
- rowCount
779
- } = model;
780
-
781
- var _left = clamp(column + deltaColumn, 0, columnCount - 1);
782
-
783
- var _top = clamp(row + deltaRow, 0, rowCount - 1);
784
-
785
- this.moveCursorToPosition(_left, _top, extendSelection);
729
+ return {
730
+ cursorRow: newCursorRow,
731
+ cursorColumn: newCursorColumn,
732
+ selectedRanges: newSelectedRanges,
733
+ lastSelectedRanges: selectedRanges
734
+ };
735
+ });
786
736
  }
787
- }
788
- /**
789
- * Move the cursor in the provided selection direction
790
- * @param {string} direction The direction to move the cursor in
791
- */
792
-
793
-
794
- moveCursorInDirection() {
795
- var direction = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : GridRange.SELECTION_DIRECTION.DOWN;
796
- var {
797
- model
798
- } = this.props;
799
- var {
800
- columnCount,
801
- rowCount
802
- } = model;
803
- var {
804
- cursorRow,
805
- cursorColumn,
806
- selectedRanges
807
- } = this.state;
808
- var ranges = selectedRanges.length > 0 ? selectedRanges : [GridRange.makeCell(cursorColumn, cursorRow)];
809
- var nextCursor = null;
810
-
811
- if (ranges.length === 1 && GridRange.cellCount(ranges) === 1) {
812
- var _gridRange$nextCell;
813
-
814
- // If we only have one cell selected, we want to update the cursor and we want to update the selected cells
815
- var gridRange = new GridRange(0, 0, columnCount - 1, rowCount - 1);
816
- nextCursor = (_gridRange$nextCell = gridRange.nextCell(cursorColumn, cursorRow, direction)) !== null && _gridRange$nextCell !== void 0 ? _gridRange$nextCell : gridRange.startCell(direction);
817
- } else {
818
- nextCursor = GridRange.nextCell(GridRange.boundedRanges(ranges, columnCount, rowCount), cursorColumn, cursorRow, direction);
737
+ }, {
738
+ key: "selectAll",
739
+ value: function selectAll() {
740
+ var _this$props3 = this.props,
741
+ model = _this$props3.model,
742
+ theme = _this$props3.theme;
743
+ var autoSelectRow = theme.autoSelectRow,
744
+ autoSelectColumn = theme.autoSelectColumn;
745
+ var top = autoSelectColumn ? null : 0;
746
+ var bottom = autoSelectColumn ? null : model.rowCount - 1;
747
+ var left = autoSelectRow ? null : 0;
748
+ var right = autoSelectRow ? null : model.columnCount - 1;
749
+ this.setSelectedRanges([new GridRange(left, top, right, bottom)]);
750
+ }
751
+ }, {
752
+ key: "moveCursor",
753
+ value: function moveCursor(deltaColumn, deltaRow, extendSelection) {
754
+ var _this$state3 = this.state,
755
+ cursorRow = _this$state3.cursorRow,
756
+ cursorColumn = _this$state3.cursorColumn,
757
+ selectionEndColumn = _this$state3.selectionEndColumn,
758
+ selectionEndRow = _this$state3.selectionEndRow;
759
+ var column = extendSelection ? selectionEndColumn : cursorColumn;
760
+ var row = extendSelection ? selectionEndRow : cursorRow;
761
+
762
+ if (row === null || column === null) {
763
+ var _this$state4 = this.state,
764
+ left = _this$state4.left,
765
+ top = _this$state4.top;
766
+ this.moveCursorToPosition(left, top, extendSelection);
767
+ } else {
768
+ var model = this.props.model;
769
+ var columnCount = model.columnCount,
770
+ rowCount = model.rowCount;
771
+
772
+ var _left = clamp(column + deltaColumn, 0, columnCount - 1);
773
+
774
+ var _top = clamp(row + deltaRow, 0, rowCount - 1);
775
+
776
+ this.moveCursorToPosition(_left, _top, extendSelection);
777
+ }
819
778
  }
779
+ /**
780
+ * Move the cursor in the provided selection direction
781
+ * @param {string} direction The direction to move the cursor in
782
+ */
820
783
 
821
- if (nextCursor != null) {
822
- var {
823
- column,
824
- row
825
- } = nextCursor;
826
- this.setState({
827
- cursorColumn: column,
828
- cursorRow: row
829
- });
784
+ }, {
785
+ key: "moveCursorInDirection",
786
+ value: function moveCursorInDirection() {
787
+ var direction = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : GridRange.SELECTION_DIRECTION.DOWN;
788
+ var model = this.props.model;
789
+ var columnCount = model.columnCount,
790
+ rowCount = model.rowCount;
791
+ var _this$state5 = this.state,
792
+ cursorRow = _this$state5.cursorRow,
793
+ cursorColumn = _this$state5.cursorColumn,
794
+ selectedRanges = _this$state5.selectedRanges;
795
+ var ranges = selectedRanges.length > 0 ? selectedRanges : [GridRange.makeCell(cursorColumn, cursorRow)];
796
+ var nextCursor = null;
797
+
798
+ if (ranges.length === 1 && GridRange.cellCount(ranges) === 1) {
799
+ var _gridRange$nextCell;
800
+
801
+ // If we only have one cell selected, we want to update the cursor and we want to update the selected cells
802
+ var gridRange = new GridRange(0, 0, columnCount - 1, rowCount - 1);
803
+ nextCursor = (_gridRange$nextCell = gridRange.nextCell(cursorColumn, cursorRow, direction)) !== null && _gridRange$nextCell !== void 0 ? _gridRange$nextCell : gridRange.startCell(direction);
804
+ } else {
805
+ nextCursor = GridRange.nextCell(GridRange.boundedRanges(ranges, columnCount, rowCount), cursorColumn, cursorRow, direction);
806
+ }
830
807
 
831
- if (!GridRange.containsCell(selectedRanges, column, row)) {
808
+ if (nextCursor != null) {
809
+ var _nextCursor = nextCursor,
810
+ column = _nextCursor.column,
811
+ row = _nextCursor.row;
832
812
  this.setState({
833
- selectedRanges: [GridRange.makeCell(column, row)],
834
- selectionStartColumn: column,
835
- selectionStartRow: row,
836
- selectionEndColumn: column,
837
- selectionEndRow: row
813
+ cursorColumn: column,
814
+ cursorRow: row
838
815
  });
839
- }
840
-
841
- this.moveViewToCell(nextCursor.column, nextCursor.row);
842
- }
843
- }
844
- /**
845
- * Move a cursor to the specified position in the grid.
846
- * @param {number|null} column The column index to move the cursor to
847
- * @param {number|null} row The row index to move the cursor to
848
- * @param {boolean} extendSelection Whether to extend the current selection (eg. holding Shift)
849
- * @param {boolean} keepCursorInView Whether to move the viewport so that the cursor is in view
850
- * @param {boolean} maximizePreviousRange With this and `extendSelection` true, it will maximize/add to the previous range only, ignoring where the selection was started
851
- */
852
-
853
-
854
- moveCursorToPosition(column, row) {
855
- var extendSelection = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
856
- var keepCursorInView = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
857
- var maximizePreviousRange = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
858
-
859
- if (!extendSelection) {
860
- this.beginSelection(column, row);
861
- }
862
-
863
- this.moveSelection(column, row, extendSelection, maximizePreviousRange);
864
816
 
865
- if (keepCursorInView) {
866
- this.moveViewToCell(column, row);
867
- }
868
- }
869
- /**
870
- * Moves the view to make the specified cell visible
871
- *
872
- * @param {number|null} column The column index to bring into view
873
- * @param {number|null} row The row index to bring into view
874
- */
875
-
876
-
877
- moveViewToCell(column, row) {
878
- var {
879
- metricCalculator
880
- } = this;
881
- var {
882
- bottomVisible,
883
- rightVisible,
884
- topVisible,
885
- leftVisible
886
- } = this.metrics;
887
- var metricState = this.getMetricState(this.state);
888
- var {
889
- top,
890
- left,
891
- topOffset,
892
- leftOffset
893
- } = this.state;
894
-
895
- if (row != null && !GridUtils.isFloatingRow(row, this.metrics)) {
896
- if (row < topVisible) {
897
- top = metricCalculator.getTopForTopVisible(metricState, row);
898
- topOffset = 0;
899
- } else if (row > bottomVisible) {
900
- top = metricCalculator.getTopForBottomVisible(metricState, row);
901
- topOffset = 0;
902
- }
903
- }
817
+ if (!GridRange.containsCell(selectedRanges, column, row)) {
818
+ this.setState({
819
+ selectedRanges: [GridRange.makeCell(column, row)],
820
+ selectionStartColumn: column,
821
+ selectionStartRow: row,
822
+ selectionEndColumn: column,
823
+ selectionEndRow: row
824
+ });
825
+ }
904
826
 
905
- if (column != null && !GridUtils.isFloatingColumn(column, this.metrics)) {
906
- if (column < leftVisible) {
907
- left = metricCalculator.getLeftForLeftVisible(metricState, column);
908
- leftOffset = 0;
909
- } else if (column > rightVisible) {
910
- left = metricCalculator.getLeftForRightVisible(metricState, column);
911
- leftOffset = 0;
827
+ this.moveViewToCell(nextCursor.column, nextCursor.row);
912
828
  }
913
829
  }
830
+ /**
831
+ * Move a cursor to the specified position in the grid.
832
+ * @param {number|null} column The column index to move the cursor to
833
+ * @param {number|null} row The row index to move the cursor to
834
+ * @param {boolean} extendSelection Whether to extend the current selection (eg. holding Shift)
835
+ * @param {boolean} keepCursorInView Whether to move the viewport so that the cursor is in view
836
+ * @param {boolean} maximizePreviousRange With this and `extendSelection` true, it will maximize/add to the previous range only, ignoring where the selection was started
837
+ */
914
838
 
915
- this.setViewState({
916
- top,
917
- left,
918
- topOffset,
919
- leftOffset
920
- });
921
- }
922
- /**
923
- * Checks the `top` and `left` properties that are set and updates the isStuckToBottom/Right properties
924
- * Should be called when user interaction occurs
925
- * @param {object} viewState New state properties to set.
926
- * @param {boolean} forceUpdate Whether to force an update.
927
- */
928
-
929
-
930
- setViewState(viewState) {
931
- var forceUpdate = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
932
- var {
933
- isStickyBottom,
934
- isStickyRight
935
- } = this.props;
936
- var {
937
- top,
938
- left
939
- } = viewState;
940
- var {
941
- lastTop,
942
- lastLeft
943
- } = this.metrics;
944
-
945
- if (top != null) {
946
- this.isStuckToBottom = isStickyBottom && top >= lastTop;
947
- }
839
+ }, {
840
+ key: "moveCursorToPosition",
841
+ value: function moveCursorToPosition(column, row) {
842
+ var extendSelection = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
843
+ var keepCursorInView = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
844
+ var maximizePreviousRange = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
948
845
 
949
- if (left != null) {
950
- this.isStuckToRight = isStickyRight && left >= lastLeft;
951
- }
846
+ if (!extendSelection) {
847
+ this.beginSelection(column, row);
848
+ }
952
849
 
953
- this.setState(viewState);
850
+ this.moveSelection(column, row, extendSelection, maximizePreviousRange);
954
851
 
955
- if (forceUpdate) {
956
- this.forceUpdate();
852
+ if (keepCursorInView) {
853
+ this.moveViewToCell(column, row);
854
+ }
957
855
  }
958
- }
959
- /**
960
- * Start editing the data at the given index
961
- *
962
- * @param {number} column The visible column index to start editing
963
- * @param {number} row The visible row index to start editing
964
- * @param {boolean} isQuickEdit If this is a quick edit (the arrow keys can commit)
965
- * @param {number[]|null} selectionRange The tuple [start,end] text selection range of the value to select when editing
966
- * @param {string?} value The value to start with in the edit field. Leave undefined to use the current value.
967
- */
968
-
969
-
970
- startEditing(column, row) {
971
- var isQuickEdit = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
972
- var selectionRange = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
973
- var value = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : undefined;
974
- var {
975
- model
976
- } = this.props;
977
- var modelColumn = this.getModelColumn(column);
978
- var modelRow = this.getModelRow(row);
979
- var cell = {
980
- column,
981
- row,
982
- selectionRange,
983
- value: value !== undefined ? value : model.editValueForCell(modelColumn, modelRow),
984
- isQuickEdit
985
- };
986
- this.setState({
987
- editingCell: cell,
988
- cursorColumn: column,
989
- cursorRow: row
990
- });
991
- this.moveViewToCell(column, row);
992
- }
856
+ /**
857
+ * Moves the view to make the specified cell visible
858
+ *
859
+ * @param {number|null} column The column index to bring into view
860
+ * @param {number|null} row The row index to bring into view
861
+ */
993
862
 
994
- isValidForCell(column, row, value) {
995
- var {
996
- model
997
- } = this.props;
998
- var modelColumn = this.getModelColumn(column);
999
- var modelRow = this.getModelRow(row);
1000
- return model.isValidForCell(modelColumn, modelRow, value);
1001
- }
1002
- /**
1003
- * Paste a value with the current selection
1004
- * It first needs to validate that the pasted table is valid for the given selection.
1005
- * Also may update selection if single cells are selected and a table is pasted.
1006
- * @param {string[][] | string} value Table or a string that is being pasted
1007
- */
1008
-
1009
-
1010
- pasteValue(value) {
1011
- var _this = this;
1012
-
1013
- return _asyncToGenerator(function* () {
1014
- var {
1015
- model
1016
- } = _this.props;
1017
- var {
1018
- movedColumns,
1019
- movedRows,
1020
- selectedRanges
1021
- } = _this.state;
1022
-
1023
- try {
1024
- if (!model.isEditable || !selectedRanges.every(range => model.isEditableRange(range))) {
1025
- throw new PasteError("Can't paste in to read-only area.");
863
+ }, {
864
+ key: "moveViewToCell",
865
+ value: function moveViewToCell(column, row) {
866
+ var metricCalculator = this.metricCalculator;
867
+ var _this$metrics4 = this.metrics,
868
+ bottomVisible = _this$metrics4.bottomVisible,
869
+ rightVisible = _this$metrics4.rightVisible,
870
+ topVisible = _this$metrics4.topVisible,
871
+ leftVisible = _this$metrics4.leftVisible;
872
+ var metricState = this.getMetricState(this.state);
873
+ var _this$state6 = this.state,
874
+ top = _this$state6.top,
875
+ left = _this$state6.left,
876
+ topOffset = _this$state6.topOffset,
877
+ leftOffset = _this$state6.leftOffset;
878
+
879
+ if (row != null && !GridUtils.isFloatingRow(row, this.metrics)) {
880
+ if (row < topVisible) {
881
+ top = metricCalculator.getTopForTopVisible(metricState, row);
882
+ topOffset = 0;
883
+ } else if (row > bottomVisible) {
884
+ top = metricCalculator.getTopForBottomVisible(metricState, row);
885
+ topOffset = 0;
1026
886
  }
887
+ }
1027
888
 
1028
- if (selectedRanges.length <= 0) {
1029
- throw new PasteError('Select an area to paste to.');
889
+ if (column != null && !GridUtils.isFloatingColumn(column, this.metrics)) {
890
+ if (column < leftVisible) {
891
+ left = metricCalculator.getLeftForLeftVisible(metricState, column);
892
+ leftOffset = 0;
893
+ } else if (column > rightVisible) {
894
+ left = metricCalculator.getLeftForRightVisible(metricState, column);
895
+ leftOffset = 0;
1030
896
  }
897
+ }
1031
898
 
1032
- if (typeof value === 'string') {
1033
- // Just paste the value into all the selected cells
1034
- var _edits = [];
1035
- var modelRanges = GridUtils.getModelRanges(selectedRanges, movedColumns, movedRows);
1036
- GridRange.forEachCell(modelRanges, (x, y) => {
1037
- _edits.push({
1038
- x,
1039
- y,
1040
- text: value
1041
- });
1042
- });
1043
- yield model.setValues(_edits);
1044
- return;
1045
- } // Otherwise it's a table of data
1046
-
1047
-
1048
- var tableHeight = value.length;
1049
- var tableWidth = value[0].length;
1050
- var {
1051
- columnCount,
1052
- rowCount
1053
- } = model;
1054
- var ranges = selectedRanges; // If each cell is a single selection, we need to update the selection to map to the newly pasted data
1055
-
1056
- if (ranges.every(range => GridRange.cellCount([range]) === 1 && range.startColumn + tableWidth <= columnCount && range.startRow + tableHeight <= rowCount)) {
1057
- // Remap the selected ranges
1058
- ranges = ranges.map(range => new GridRange(range.startColumn, range.startRow, range.startColumn + tableWidth - 1, range.startRow + tableHeight - 1));
1059
-
1060
- _this.setSelectedRanges(ranges);
1061
- }
899
+ this.setViewState({
900
+ top: top,
901
+ left: left,
902
+ topOffset: topOffset,
903
+ leftOffset: leftOffset
904
+ });
905
+ }
906
+ /**
907
+ * Checks the `top` and `left` properties that are set and updates the isStuckToBottom/Right properties
908
+ * Should be called when user interaction occurs
909
+ * @param {object} viewState New state properties to set.
910
+ * @param {boolean} forceUpdate Whether to force an update.
911
+ */
1062
912
 
1063
- if (!ranges.every(range => GridRange.rowCount([range]) === tableHeight && GridRange.columnCount([range]) === tableWidth)) {
1064
- throw new PasteError('Copy and paste area are not same size.');
1065
- }
913
+ }, {
914
+ key: "setViewState",
915
+ value: function setViewState(viewState) {
916
+ var forceUpdate = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
917
+ var _this$props4 = this.props,
918
+ isStickyBottom = _this$props4.isStickyBottom,
919
+ isStickyRight = _this$props4.isStickyRight;
920
+ var top = viewState.top,
921
+ left = viewState.left;
922
+ var _this$metrics5 = this.metrics,
923
+ lastTop = _this$metrics5.lastTop,
924
+ lastLeft = _this$metrics5.lastLeft;
925
+
926
+ if (top != null) {
927
+ this.isStuckToBottom = isStickyBottom && top >= lastTop;
928
+ }
1066
929
 
1067
- var edits = [];
1068
- ranges.forEach(range => {
1069
- for (var x = 0; x < tableWidth; x += 1) {
1070
- for (var y = 0; y < tableHeight; y += 1) {
1071
- edits.push({
1072
- x: range.startColumn + x,
1073
- y: range.startRow + y,
1074
- text: value[y][x]
1075
- });
1076
- }
1077
- }
1078
- });
1079
- yield model.setValues(edits);
1080
- } catch (e) {
1081
- var {
1082
- onError
1083
- } = _this.props;
1084
- onError(e);
930
+ if (left != null) {
931
+ this.isStuckToRight = isStickyRight && left >= lastLeft;
1085
932
  }
1086
- })();
1087
- }
1088
933
 
1089
- setValueForCell(column, row, value) {
1090
- var {
1091
- model
1092
- } = this.props;
1093
- var modelColumn = this.getModelColumn(column);
1094
- var modelRow = this.getModelRow(row);
934
+ this.setState(viewState);
1095
935
 
1096
- if (model.isValidForCell(modelColumn, modelRow, value)) {
1097
- model.setValueForCell(modelColumn, modelRow, value);
936
+ if (forceUpdate) {
937
+ this.forceUpdate();
938
+ }
1098
939
  }
1099
- }
940
+ /**
941
+ * Start editing the data at the given index
942
+ *
943
+ * @param {number} column The visible column index to start editing
944
+ * @param {number} row The visible row index to start editing
945
+ * @param {boolean} isQuickEdit If this is a quick edit (the arrow keys can commit)
946
+ * @param {number[]|null} selectionRange The tuple [start,end] text selection range of the value to select when editing
947
+ * @param {string?} value The value to start with in the edit field. Leave undefined to use the current value.
948
+ */
1100
949
 
1101
- setValueForRanges(ranges, value) {
1102
- var {
1103
- model
1104
- } = this.props;
1105
- var {
1106
- movedColumns,
1107
- movedRows
1108
- } = this.state;
1109
- var modelRanges = GridUtils.getModelRanges(ranges, movedColumns, movedRows);
1110
- model.setValueForRanges(modelRanges, value);
1111
- }
950
+ }, {
951
+ key: "startEditing",
952
+ value: function startEditing(column, row) {
953
+ var isQuickEdit = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
954
+ var selectionRange = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
955
+ var value = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : undefined;
956
+ var model = this.props.model;
957
+ var modelColumn = this.getModelColumn(column);
958
+ var modelRow = this.getModelRow(row);
959
+ var cell = {
960
+ column: column,
961
+ row: row,
962
+ selectionRange: selectionRange,
963
+ value: value !== undefined ? value : model.editValueForCell(modelColumn, modelRow),
964
+ isQuickEdit: isQuickEdit
965
+ };
966
+ this.setState({
967
+ editingCell: cell,
968
+ cursorColumn: column,
969
+ cursorRow: row
970
+ });
971
+ this.moveViewToCell(column, row);
972
+ }
973
+ }, {
974
+ key: "isValidForCell",
975
+ value: function isValidForCell(column, row, value) {
976
+ var model = this.props.model;
977
+ var modelColumn = this.getModelColumn(column);
978
+ var modelRow = this.getModelRow(row);
979
+ return model.isValidForCell(modelColumn, modelRow, value);
980
+ }
981
+ /**
982
+ * Paste a value with the current selection
983
+ * It first needs to validate that the pasted table is valid for the given selection.
984
+ * Also may update selection if single cells are selected and a table is pasted.
985
+ * @param {string[][] | string} value Table or a string that is being pasted
986
+ */
1112
987
 
1113
- isSelected(row, column) {
1114
- var {
1115
- selectedRanges
1116
- } = this.state;
988
+ }, {
989
+ key: "pasteValue",
990
+ value: function () {
991
+ var _pasteValue = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(value) {
992
+ var model, _this$state7, movedColumns, movedRows, selectedRanges, _edits, modelRanges, tableHeight, tableWidth, columnCount, rowCount, ranges, edits, onError;
993
+
994
+ return regeneratorRuntime.wrap(function _callee$(_context) {
995
+ while (1) {
996
+ switch (_context.prev = _context.next) {
997
+ case 0:
998
+ model = this.props.model;
999
+ _this$state7 = this.state, movedColumns = _this$state7.movedColumns, movedRows = _this$state7.movedRows, selectedRanges = _this$state7.selectedRanges;
1000
+ _context.prev = 2;
1001
+
1002
+ if (!(!model.isEditable || !selectedRanges.every(function (range) {
1003
+ return model.isEditableRange(range);
1004
+ }))) {
1005
+ _context.next = 5;
1006
+ break;
1007
+ }
1008
+
1009
+ throw new PasteError("Can't paste in to read-only area.");
1010
+
1011
+ case 5:
1012
+ if (!(selectedRanges.length <= 0)) {
1013
+ _context.next = 7;
1014
+ break;
1015
+ }
1016
+
1017
+ throw new PasteError('Select an area to paste to.');
1018
+
1019
+ case 7:
1020
+ if (!(typeof value === 'string')) {
1021
+ _context.next = 14;
1022
+ break;
1023
+ }
1024
+
1025
+ // Just paste the value into all the selected cells
1026
+ _edits = [];
1027
+ modelRanges = GridUtils.getModelRanges(selectedRanges, movedColumns, movedRows);
1028
+ GridRange.forEachCell(modelRanges, function (x, y) {
1029
+ _edits.push({
1030
+ x: x,
1031
+ y: y,
1032
+ text: value
1033
+ });
1034
+ });
1035
+ _context.next = 13;
1036
+ return model.setValues(_edits);
1037
+
1038
+ case 13:
1039
+ return _context.abrupt("return");
1040
+
1041
+ case 14:
1042
+ // Otherwise it's a table of data
1043
+ tableHeight = value.length;
1044
+ tableWidth = value[0].length;
1045
+ columnCount = model.columnCount, rowCount = model.rowCount;
1046
+ ranges = selectedRanges; // If each cell is a single selection, we need to update the selection to map to the newly pasted data
1047
+
1048
+ if (ranges.every(function (range) {
1049
+ return GridRange.cellCount([range]) === 1 && range.startColumn + tableWidth <= columnCount && range.startRow + tableHeight <= rowCount;
1050
+ })) {
1051
+ // Remap the selected ranges
1052
+ ranges = ranges.map(function (range) {
1053
+ return new GridRange(range.startColumn, range.startRow, range.startColumn + tableWidth - 1, range.startRow + tableHeight - 1);
1054
+ });
1055
+ this.setSelectedRanges(ranges);
1056
+ }
1057
+
1058
+ if (ranges.every(function (range) {
1059
+ return GridRange.rowCount([range]) === tableHeight && GridRange.columnCount([range]) === tableWidth;
1060
+ })) {
1061
+ _context.next = 21;
1062
+ break;
1063
+ }
1064
+
1065
+ throw new PasteError('Copy and paste area are not same size.');
1066
+
1067
+ case 21:
1068
+ edits = [];
1069
+ ranges.forEach(function (range) {
1070
+ for (var x = 0; x < tableWidth; x += 1) {
1071
+ for (var y = 0; y < tableHeight; y += 1) {
1072
+ edits.push({
1073
+ x: range.startColumn + x,
1074
+ y: range.startRow + y,
1075
+ text: value[y][x]
1076
+ });
1077
+ }
1078
+ }
1079
+ });
1080
+ _context.next = 25;
1081
+ return model.setValues(edits);
1082
+
1083
+ case 25:
1084
+ _context.next = 31;
1085
+ break;
1086
+
1087
+ case 27:
1088
+ _context.prev = 27;
1089
+ _context.t0 = _context["catch"](2);
1090
+ onError = this.props.onError;
1091
+ onError(_context.t0);
1092
+
1093
+ case 31:
1094
+ case "end":
1095
+ return _context.stop();
1096
+ }
1097
+ }
1098
+ }, _callee, this, [[2, 27]]);
1099
+ }));
1117
1100
 
1118
- for (var i = 0; i < selectedRanges.length; i += 1) {
1119
- var selectedRange = selectedRanges[i];
1120
- var rowSelected = selectedRange.startRow === null || selectedRange.startRow <= row && row <= selectedRange.endRow;
1121
- var columnSelected = selectedRange.startColumn === null || selectedRange.startColumn <= column && column <= selectedRange.endColumn;
1101
+ function pasteValue(_x) {
1102
+ return _pasteValue.apply(this, arguments);
1103
+ }
1122
1104
 
1123
- if (rowSelected && columnSelected) {
1124
- return true;
1105
+ return pasteValue;
1106
+ }()
1107
+ }, {
1108
+ key: "setValueForCell",
1109
+ value: function setValueForCell(column, row, value) {
1110
+ var model = this.props.model;
1111
+ var modelColumn = this.getModelColumn(column);
1112
+ var modelRow = this.getModelRow(row);
1113
+
1114
+ if (model.isValidForCell(modelColumn, modelRow, value)) {
1115
+ model.setValueForCell(modelColumn, modelRow, value);
1125
1116
  }
1126
1117
  }
1118
+ }, {
1119
+ key: "setValueForRanges",
1120
+ value: function setValueForRanges(ranges, value) {
1121
+ var model = this.props.model;
1122
+ var _this$state8 = this.state,
1123
+ movedColumns = _this$state8.movedColumns,
1124
+ movedRows = _this$state8.movedRows;
1125
+ var modelRanges = GridUtils.getModelRanges(ranges, movedColumns, movedRows);
1126
+ model.setValueForRanges(modelRanges, value);
1127
+ }
1128
+ }, {
1129
+ key: "isSelected",
1130
+ value: function isSelected(row, column) {
1131
+ var selectedRanges = this.state.selectedRanges;
1132
+
1133
+ for (var i = 0; i < selectedRanges.length; i += 1) {
1134
+ var selectedRange = selectedRanges[i];
1135
+ var rowSelected = selectedRange.startRow === null || selectedRange.startRow <= row && row <= selectedRange.endRow;
1136
+ var columnSelected = selectedRange.startColumn === null || selectedRange.startColumn <= column && column <= selectedRange.endColumn;
1137
+
1138
+ if (rowSelected && columnSelected) {
1139
+ return true;
1140
+ }
1141
+ }
1127
1142
 
1128
- return false;
1129
- }
1130
-
1131
- addDocumentCursor() {
1132
- var cursor = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
1133
- if (this.documentCursor === Grid.getCursorClassName(cursor)) return;
1134
- document.documentElement.classList.remove(this.documentCursor);
1135
- this.documentCursor = Grid.getCursorClassName(cursor);
1136
- document.documentElement.classList.add(this.documentCursor);
1137
- document.documentElement.classList.add('grid-block-events');
1138
- }
1139
-
1140
- removeDocumentCursor() {
1141
- if (this.documentCursor) {
1143
+ return false;
1144
+ }
1145
+ }, {
1146
+ key: "addDocumentCursor",
1147
+ value: function addDocumentCursor() {
1148
+ var cursor = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
1149
+ if (this.documentCursor === Grid.getCursorClassName(cursor)) return;
1142
1150
  document.documentElement.classList.remove(this.documentCursor);
1143
- document.documentElement.classList.remove('grid-block-events');
1144
- this.documentCursor = null;
1151
+ this.documentCursor = Grid.getCursorClassName(cursor);
1152
+ document.documentElement.classList.add(this.documentCursor);
1153
+ document.documentElement.classList.add('grid-block-events');
1145
1154
  }
1146
- }
1147
-
1148
- startDragTimer(event) {
1149
- this.stopDragTimer();
1150
- var mouseEvent = new MouseEvent('custom', event);
1151
- this.dragTimer = setTimeout(() => {
1152
- this.handleMouseDrag(mouseEvent);
1153
- }, Grid.dragTimeout);
1154
- }
1155
-
1156
- stopDragTimer() {
1157
- if (this.dragTimer) {
1158
- clearTimeout(this.dragTimer);
1159
- this.dragTimer = null;
1155
+ }, {
1156
+ key: "removeDocumentCursor",
1157
+ value: function removeDocumentCursor() {
1158
+ if (this.documentCursor) {
1159
+ document.documentElement.classList.remove(this.documentCursor);
1160
+ document.documentElement.classList.remove('grid-block-events');
1161
+ this.documentCursor = null;
1162
+ }
1160
1163
  }
1161
- }
1162
- /**
1163
- * When scrolling you've have to re-draw the whole canvas. As a consequence, all these drawing methods
1164
- * must be very quick.
1165
- */
1166
-
1167
-
1168
- drawCanvas() {
1169
- var metrics = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.updateMetrics();
1170
- var {
1171
- left,
1172
- top,
1173
- cursorColumn,
1174
- cursorRow,
1175
- draggingColumn,
1176
- draggingColumnOffset,
1177
- draggingColumnSeparator,
1178
- draggingRow,
1179
- draggingRowOffset,
1180
- draggingRowSeparator,
1181
- editingCell,
1182
- isDraggingHorizontalScrollBar,
1183
- isDraggingVerticalScrollBar,
1184
- isDragging,
1185
- mouseX,
1186
- mouseY,
1187
- selectedRanges
1188
- } = this.state;
1189
- var {
1190
- model,
1191
- stateOverride
1192
- } = this.props;
1193
- var {
1194
- renderer
1195
- } = this;
1196
- var context = this.canvasContext;
1197
- var theme = this.getTheme();
1198
- var width = this.canvas.clientWidth;
1199
- var height = this.canvas.clientHeight;
1200
-
1201
- var renderState = _objectSpread({
1202
- left,
1203
- top,
1204
- width,
1205
- height,
1206
- context,
1207
- theme,
1208
- model,
1209
- metrics,
1210
- mouseX,
1211
- mouseY,
1212
- selectedRanges,
1213
- draggingColumn,
1214
- draggingColumnOffset,
1215
- draggingColumnSeparator,
1216
- draggingRow,
1217
- draggingRowOffset,
1218
- draggingRowSeparator,
1219
- editingCell,
1220
- isDraggingHorizontalScrollBar,
1221
- isDraggingVerticalScrollBar,
1222
- isDragging,
1223
- cursorColumn,
1224
- cursorRow
1225
- }, stateOverride);
1226
-
1227
- context.save();
1228
- renderer.drawCanvas(renderState);
1229
- context.restore();
1230
- }
1164
+ }, {
1165
+ key: "startDragTimer",
1166
+ value: function startDragTimer(event) {
1167
+ var _this5 = this;
1168
+
1169
+ this.stopDragTimer();
1170
+ var mouseEvent = new MouseEvent('custom', event);
1171
+ this.dragTimer = setTimeout(function () {
1172
+ _this5.handleMouseDrag(mouseEvent);
1173
+ }, Grid.dragTimeout);
1174
+ }
1175
+ }, {
1176
+ key: "stopDragTimer",
1177
+ value: function stopDragTimer() {
1178
+ if (this.dragTimer) {
1179
+ clearTimeout(this.dragTimer);
1180
+ this.dragTimer = null;
1181
+ }
1182
+ }
1183
+ /**
1184
+ * When scrolling you've have to re-draw the whole canvas. As a consequence, all these drawing methods
1185
+ * must be very quick.
1186
+ */
1231
1187
 
1232
- focus() {
1233
- this.canvas.focus();
1234
- }
1188
+ }, {
1189
+ key: "drawCanvas",
1190
+ value: function drawCanvas() {
1191
+ var metrics = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.updateMetrics();
1192
+ var _this$state9 = this.state,
1193
+ left = _this$state9.left,
1194
+ top = _this$state9.top,
1195
+ cursorColumn = _this$state9.cursorColumn,
1196
+ cursorRow = _this$state9.cursorRow,
1197
+ draggingColumn = _this$state9.draggingColumn,
1198
+ draggingColumnOffset = _this$state9.draggingColumnOffset,
1199
+ draggingColumnSeparator = _this$state9.draggingColumnSeparator,
1200
+ draggingRow = _this$state9.draggingRow,
1201
+ draggingRowOffset = _this$state9.draggingRowOffset,
1202
+ draggingRowSeparator = _this$state9.draggingRowSeparator,
1203
+ editingCell = _this$state9.editingCell,
1204
+ isDraggingHorizontalScrollBar = _this$state9.isDraggingHorizontalScrollBar,
1205
+ isDraggingVerticalScrollBar = _this$state9.isDraggingVerticalScrollBar,
1206
+ isDragging = _this$state9.isDragging,
1207
+ mouseX = _this$state9.mouseX,
1208
+ mouseY = _this$state9.mouseY,
1209
+ selectedRanges = _this$state9.selectedRanges;
1210
+ var _this$props5 = this.props,
1211
+ model = _this$props5.model,
1212
+ stateOverride = _this$props5.stateOverride;
1213
+ var renderer = this.renderer;
1214
+ var context = this.canvasContext;
1215
+ var theme = this.getTheme();
1216
+ var width = this.canvas.clientWidth;
1217
+ var height = this.canvas.clientHeight;
1218
+
1219
+ var renderState = _objectSpread({
1220
+ left: left,
1221
+ top: top,
1222
+ width: width,
1223
+ height: height,
1224
+ context: context,
1225
+ theme: theme,
1226
+ model: model,
1227
+ metrics: metrics,
1228
+ mouseX: mouseX,
1229
+ mouseY: mouseY,
1230
+ selectedRanges: selectedRanges,
1231
+ draggingColumn: draggingColumn,
1232
+ draggingColumnOffset: draggingColumnOffset,
1233
+ draggingColumnSeparator: draggingColumnSeparator,
1234
+ draggingRow: draggingRow,
1235
+ draggingRowOffset: draggingRowOffset,
1236
+ draggingRowSeparator: draggingRowSeparator,
1237
+ editingCell: editingCell,
1238
+ isDraggingHorizontalScrollBar: isDraggingHorizontalScrollBar,
1239
+ isDraggingVerticalScrollBar: isDraggingVerticalScrollBar,
1240
+ isDragging: isDragging,
1241
+ cursorColumn: cursorColumn,
1242
+ cursorRow: cursorRow
1243
+ }, stateOverride);
1244
+
1245
+ context.save();
1246
+ renderer.drawCanvas(renderState);
1247
+ context.restore();
1248
+ }
1249
+ }, {
1250
+ key: "focus",
1251
+ value: function focus() {
1252
+ this.canvas.focus();
1253
+ }
1254
+ }, {
1255
+ key: "isFocused",
1256
+ value: function isFocused() {
1257
+ return document.activeElement === this.canvas;
1258
+ }
1259
+ }, {
1260
+ key: "handleClick",
1261
+ value: function handleClick(event) {
1262
+ var gridPoint = this.getGridPointFromEvent(event);
1263
+ var mouseHandlers = this.getMouseHandlers();
1264
+
1265
+ for (var i = 0; i < mouseHandlers.length; i += 1) {
1266
+ var mouseHandler = mouseHandlers[i];
1267
+
1268
+ if (mouseHandler.onClick(gridPoint, this, event)) {
1269
+ event.stopPropagation();
1270
+ event.preventDefault();
1271
+ break;
1272
+ }
1273
+ }
1235
1274
 
1236
- isFocused() {
1237
- return document.activeElement === this.canvas;
1238
- }
1275
+ this.canvas.focus();
1276
+ }
1277
+ }, {
1278
+ key: "handleContextMenu",
1279
+ value: function handleContextMenu(event) {
1280
+ var gridPoint = this.getGridPointFromEvent(event);
1281
+ var mouseHandlers = this.getMouseHandlers();
1282
+
1283
+ for (var i = 0; i < mouseHandlers.length; i += 1) {
1284
+ var mouseHandler = mouseHandlers[i];
1285
+
1286
+ if (mouseHandler.onContextMenu(gridPoint, this, event)) {
1287
+ event.stopPropagation();
1288
+ event.preventDefault();
1289
+ break;
1290
+ }
1291
+ }
1292
+ }
1293
+ }, {
1294
+ key: "handleKeyDown",
1295
+ value: function handleKeyDown(e) {
1296
+ var keyHandlers = this.getKeyHandlers();
1239
1297
 
1240
- handleClick(event) {
1241
- var gridPoint = this.getGridPointFromEvent(event);
1242
- var mouseHandlers = this.getMouseHandlers();
1298
+ for (var i = 0; i < keyHandlers.length; i += 1) {
1299
+ var keyHandler = keyHandlers[i];
1300
+ var result = keyHandler.onDown(e, this);
1243
1301
 
1244
- for (var i = 0; i < mouseHandlers.length; i += 1) {
1245
- var mouseHandler = mouseHandlers[i];
1302
+ if (result) {
1303
+ var _result$stopPropagati, _result$preventDefaul;
1246
1304
 
1247
- if (mouseHandler.onClick(gridPoint, this, event)) {
1248
- event.stopPropagation();
1249
- event.preventDefault();
1250
- break;
1305
+ if ((_result$stopPropagati = result === null || result === void 0 ? void 0 : result.stopPropagation) !== null && _result$stopPropagati !== void 0 ? _result$stopPropagati : true) e.stopPropagation();
1306
+ if ((_result$preventDefaul = result === null || result === void 0 ? void 0 : result.preventDefault) !== null && _result$preventDefaul !== void 0 ? _result$preventDefaul : true) e.preventDefault();
1307
+ break;
1308
+ }
1251
1309
  }
1252
1310
  }
1311
+ /**
1312
+ * Notify all of the mouse handlers for this grid of a mouse event.
1313
+ * @param {String} functionName The name of the function in the mouse handler to call
1314
+ * @param {MouseEvent} event The mouse event to notify
1315
+ * @param {Boolean} updateCoordinates Whether to update the mouse coordinates
1316
+ * @param {Boolean} addCursorToDocument Whether to add a cursor overlay or not (for dragging)
1317
+ */
1253
1318
 
1254
- this.canvas.focus();
1255
- }
1256
-
1257
- handleContextMenu(event) {
1258
- var gridPoint = this.getGridPointFromEvent(event);
1259
- var mouseHandlers = this.getMouseHandlers();
1319
+ }, {
1320
+ key: "notifyMouseHandlers",
1321
+ value: function notifyMouseHandlers(functionName, event) {
1322
+ var updateCoordinates = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
1323
+ var addCursorToDocument = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
1324
+ var gridPoint = this.getGridPointFromEvent(event);
1325
+ var mouseHandlers = this.getMouseHandlers();
1326
+ var cursor = null;
1260
1327
 
1261
- for (var i = 0; i < mouseHandlers.length; i += 1) {
1262
- var mouseHandler = mouseHandlers[i];
1328
+ for (var i = 0; i < mouseHandlers.length; i += 1) {
1329
+ var mouseHandler = mouseHandlers[i];
1330
+ var result = mouseHandler[functionName] && mouseHandler[functionName](gridPoint, this, event);
1263
1331
 
1264
- if (mouseHandler.onContextMenu(gridPoint, this, event)) {
1265
- event.stopPropagation();
1266
- event.preventDefault();
1267
- break;
1268
- }
1269
- }
1270
- }
1332
+ if (result) {
1333
+ var _result$stopPropagati2, _result$preventDefaul2;
1271
1334
 
1272
- handleKeyDown(e) {
1273
- var keyHandlers = this.getKeyHandlers();
1335
+ if (mouseHandler.cursor != null) {
1336
+ cursor = mouseHandler.cursor;
1274
1337
 
1275
- for (var i = 0; i < keyHandlers.length; i += 1) {
1276
- var keyHandler = keyHandlers[i];
1277
- var result = keyHandler.onDown(e, this);
1338
+ if (addCursorToDocument) {
1339
+ this.addDocumentCursor(cursor);
1340
+ }
1341
+ } // result is bool or object, events are stopped by default
1278
1342
 
1279
- if (result) {
1280
- var _result$stopPropagati, _result$preventDefaul;
1281
1343
 
1282
- if ((_result$stopPropagati = result === null || result === void 0 ? void 0 : result.stopPropagation) !== null && _result$stopPropagati !== void 0 ? _result$stopPropagati : true) e.stopPropagation();
1283
- if ((_result$preventDefaul = result === null || result === void 0 ? void 0 : result.preventDefault) !== null && _result$preventDefaul !== void 0 ? _result$preventDefaul : true) e.preventDefault();
1284
- break;
1344
+ if ((_result$stopPropagati2 = result === null || result === void 0 ? void 0 : result.stopPropagation) !== null && _result$stopPropagati2 !== void 0 ? _result$stopPropagati2 : true) event.stopPropagation();
1345
+ if ((_result$preventDefaul2 = result === null || result === void 0 ? void 0 : result.preventDefault) !== null && _result$preventDefaul2 !== void 0 ? _result$preventDefaul2 : true) event.preventDefault();
1346
+ break;
1347
+ }
1285
1348
  }
1286
- }
1287
- }
1288
- /**
1289
- * Notify all of the mouse handlers for this grid of a mouse event.
1290
- * @param {String} functionName The name of the function in the mouse handler to call
1291
- * @param {MouseEvent} event The mouse event to notify
1292
- * @param {Boolean} updateCoordinates Whether to update the mouse coordinates
1293
- * @param {Boolean} addCursorToDocument Whether to add a cursor overlay or not (for dragging)
1294
- */
1295
-
1296
-
1297
- notifyMouseHandlers(functionName, event) {
1298
- var updateCoordinates = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
1299
- var addCursorToDocument = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
1300
- var gridPoint = this.getGridPointFromEvent(event);
1301
- var mouseHandlers = this.getMouseHandlers();
1302
- var cursor = null;
1303
-
1304
- for (var i = 0; i < mouseHandlers.length; i += 1) {
1305
- var mouseHandler = mouseHandlers[i];
1306
- var result = mouseHandler[functionName] && mouseHandler[functionName](gridPoint, this, event);
1307
-
1308
- if (result) {
1309
- var _result$stopPropagati2, _result$preventDefaul2;
1310
-
1311
- if (mouseHandler.cursor != null) {
1312
- ({
1313
- cursor
1314
- } = mouseHandler);
1315
-
1316
- if (addCursorToDocument) {
1317
- this.addDocumentCursor(cursor);
1318
- }
1319
- } // result is bool or object, events are stopped by default
1320
1349
 
1350
+ this.setState({
1351
+ cursor: cursor
1352
+ });
1321
1353
 
1322
- if ((_result$stopPropagati2 = result === null || result === void 0 ? void 0 : result.stopPropagation) !== null && _result$stopPropagati2 !== void 0 ? _result$stopPropagati2 : true) event.stopPropagation();
1323
- if ((_result$preventDefaul2 = result === null || result === void 0 ? void 0 : result.preventDefault) !== null && _result$preventDefaul2 !== void 0 ? _result$preventDefaul2 : true) event.preventDefault();
1324
- break;
1354
+ if (updateCoordinates) {
1355
+ var x = gridPoint.x,
1356
+ y = gridPoint.y;
1357
+ this.setState({
1358
+ mouseX: x,
1359
+ mouseY: y
1360
+ });
1325
1361
  }
1326
1362
  }
1363
+ }, {
1364
+ key: "handleMouseDown",
1365
+ value: function handleMouseDown(event) {
1366
+ window.addEventListener('mousemove', this.handleMouseDrag, true);
1367
+ window.addEventListener('mouseup', this.handleMouseUp, true);
1368
+
1369
+ if (event.button != null && event.button !== 0) {
1370
+ return;
1371
+ }
1327
1372
 
1328
- this.setState({
1329
- cursor
1330
- });
1331
-
1332
- if (updateCoordinates) {
1333
- var {
1334
- x,
1335
- y
1336
- } = gridPoint;
1373
+ this.notifyMouseHandlers(GridMouseHandler.FUNCTION_NAMES.DOWN, event);
1374
+ this.startDragTimer(event);
1375
+ }
1376
+ }, {
1377
+ key: "handleDoubleClick",
1378
+ value: function handleDoubleClick(event) {
1379
+ this.notifyMouseHandlers(GridMouseHandler.FUNCTION_NAMES.DOUBLE_CLICK, event);
1380
+ }
1381
+ }, {
1382
+ key: "handleMouseMove",
1383
+ value: function handleMouseMove(event) {
1384
+ this.notifyMouseHandlers(GridMouseHandler.FUNCTION_NAMES.MOVE, event);
1385
+ }
1386
+ }, {
1387
+ key: "handleMouseLeave",
1388
+ value: function handleMouseLeave(event) {
1389
+ this.notifyMouseHandlers(GridMouseHandler.FUNCTION_NAMES.LEAVE, event, false);
1337
1390
  this.setState({
1338
- mouseX: x,
1339
- mouseY: y
1391
+ mouseX: null,
1392
+ mouseY: null
1340
1393
  });
1341
1394
  }
1342
- }
1343
-
1344
- handleMouseDown(event) {
1345
- window.addEventListener('mousemove', this.handleMouseDrag, true);
1346
- window.addEventListener('mouseup', this.handleMouseUp, true);
1347
-
1348
- if (event.button != null && event.button !== 0) {
1349
- return;
1395
+ }, {
1396
+ key: "handleMouseDrag",
1397
+ value: function handleMouseDrag(event) {
1398
+ this.setState({
1399
+ isDragging: true
1400
+ });
1401
+ this.notifyMouseHandlers(GridMouseHandler.FUNCTION_NAMES.DRAG, event, true, true);
1402
+ this.stopDragTimer();
1350
1403
  }
1404
+ }, {
1405
+ key: "handleMouseUp",
1406
+ value: function handleMouseUp(event) {
1407
+ window.removeEventListener('mousemove', this.handleMouseDrag, true);
1408
+ window.removeEventListener('mouseup', this.handleMouseUp, true);
1409
+
1410
+ if (event.button != null && event.button !== 0) {
1411
+ return;
1412
+ }
1351
1413
 
1352
- this.notifyMouseHandlers(GridMouseHandler.FUNCTION_NAMES.DOWN, event);
1353
- this.startDragTimer(event);
1354
- }
1355
-
1356
- handleDoubleClick(event) {
1357
- this.notifyMouseHandlers(GridMouseHandler.FUNCTION_NAMES.DOUBLE_CLICK, event);
1358
- }
1359
-
1360
- handleMouseMove(event) {
1361
- this.notifyMouseHandlers(GridMouseHandler.FUNCTION_NAMES.MOVE, event);
1362
- }
1363
-
1364
- handleMouseLeave(event) {
1365
- this.notifyMouseHandlers(GridMouseHandler.FUNCTION_NAMES.LEAVE, event, false);
1366
- this.setState({
1367
- mouseX: null,
1368
- mouseY: null
1369
- });
1370
- }
1371
-
1372
- handleMouseDrag(event) {
1373
- this.setState({
1374
- isDragging: true
1375
- });
1376
- this.notifyMouseHandlers(GridMouseHandler.FUNCTION_NAMES.DRAG, event, true, true);
1377
- this.stopDragTimer();
1378
- }
1379
-
1380
- handleMouseUp(event) {
1381
- window.removeEventListener('mousemove', this.handleMouseDrag, true);
1382
- window.removeEventListener('mouseup', this.handleMouseUp, true);
1383
-
1384
- if (event.button != null && event.button !== 0) {
1385
- return;
1414
+ this.notifyMouseHandlers(GridMouseHandler.FUNCTION_NAMES.UP, event, false);
1415
+ this.stopDragTimer();
1416
+ this.removeDocumentCursor();
1386
1417
  }
1387
-
1388
- this.notifyMouseHandlers(GridMouseHandler.FUNCTION_NAMES.UP, event, false);
1389
- this.stopDragTimer();
1390
- this.removeDocumentCursor();
1391
- }
1392
-
1393
- handleResize() {
1394
- /**
1395
- * We need to always redraw the canvas in the same frame as the updateCanvasScale
1396
- * because it clears the canvas by nature of direct dom manipulation. However,
1397
- * We also need to verify the state/metrics, which we currently have no way
1398
- * of doing outside of a full componentDidUpdate() call, so we force the update.
1399
- * Ideally, we could verify state/metrics without the forced update.
1400
- */
1401
- this.updateCanvasScale();
1402
- this.updateCanvas();
1403
- this.forceUpdate();
1404
- }
1405
-
1406
- handleWheel(e) {
1407
- this.notifyMouseHandlers(GridMouseHandler.FUNCTION_NAMES.WHEEL, e);
1408
-
1409
- if (e.defaultPrevented) {
1410
- return;
1418
+ }, {
1419
+ key: "handleResize",
1420
+ value: function handleResize() {
1421
+ /**
1422
+ * We need to always redraw the canvas in the same frame as the updateCanvasScale
1423
+ * because it clears the canvas by nature of direct dom manipulation. However,
1424
+ * We also need to verify the state/metrics, which we currently have no way
1425
+ * of doing outside of a full componentDidUpdate() call, so we force the update.
1426
+ * Ideally, we could verify state/metrics without the forced update.
1427
+ */
1428
+ this.updateCanvasScale();
1429
+ this.updateCanvas();
1430
+ this.forceUpdate();
1411
1431
  }
1432
+ }, {
1433
+ key: "handleWheel",
1434
+ value: function handleWheel(e) {
1435
+ this.notifyMouseHandlers(GridMouseHandler.FUNCTION_NAMES.WHEEL, e);
1412
1436
 
1413
- var {
1414
- metricCalculator,
1415
- metrics
1416
- } = this;
1417
- var metricState = this.getMetricState();
1418
- var {
1419
- lastTop,
1420
- lastLeft
1421
- } = metrics;
1422
- var {
1423
- top,
1424
- left,
1425
- topOffset,
1426
- leftOffset
1427
- } = metrics;
1428
- var theme = this.getTheme();
1429
- var {
1430
- deltaX,
1431
- deltaY
1432
- } = GridUtils.getScrollDelta(e, metrics.barWidth, metrics.barHeight, metrics.rowHeight, metrics.rowHeight); // iterate through each column to determine column width and figure out how far to scroll
1433
- // get column width of next column to scroll to, and subract it from the remaining distance to travel
1434
-
1435
- while (deltaX !== 0) {
1436
- leftOffset += deltaX;
1437
- deltaX = 0; // no scrolling needed, at directional edge
1438
-
1439
- if (leftOffset > 0 && left >= lastLeft || leftOffset < 0 && left <= 0) {
1440
- leftOffset = 0;
1441
- break;
1437
+ if (e.defaultPrevented) {
1438
+ return;
1442
1439
  }
1443
1440
 
1444
- if (leftOffset > 0) {
1445
- var _metrics$visibleColum;
1441
+ var metricCalculator = this.metricCalculator,
1442
+ metrics = this.metrics;
1443
+ var metricState = this.getMetricState();
1444
+ var lastTop = metrics.lastTop,
1445
+ lastLeft = metrics.lastLeft;
1446
+ var top = metrics.top,
1447
+ left = metrics.left,
1448
+ topOffset = metrics.topOffset,
1449
+ leftOffset = metrics.leftOffset;
1450
+ var theme = this.getTheme();
1446
1451
 
1447
- // scroll right
1448
- // get width of next column
1449
- var columnWidth = (_metrics$visibleColum = metrics.visibleColumnWidths.get(left)) !== null && _metrics$visibleColum !== void 0 ? _metrics$visibleColum : metricCalculator.getVisibleColumnWidth(left, metricState);
1452
+ var _GridUtils$getScrollD = GridUtils.getScrollDelta(e, metrics.barWidth, metrics.barHeight, metrics.rowHeight, metrics.rowHeight),
1453
+ deltaX = _GridUtils$getScrollD.deltaX,
1454
+ deltaY = _GridUtils$getScrollD.deltaY; // iterate through each column to determine column width and figure out how far to scroll
1455
+ // get column width of next column to scroll to, and subract it from the remaining distance to travel
1450
1456
 
1451
- if (leftOffset >= columnWidth) {
1452
- // remove width from balance and advance by 1 column
1453
- deltaX = leftOffset - columnWidth;
1454
- leftOffset = 0;
1455
- left += 1;
1456
- } else if (theme.scrollSnapToColumn) {
1457
- // if there's still a balance to travel but its less then a column and snapping is on
1458
- leftOffset = 0;
1459
- left += 1;
1460
- }
1461
- } else if (leftOffset < 0) {
1462
- var _metrics$visibleColum2;
1463
1457
 
1464
- // scroll left
1465
- // get width of next column
1466
- var _columnWidth = (_metrics$visibleColum2 = metrics.visibleColumnWidths.get(left - 1)) !== null && _metrics$visibleColum2 !== void 0 ? _metrics$visibleColum2 : metricCalculator.getVisibleColumnWidth(left - 1, metricState);
1458
+ while (deltaX !== 0) {
1459
+ leftOffset += deltaX;
1460
+ deltaX = 0; // no scrolling needed, at directional edge
1467
1461
 
1468
- if (Math.abs(leftOffset) <= _columnWidth && theme.scrollSnapToColumn) {
1469
- // if there's still a balance to travel but its less then a column and snapping is on
1470
- leftOffset = 0;
1471
- left -= 1;
1472
- } else {
1473
- // remove width from balance and advance by 1 column
1474
- deltaX = leftOffset + _columnWidth;
1462
+ if (leftOffset > 0 && left >= lastLeft || leftOffset < 0 && left <= 0) {
1475
1463
  leftOffset = 0;
1476
- left -= 1;
1464
+ break;
1477
1465
  }
1478
- }
1479
- } // iterate through each row to determine row height and figure out how far to scroll
1480
- // get row height of next row to scroll to, and subract it from the remaining distance to travel
1481
-
1482
-
1483
- while (deltaY !== 0) {
1484
- topOffset += deltaY;
1485
- deltaY = 0; // no scrolling needed, at directional edge
1486
1466
 
1487
- if (topOffset > 0 && top >= lastTop || topOffset < 0 && top <= 0) {
1488
- topOffset = 0;
1489
- break;
1490
- }
1467
+ if (leftOffset > 0) {
1468
+ var _metrics$visibleColum;
1469
+
1470
+ // scroll right
1471
+ // get width of next column
1472
+ var columnWidth = (_metrics$visibleColum = metrics.visibleColumnWidths.get(left)) !== null && _metrics$visibleColum !== void 0 ? _metrics$visibleColum : metricCalculator.getVisibleColumnWidth(left, metricState);
1473
+
1474
+ if (leftOffset >= columnWidth) {
1475
+ // remove width from balance and advance by 1 column
1476
+ deltaX = leftOffset - columnWidth;
1477
+ leftOffset = 0;
1478
+ left += 1;
1479
+ } else if (theme.scrollSnapToColumn) {
1480
+ // if there's still a balance to travel but its less then a column and snapping is on
1481
+ leftOffset = 0;
1482
+ left += 1;
1483
+ }
1484
+ } else if (leftOffset < 0) {
1485
+ var _metrics$visibleColum2;
1486
+
1487
+ // scroll left
1488
+ // get width of next column
1489
+ var _columnWidth = (_metrics$visibleColum2 = metrics.visibleColumnWidths.get(left - 1)) !== null && _metrics$visibleColum2 !== void 0 ? _metrics$visibleColum2 : metricCalculator.getVisibleColumnWidth(left - 1, metricState);
1490
+
1491
+ if (Math.abs(leftOffset) <= _columnWidth && theme.scrollSnapToColumn) {
1492
+ // if there's still a balance to travel but its less then a column and snapping is on
1493
+ leftOffset = 0;
1494
+ left -= 1;
1495
+ } else {
1496
+ // remove width from balance and advance by 1 column
1497
+ deltaX = leftOffset + _columnWidth;
1498
+ leftOffset = 0;
1499
+ left -= 1;
1500
+ }
1501
+ }
1502
+ } // iterate through each row to determine row height and figure out how far to scroll
1503
+ // get row height of next row to scroll to, and subract it from the remaining distance to travel
1491
1504
 
1492
- if (topOffset > 0) {
1493
- var _metrics$visibleRowHe;
1494
1505
 
1495
- // scroll direction down
1496
- // get height of next row
1497
- var rowHeight = (_metrics$visibleRowHe = metrics.visibleRowHeights.get(top)) !== null && _metrics$visibleRowHe !== void 0 ? _metrics$visibleRowHe : metricCalculator.getVisibleRowHeight(top, metricState);
1506
+ while (deltaY !== 0) {
1507
+ topOffset += deltaY;
1508
+ deltaY = 0; // no scrolling needed, at directional edge
1498
1509
 
1499
- if (topOffset >= rowHeight) {
1500
- // remove height from balance and advance by 1 row
1501
- deltaY = topOffset - rowHeight;
1502
- topOffset = 0;
1503
- top += 1;
1504
- } else if (theme.scrollSnapToRow) {
1505
- // if there's still a balance to travel but its less then a row and snapping is on
1510
+ if (topOffset > 0 && top >= lastTop || topOffset < 0 && top <= 0) {
1506
1511
  topOffset = 0;
1507
- top += 1;
1512
+ break;
1508
1513
  }
1509
- } else if (topOffset < 0) {
1510
- var _metrics$visibleRowHe2;
1511
-
1512
- // scroll direction up
1513
- // get height of next row
1514
- var _rowHeight = (_metrics$visibleRowHe2 = metrics.visibleRowHeights.get(top - 1)) !== null && _metrics$visibleRowHe2 !== void 0 ? _metrics$visibleRowHe2 : metricCalculator.getVisibleRowHeight(top - 1, metricState);
1515
1514
 
1516
- if (Math.abs(topOffset) <= _rowHeight && theme.scrollSnapToRow) {
1517
- // if there's still a balance to travel but its less then a row and snapping is on
1518
- topOffset = 0;
1519
- top -= 1;
1520
- } else {
1521
- // remove height from balance and advance by 1 row
1522
- deltaY = topOffset + _rowHeight;
1523
- topOffset = 0;
1524
- top -= 1;
1515
+ if (topOffset > 0) {
1516
+ var _metrics$visibleRowHe;
1517
+
1518
+ // scroll direction down
1519
+ // get height of next row
1520
+ var rowHeight = (_metrics$visibleRowHe = metrics.visibleRowHeights.get(top)) !== null && _metrics$visibleRowHe !== void 0 ? _metrics$visibleRowHe : metricCalculator.getVisibleRowHeight(top, metricState);
1521
+
1522
+ if (topOffset >= rowHeight) {
1523
+ // remove height from balance and advance by 1 row
1524
+ deltaY = topOffset - rowHeight;
1525
+ topOffset = 0;
1526
+ top += 1;
1527
+ } else if (theme.scrollSnapToRow) {
1528
+ // if there's still a balance to travel but its less then a row and snapping is on
1529
+ topOffset = 0;
1530
+ top += 1;
1531
+ }
1532
+ } else if (topOffset < 0) {
1533
+ var _metrics$visibleRowHe2;
1534
+
1535
+ // scroll direction up
1536
+ // get height of next row
1537
+ var _rowHeight = (_metrics$visibleRowHe2 = metrics.visibleRowHeights.get(top - 1)) !== null && _metrics$visibleRowHe2 !== void 0 ? _metrics$visibleRowHe2 : metricCalculator.getVisibleRowHeight(top - 1, metricState);
1538
+
1539
+ if (Math.abs(topOffset) <= _rowHeight && theme.scrollSnapToRow) {
1540
+ // if there's still a balance to travel but its less then a row and snapping is on
1541
+ topOffset = 0;
1542
+ top -= 1;
1543
+ } else {
1544
+ // remove height from balance and advance by 1 row
1545
+ deltaY = topOffset + _rowHeight;
1546
+ topOffset = 0;
1547
+ top -= 1;
1548
+ }
1525
1549
  }
1526
1550
  }
1527
- }
1528
1551
 
1529
- this.setViewState({
1530
- top,
1531
- left,
1532
- leftOffset,
1533
- topOffset
1534
- });
1535
- e.stopPropagation();
1536
- e.preventDefault();
1537
- }
1552
+ this.setViewState({
1553
+ top: top,
1554
+ left: left,
1555
+ leftOffset: leftOffset,
1556
+ topOffset: topOffset
1557
+ });
1558
+ e.stopPropagation();
1559
+ e.preventDefault();
1560
+ }
1561
+ }, {
1562
+ key: "handleEditCellCancel",
1563
+ value: function handleEditCellCancel() {
1564
+ this.setState({
1565
+ editingCell: null
1566
+ });
1567
+ this.focus();
1568
+ }
1569
+ }, {
1570
+ key: "handleEditCellChange",
1571
+ value: function handleEditCellChange(value) {
1572
+ this.setState(function (_ref) {
1573
+ var editingCell = _ref.editingCell;
1574
+ return {
1575
+ editingCell: _objectSpread(_objectSpread({}, editingCell), {}, {
1576
+ value: value
1577
+ })
1578
+ };
1579
+ });
1580
+ }
1581
+ }, {
1582
+ key: "handleEditCellCommit",
1583
+ value: function handleEditCellCommit(value) {
1584
+ var _ref2 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
1585
+ _ref2$direction = _ref2.direction,
1586
+ direction = _ref2$direction === void 0 ? GridRange.SELECTION_DIRECTION.DOWN : _ref2$direction,
1587
+ _ref2$fillRange = _ref2.fillRange,
1588
+ fillRange = _ref2$fillRange === void 0 ? false : _ref2$fillRange;
1589
+
1590
+ var _this$state10 = this.state,
1591
+ column = _this$state10.cursorColumn,
1592
+ row = _this$state10.cursorRow,
1593
+ selectedRanges = _this$state10.selectedRanges;
1594
+
1595
+ if (!this.isValidForCell(column, row, value)) {
1596
+ // Don't allow an invalid value to be commited, the editing cell should show an error
1597
+ if (direction == null) {
1598
+ // If they clicked off of the editing cell, just remove focus
1599
+ this.setState({
1600
+ editingCell: null
1601
+ });
1602
+ }
1538
1603
 
1539
- handleEditCellCancel() {
1540
- this.setState({
1541
- editingCell: null
1542
- });
1543
- this.focus();
1544
- }
1604
+ return;
1605
+ }
1545
1606
 
1546
- handleEditCellChange(value) {
1547
- this.setState((_ref) => {
1548
- var {
1549
- editingCell
1550
- } = _ref;
1551
- return {
1552
- editingCell: _objectSpread(_objectSpread({}, editingCell), {}, {
1553
- value
1554
- })
1555
- };
1556
- });
1557
- }
1607
+ if (fillRange) {
1608
+ this.setValueForRanges(selectedRanges, value);
1609
+ } else {
1610
+ this.setValueForCell(column, row, value);
1611
+ }
1558
1612
 
1559
- handleEditCellCommit(value) {
1560
- var {
1561
- direction = GridRange.SELECTION_DIRECTION.DOWN,
1562
- fillRange = false
1563
- } = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
1564
- var {
1565
- cursorColumn: column,
1566
- cursorRow: row,
1567
- selectedRanges
1568
- } = this.state;
1569
-
1570
- if (!this.isValidForCell(column, row, value)) {
1571
- // Don't allow an invalid value to be commited, the editing cell should show an error
1572
- if (direction == null) {
1573
- // If they clicked off of the editing cell, just remove focus
1574
- this.setState({
1575
- editingCell: null
1576
- });
1613
+ if (direction != null) {
1614
+ this.moveCursorInDirection(direction);
1577
1615
  }
1578
1616
 
1579
- return;
1617
+ this.setState({
1618
+ editingCell: null
1619
+ });
1620
+ this.focus();
1580
1621
  }
1622
+ }, {
1623
+ key: "renderInputField",
1624
+ value: function renderInputField() {
1625
+ var model = this.props.model;
1626
+ var editingCell = this.state.editingCell;
1627
+ var metrics = this.metrics;
1628
+
1629
+ if (editingCell == null || metrics == null) {
1630
+ return null;
1631
+ }
1581
1632
 
1582
- if (fillRange) {
1583
- this.setValueForRanges(selectedRanges, value);
1584
- } else {
1585
- this.setValueForCell(column, row, value);
1633
+ var _editingCell$selectio = editingCell.selectionRange,
1634
+ selectionRange = _editingCell$selectio === void 0 ? null : _editingCell$selectio,
1635
+ value = editingCell.value,
1636
+ isQuickEdit = editingCell.isQuickEdit;
1637
+ var _this$state11 = this.state,
1638
+ row = _this$state11.cursorRow,
1639
+ column = _this$state11.cursorColumn;
1640
+ var gridX = metrics.gridX,
1641
+ gridY = metrics.gridY,
1642
+ visibleColumnXs = metrics.visibleColumnXs,
1643
+ visibleRowYs = metrics.visibleRowYs,
1644
+ visibleColumnWidths = metrics.visibleColumnWidths,
1645
+ visibleRowHeights = metrics.visibleRowHeights;
1646
+ var x = visibleColumnXs.get(column);
1647
+ var y = visibleRowYs.get(row);
1648
+ var w = visibleColumnWidths.get(column);
1649
+ var h = visibleRowHeights.get(row);
1650
+ var isVisible = x != null && y != null && w != null && h != null; // If the cell isn't visible, we still need to display an invisible cell for focus purposes
1651
+
1652
+ var wrapperStyle = isVisible ? {
1653
+ position: 'absolute',
1654
+ left: gridX + x,
1655
+ top: gridY + y,
1656
+ width: w,
1657
+ height: h
1658
+ } : {
1659
+ opacity: 0
1660
+ };
1661
+ var modelColumn = this.getModelColumn(column);
1662
+ var modelRow = this.getModelRow(row);
1663
+ var inputStyle = modelColumn != null && modelRow != null ? {
1664
+ textAlign: model.textAlignForCell(modelColumn, modelRow)
1665
+ } : null;
1666
+ var isValid = model.isValidForCell(modelColumn, modelRow, value);
1667
+ return /*#__PURE__*/React.createElement("div", {
1668
+ style: wrapperStyle
1669
+ }, /*#__PURE__*/React.createElement(CellInputField, {
1670
+ key: "".concat(column, ",").concat(row),
1671
+ selectionRange: selectionRange,
1672
+ className: classNames({
1673
+ error: !isValid
1674
+ }),
1675
+ onCancel: this.handleEditCellCancel,
1676
+ onChange: this.handleEditCellChange,
1677
+ onDone: this.handleEditCellCommit,
1678
+ isQuickEdit: isQuickEdit,
1679
+ style: inputStyle,
1680
+ value: value
1681
+ }));
1586
1682
  }
1587
-
1588
- if (direction != null) {
1589
- this.moveCursorInDirection(direction);
1683
+ }, {
1684
+ key: "render",
1685
+ value: function render() {
1686
+ var _this6 = this;
1687
+
1688
+ var cursor = this.state.cursor;
1689
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("canvas", {
1690
+ className: classNames('grid-canvas', Grid.getCursorClassName(cursor)),
1691
+ ref: function ref(canvas) {
1692
+ _this6.canvas = canvas;
1693
+ },
1694
+ onClick: this.handleClick,
1695
+ onContextMenu: this.handleContextMenu,
1696
+ onDoubleClick: this.handleDoubleClick,
1697
+ onKeyDown: this.handleKeyDown,
1698
+ onMouseDown: this.handleMouseDown,
1699
+ onMouseMove: this.handleMouseMove,
1700
+ onMouseLeave: this.handleMouseLeave,
1701
+ tabIndex: 0
1702
+ }, "Your browser does not support HTML canvas. Update your browser?"), this.renderInputField());
1590
1703
  }
1591
-
1592
- this.setState({
1593
- editingCell: null
1594
- });
1595
- this.focus();
1596
- }
1597
-
1598
- renderInputField() {
1599
- var {
1600
- model
1601
- } = this.props;
1602
- var {
1603
- editingCell
1604
- } = this.state;
1605
- var {
1606
- metrics
1607
- } = this;
1608
-
1609
- if (editingCell == null || metrics == null) {
1610
- return null;
1704
+ }], [{
1705
+ key: "getScale",
1706
+ value: // use same constant as chrome source for windows
1707
+ // https://github.com/chromium/chromium/blob/973af9d461b6b5dc60208c8d3d66adc27e53da78/ui/events/blink/web_input_event_builders_win.cc#L285
1708
+ function getScale(context) {
1709
+ var devicePixelRatio = window.devicePixelRatio || 1;
1710
+ var backingStorePixelRatio = context.webkitBackingStorePixelRatio || context.mozBackingStorePixelRatio || context.msBackingStorePixelRatio || context.oBackingStorePixelRatio || context.backingStorePixelRatio || 1;
1711
+ return devicePixelRatio / backingStorePixelRatio;
1611
1712
  }
1713
+ }, {
1714
+ key: "getCursorClassName",
1715
+ value: function getCursorClassName(cursor) {
1716
+ return cursor ? "grid-cursor-".concat(cursor) : null;
1717
+ }
1718
+ }]);
1612
1719
 
1613
- var {
1614
- selectionRange = null,
1615
- value,
1616
- isQuickEdit
1617
- } = editingCell;
1618
- var {
1619
- cursorRow: row,
1620
- cursorColumn: column
1621
- } = this.state;
1622
- var {
1623
- gridX,
1624
- gridY,
1625
- visibleColumnXs,
1626
- visibleRowYs,
1627
- visibleColumnWidths,
1628
- visibleRowHeights
1629
- } = metrics;
1630
- var x = visibleColumnXs.get(column);
1631
- var y = visibleRowYs.get(row);
1632
- var w = visibleColumnWidths.get(column);
1633
- var h = visibleRowHeights.get(row);
1634
- var isVisible = x != null && y != null && w != null && h != null; // If the cell isn't visible, we still need to display an invisible cell for focus purposes
1635
-
1636
- var wrapperStyle = isVisible ? {
1637
- position: 'absolute',
1638
- left: gridX + x,
1639
- top: gridY + y,
1640
- width: w,
1641
- height: h
1642
- } : {
1643
- opacity: 0
1644
- };
1645
- var modelColumn = this.getModelColumn(column);
1646
- var modelRow = this.getModelRow(row);
1647
- var inputStyle = modelColumn != null && modelRow != null ? {
1648
- textAlign: model.textAlignForCell(modelColumn, modelRow)
1649
- } : null;
1650
- var isValid = model.isValidForCell(modelColumn, modelRow, value);
1651
- return /*#__PURE__*/React.createElement("div", {
1652
- style: wrapperStyle
1653
- }, /*#__PURE__*/React.createElement(CellInputField, {
1654
- key: "".concat(column, ",").concat(row),
1655
- selectionRange: selectionRange,
1656
- className: classNames({
1657
- error: !isValid
1658
- }),
1659
- onCancel: this.handleEditCellCancel,
1660
- onChange: this.handleEditCellChange,
1661
- onDone: this.handleEditCellCommit,
1662
- isQuickEdit: isQuickEdit,
1663
- style: inputStyle,
1664
- value: value
1665
- }));
1666
- }
1667
-
1668
- render() {
1669
- var {
1670
- cursor
1671
- } = this.state;
1672
- return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("canvas", {
1673
- className: classNames('grid-canvas', Grid.getCursorClassName(cursor)),
1674
- ref: canvas => {
1675
- this.canvas = canvas;
1676
- },
1677
- onClick: this.handleClick,
1678
- onContextMenu: this.handleContextMenu,
1679
- onDoubleClick: this.handleDoubleClick,
1680
- onKeyDown: this.handleKeyDown,
1681
- onMouseDown: this.handleMouseDown,
1682
- onMouseMove: this.handleMouseMove,
1683
- onMouseLeave: this.handleMouseLeave,
1684
- tabIndex: 0
1685
- }, "Your browser does not support HTML canvas. Update your browser?"), this.renderInputField());
1686
- }
1687
-
1688
- }
1720
+ return Grid;
1721
+ }(PureComponent);
1689
1722
 
1690
1723
  _defineProperty(Grid, "pixelsPerLine", 100 / 3);
1691
1724
 
1692
1725
  _defineProperty(Grid, "dragTimeout", 1000);
1693
1726
 
1694
- _defineProperty(Grid, "getTheme", memoize(userTheme => _objectSpread(_objectSpread({}, GridTheme), userTheme)));
1727
+ _defineProperty(Grid, "getTheme", memoize(function (userTheme) {
1728
+ return _objectSpread(_objectSpread({}, GridTheme), userTheme);
1729
+ }));
1695
1730
 
1696
1731
  Grid.propTypes = {
1697
1732
  canvasOptions: PropTypes.shape({}),
@@ -1732,11 +1767,11 @@ Grid.defaultProps = {
1732
1767
  mouseHandlers: [],
1733
1768
  movedColumns: [],
1734
1769
  movedRows: [],
1735
- onError: () => {},
1736
- onSelectionChanged: () => {},
1737
- onMovedColumnsChanged: () => {},
1738
- onMoveColumnComplete: () => {},
1739
- onViewChanged: () => {},
1770
+ onError: function onError() {},
1771
+ onSelectionChanged: function onSelectionChanged() {},
1772
+ onMovedColumnsChanged: function onMovedColumnsChanged() {},
1773
+ onMoveColumnComplete: function onMoveColumnComplete() {},
1774
+ onViewChanged: function onViewChanged() {},
1740
1775
  renderer: null,
1741
1776
  stateOverride: {},
1742
1777
  theme: {