@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/GridRange.js CHANGED
@@ -1,694 +1,752 @@
1
- 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; }
1
+ function _construct(Parent, args, Class) { if (_isNativeReflectConstruct()) { _construct = Reflect.construct; } else { _construct = function _construct(Parent, args, Class) { var a = [null]; a.push.apply(a, args); var Constructor = Function.bind.apply(Parent, a); var instance = new Constructor(); if (Class) _setPrototypeOf(instance, Class.prototype); return instance; }; } return _construct.apply(null, arguments); }
2
2
 
3
- class GridRange {
4
- static normalize(startColumn, startRow, endColumn, endRow) {
5
- var left = startColumn;
6
- var top = startRow;
7
- var right = endColumn;
8
- var bottom = endRow;
3
+ 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; } }
9
4
 
10
- if (left != null && right != null && right < left) {
11
- left = right;
12
- right = startColumn;
13
- }
5
+ function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
14
6
 
15
- if (top != null && bottom != null && bottom < top) {
16
- top = bottom;
17
- bottom = startRow;
18
- }
7
+ function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
19
8
 
20
- return [left, top, right, bottom];
21
- }
22
- /** Make a GridRange, but ensure startColumn <= endColumn, startRow <= endRow */
23
-
24
-
25
- static makeNormalized() {
26
- return new GridRange(...GridRange.normalize(...arguments));
27
- }
9
+ 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."); }
28
10
 
29
- static makeCell(column, row) {
30
- return new GridRange(column, row, column, row);
31
- }
11
+ 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); }
32
12
 
33
- static makeColumn(column) {
34
- return new GridRange(column, null, column, null);
35
- }
13
+ function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter); }
36
14
 
37
- static makeRow(row) {
38
- return new GridRange(null, row, null, row);
39
- }
15
+ function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
40
16
 
41
- static minOrNull(value1, value2) {
42
- if (value1 == null || value2 == null) {
43
- return null;
44
- }
17
+ 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; }
45
18
 
46
- return Math.min(value1, value2);
47
- }
19
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
48
20
 
49
- static maxOrNull(value1, value2) {
50
- if (value1 == null || value2 == null) {
51
- return null;
52
- }
21
+ 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); } }
53
22
 
54
- return Math.max(value1, value2);
55
- }
56
- /**
57
- * Consolidate the passed in ranges to the minimum set, merging overlapping ranges.
58
- * @param {[GridRange]} ranges The ranges to consolidate
59
- */
60
-
61
-
62
- static consolidate(ranges) {
63
- var result = ranges.slice();
64
- var wasModified = true;
65
-
66
- while (wasModified) {
67
- wasModified = false;
68
-
69
- for (var i = 0; i < result.length && !wasModified; i += 1) {
70
- var range = result[i];
71
-
72
- for (var j = result.length - 1; j > i; j -= 1) {
73
- var other = result[j]; // If one contains the other, we can just keep the bigger one
74
-
75
- if (range.contains(other)) {
76
- result.splice(j, 1);
77
- } else if (other.contains(range)) {
78
- wasModified = true;
79
- result[i] = other;
80
- result.splice(j, 1);
81
- break;
82
- } else if (range.startRow === other.startRow && range.endRow === other.endRow) {
83
- if (range.touches(other)) {
84
- // If the start/end rows match, and columns touch, consolidate
85
- var {
86
- startRow,
87
- endRow
88
- } = range;
89
- var startColumn = GridRange.minOrNull(range.startColumn, other.startColumn);
90
- var endColumn = GridRange.maxOrNull(range.endColumn, other.endColumn);
91
- wasModified = true;
92
- result[i] = new GridRange(startColumn, startRow, endColumn, endRow);
93
- result.splice(j, 1);
94
- break;
95
- }
96
- } else if (range.startColumn === other.startColumn && range.endColumn === other.endColumn) {
97
- if (range.touches(other)) {
98
- // If the start/end rows match, and columns touch, consolidate
99
- var {
100
- startColumn: _startColumn,
101
- endColumn: _endColumn
102
- } = range;
23
+ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
103
24
 
104
- var _startRow = GridRange.minOrNull(range.startRow, other.startRow);
25
+ 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; }
105
26
 
106
- var _endRow = GridRange.maxOrNull(range.endRow, other.endRow);
27
+ var GridRange = /*#__PURE__*/function () {
28
+ function GridRange(startColumn, startRow, endColumn, endRow) {
29
+ _classCallCheck(this, GridRange);
107
30
 
108
- wasModified = true;
109
- result[i] = new GridRange(_startColumn, _startRow, _endColumn, _endRow);
110
- result.splice(j, 1);
111
- break;
112
- }
113
- }
114
- }
115
- }
116
- }
117
-
118
- return result;
31
+ this.startColumn = startColumn;
32
+ this.startRow = startRow;
33
+ this.endColumn = endColumn;
34
+ this.endRow = endRow;
119
35
  }
120
36
 
121
- static isAxisRangeTouching(start, end, otherStart, otherEnd) {
122
- if (start == null) {
123
- if (end == null) {
124
- return true;
125
- }
126
-
127
- if (otherStart == null) {
128
- return true;
129
- }
130
-
131
- return otherStart <= end + 1;
37
+ _createClass(GridRange, [{
38
+ key: "equals",
39
+ value: function equals(other) {
40
+ return this.startColumn === other.startColumn && this.startRow === other.startRow && this.endColumn === other.endColumn && this.endRow === other.endRow;
132
41
  }
42
+ /** @returns {boolean} true if this GridRange completely contains `other` */
133
43
 
134
- if (end == null) {
135
- if (otherEnd == null) {
136
- return true;
137
- }
138
-
139
- return otherEnd >= start - 1;
44
+ }, {
45
+ key: "contains",
46
+ value: function contains(other) {
47
+ return (this.startColumn == null || other.startColumn != null && this.startColumn <= other.startColumn) && (this.startRow == null || other.startRow != null && this.startRow <= other.startRow) && (this.endColumn == null || other.endColumn != null && this.endColumn >= other.endColumn) && (this.endRow == null || other.endRow != null && this.endRow >= other.endRow);
140
48
  }
141
-
142
- if (otherStart == null) {
143
- if (otherEnd == null) {
144
- return true;
49
+ /**
50
+ * Check if the provided cell is in this range
51
+ * @param {number} column The column to check
52
+ * @param {number} row The row to check
53
+ * @returns {boolean} True if this cell is within this range
54
+ */
55
+
56
+ }, {
57
+ key: "containsCell",
58
+ value: function containsCell(column, row) {
59
+ if (column == null || row == null) {
60
+ return false;
145
61
  }
146
62
 
147
- return start <= otherEnd + 1;
63
+ return (this.startColumn == null || this.startColumn <= column) && (this.endColumn == null || this.endColumn >= column) && (this.startRow == null || this.startRow <= row) && (this.endRow == null || this.endRow >= row);
148
64
  }
65
+ /** @returns {boolean} true if this GridRange touches `other` */
149
66
 
150
- if (otherEnd == null) {
151
- return end >= otherStart - 1;
67
+ }, {
68
+ key: "touches",
69
+ value: function touches(other) {
70
+ return GridRange.isAxisRangeTouching(this.startRow, this.endRow, other.startRow, other.endRow) && GridRange.isAxisRangeTouching(this.startColumn, this.endColumn, other.startColumn, other.endColumn);
152
71
  }
153
-
154
- if (otherStart >= start - 1) {
155
- return otherStart <= end + 1;
72
+ /**
73
+ * @param {GridRange} other The range to deselect from within this range
74
+ * @returns {[GridRange]} The ranges needed to represent the remaining
75
+ */
76
+
77
+ }, {
78
+ key: "subtract",
79
+ value: function subtract(other) {
80
+ return GridRange.subtractFromRange(this, other);
156
81
  }
157
-
158
- return otherEnd >= start - 1;
159
- }
160
-
161
- static rangeArraysEqual(ranges1, ranges2) {
162
- if (ranges1 === ranges2) {
163
- return true;
164
- }
165
-
166
- if (ranges1 == null || ranges2 == null || ranges1.length !== ranges2.length) {
167
- return false;
168
- }
169
-
170
- for (var i = 0; i < ranges1.length; i += 1) {
171
- if (!ranges1[i].equals(ranges2[i])) {
172
- return false;
82
+ /**
83
+ * Get the first cell in this range. Throws if this range is unbounded.
84
+ *
85
+ * @param {GridRange.SELECTION_DIRECTION?} direction The direction to get the starting cell in. Defaults to DOWN
86
+ * @returns {{column: number, row: number}} The first cell in this range in the direction specified
87
+ */
88
+
89
+ }, {
90
+ key: "startCell",
91
+ value: function startCell() {
92
+ var direction = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : GridRange.SELECTION_DIRECTION.DOWN;
93
+
94
+ if (!GridRange.isBounded(this)) {
95
+ throw new Error('Cannot get the startCell of an unbounded range');
173
96
  }
174
- }
175
-
176
- return true;
177
- }
178
- /**
179
- * Get the intersection (overlapping area) of two ranges
180
- * @param {GridRange} range One range to check for the intersection
181
- * @param {GridRange} otherRange The other range to check for the intersection
182
- * @returns {GridRange|null} Intersection of the two ranges. If they do not intersect, returns `null`.
183
- */
184
97
 
98
+ switch (direction) {
99
+ case GridRange.SELECTION_DIRECTION.DOWN:
100
+ case GridRange.SELECTION_DIRECTION.RIGHT:
101
+ return {
102
+ column: this.startColumn,
103
+ row: this.startRow
104
+ };
185
105
 
186
- static intersection(range, otherRange) {
187
- var _startColumn2, _endColumn2, _startRow2, _endRow2;
106
+ case GridRange.SELECTION_DIRECTION.LEFT:
107
+ case GridRange.SELECTION_DIRECTION.UP:
108
+ {
109
+ return {
110
+ column: this.endColumn,
111
+ row: this.endRow
112
+ };
113
+ }
188
114
 
189
- if (range.equals(otherRange)) {
190
- return range;
115
+ default:
116
+ throw new Error("Invalid direction: ".concat(direction));
117
+ }
191
118
  }
119
+ /**
120
+ * Get the next cell in the direction specified. Throws if this range is unbounded.
121
+ * If already at the bounds of the range in that direction, wrap to the next column or row
122
+ * If at the end of the entire range, return null
123
+ * If outside of the range, returns the next cell closest within this range.
124
+ *
125
+ * @param {number} column The cursor column
126
+ * @param {number} row The cursor row
127
+ * @param {SELECTION_DIRECTION} direction The direction to go in
128
+ * @returns {GridCell|null} The next cell in the direction specified, or `null` if at the end of the range
129
+ */
130
+
131
+ }, {
132
+ key: "nextCell",
133
+ value: function nextCell(column, row, direction) {
134
+ if (!GridRange.isBounded(this)) {
135
+ throw new Error('Bounded range required');
136
+ }
192
137
 
193
- var {
194
- startColumn,
195
- startRow,
196
- endColumn,
197
- endRow
198
- } = range;
199
- startColumn = startColumn != null && otherRange.startColumn != null ? Math.max(startColumn, otherRange.startColumn) : (_startColumn2 = startColumn) !== null && _startColumn2 !== void 0 ? _startColumn2 : otherRange.startColumn;
200
- endColumn = endColumn != null && otherRange.endColumn != null ? Math.min(endColumn, otherRange.endColumn) : (_endColumn2 = endColumn) !== null && _endColumn2 !== void 0 ? _endColumn2 : otherRange.endColumn;
201
- startRow = startRow != null && otherRange.startRow != null ? Math.max(startRow, otherRange.startRow) : (_startRow2 = startRow) !== null && _startRow2 !== void 0 ? _startRow2 : otherRange.startRow;
202
- endRow = endRow != null && otherRange.endRow != null ? Math.min(endRow, otherRange.endRow) : (_endRow2 = endRow) !== null && _endRow2 !== void 0 ? _endRow2 : otherRange.endRow;
138
+ if (column == null || row == null) {
139
+ throw new Error('Require a non-null cursor');
140
+ }
203
141
 
204
- if (startColumn != null && startColumn > endColumn || startRow != null && startRow > endRow) {
205
- return null;
206
- }
142
+ var startColumn = this.startColumn,
143
+ endColumn = this.endColumn,
144
+ startRow = this.startRow,
145
+ endRow = this.endRow;
146
+
147
+ switch (direction) {
148
+ case GridRange.SELECTION_DIRECTION.DOWN:
149
+ if (row < endRow) {
150
+ return {
151
+ column: column,
152
+ row: Math.max(row + 1, startRow)
153
+ };
154
+ }
207
155
 
208
- return new GridRange(startColumn, startRow, endColumn, endRow);
209
- }
210
- /**
211
- * @param {GridRange} range The range to be subtracted from
212
- * @param {GridRange} subtractRange The range to subtract from within this range
213
- * @returns {GridRange[]} The ranges needed to represent the remaining
214
- */
156
+ if (column < endColumn) {
157
+ return {
158
+ column: Math.max(column + 1, startColumn),
159
+ row: startRow
160
+ };
161
+ }
215
162
 
163
+ break;
216
164
 
217
- static subtractFromRange(range, subtractRange) {
218
- var result = []; // Make it a little easier by finding only the part the subtraction range intersects
165
+ case GridRange.SELECTION_DIRECTION.UP:
166
+ if (row > startRow) {
167
+ return {
168
+ column: column,
169
+ row: Math.min(row - 1, endRow)
170
+ };
171
+ }
219
172
 
220
- var subtract = GridRange.intersection(range, subtractRange);
173
+ if (column > startColumn) {
174
+ return {
175
+ column: Math.min(column - 1, endColumn),
176
+ row: endRow
177
+ };
178
+ }
221
179
 
222
- if (subtract == null) {
223
- return [range];
224
- } // Go through each of the quadrants for deselection, there can be up to 4
225
- // Top quadrant (above the subtracted area)
180
+ break;
226
181
 
182
+ case GridRange.SELECTION_DIRECTION.RIGHT:
183
+ if (column < endColumn) {
184
+ return {
185
+ column: Math.max(column + 1, startColumn),
186
+ row: row
187
+ };
188
+ }
227
189
 
228
- if (subtract.startRow != null && (range.startRow == null || range.startRow < subtract.startRow)) {
229
- result.push(new GridRange(range.startColumn, range.startRow, range.endColumn, subtract.startRow - 1));
230
- } // middle left
190
+ if (row < endRow) {
191
+ return {
192
+ column: startColumn,
193
+ row: Math.max(row + 1, startRow)
194
+ };
195
+ }
231
196
 
197
+ break;
232
198
 
233
- if (subtract.startColumn != null && (range.startColumn == null || range.startColumn < subtract.startColumn)) {
234
- result.push(new GridRange(range.startColumn, subtract.startRow, subtract.startColumn - 1, subtract.endRow));
235
- } // middle right
199
+ case GridRange.SELECTION_DIRECTION.LEFT:
200
+ if (column > startColumn) {
201
+ return {
202
+ column: Math.min(column - 1, endColumn),
203
+ row: row
204
+ };
205
+ }
236
206
 
207
+ if (row > startRow) {
208
+ return {
209
+ column: endColumn,
210
+ row: Math.min(row - 1, endRow)
211
+ };
212
+ }
237
213
 
238
- if (subtract.endColumn != null && (range.endColumn == null || range.endColumn > subtract.endColumn)) {
239
- result.push(new GridRange(subtract.endColumn + 1, subtract.startRow, range.endColumn, subtract.endRow));
240
- } // Bottom quadrant
214
+ break;
241
215
 
216
+ default:
217
+ throw new Error("Invalid direction: ".concat(direction));
218
+ }
242
219
 
243
- if (subtract.endRow != null && (range.endRow == null || range.endRow > subtract.endRow)) {
244
- result.push(new GridRange(range.startColumn, subtract.endRow + 1, range.endColumn, range.endRow));
220
+ return null;
245
221
  }
222
+ /**
223
+ * Iterate through each cell in the range
224
+ * @param {(column:number, row:number, index:number) => void} callback Callback to execute. `index` is the index within this range
225
+ * @param {GridRange.SELECTION_DIRECTION} direction The direction to iterate in
226
+ */
246
227
 
247
- return result;
248
- }
249
- /**
250
- * Subtract a range from multiple ranges
251
- * @param {GridRange[]} ranges The ranges to be subtracted from
252
- * @param {GridRange} subtractRange The range to subtract from within these ranges
253
- * @returns {GridRange[]} The ranges needed to represent the remaining
254
- */
228
+ }, {
229
+ key: "forEach",
230
+ value: function forEach(callback) {
231
+ var direction = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : GridRange.SELECTION_DIRECTION.RIGHT;
232
+ var i = 0;
255
233
 
234
+ var _this$startCell = this.startCell(direction),
235
+ c = _this$startCell.column,
236
+ r = _this$startCell.row;
256
237
 
257
- static subtractFromRanges(ranges, subtractRange) {
258
- var result = [];
238
+ while (c != null && r != null) {
239
+ var _this$nextCell;
259
240
 
260
- for (var i = 0; i < ranges.length; i += 1) {
261
- result.push(...GridRange.subtractFromRange(ranges[i], subtractRange));
262
- }
263
-
264
- return result;
265
- }
266
- /**
267
- * Subtract multiple ranges from multiple ranges
268
- * @param {GridRange[]} ranges The ranges to be subtracted from
269
- * @param {GridRange[]} subtractRanges The ranges to subtract from within these ranges
270
- * @returns {GridRange[]} The ranges needed to represent the remaining
271
- */
241
+ callback(c, r, i);
242
+ i += 1;
272
243
 
244
+ var _ref = (_this$nextCell = this.nextCell(c, r, direction)) !== null && _this$nextCell !== void 0 ? _this$nextCell : {};
273
245
 
274
- static subtractRangesFromRanges(ranges, subtractRanges) {
275
- if (!subtractRanges || subtractRanges.length === 0) {
276
- return ranges;
246
+ c = _ref.column;
247
+ r = _ref.row;
248
+ }
277
249
  }
250
+ }], [{
251
+ key: "normalize",
252
+ value: function normalize(startColumn, startRow, endColumn, endRow) {
253
+ var left = startColumn;
254
+ var top = startRow;
255
+ var right = endColumn;
256
+ var bottom = endRow;
257
+
258
+ if (left != null && right != null && right < left) {
259
+ left = right;
260
+ right = startColumn;
261
+ }
278
262
 
279
- var result = [...ranges];
263
+ if (top != null && bottom != null && bottom < top) {
264
+ top = bottom;
265
+ bottom = startRow;
266
+ }
280
267
 
281
- for (var i = 0; i < subtractRanges.length; i += 1) {
282
- result = GridRange.subtractFromRanges(result, subtractRanges[i]);
268
+ return [left, top, right, bottom];
283
269
  }
270
+ /** Make a GridRange, but ensure startColumn <= endColumn, startRow <= endRow */
284
271
 
285
- return result;
286
- }
287
- /**
288
- * Test if a given range is bounded (all values are non-null)
289
- * @param {GridRange} range The range to test
290
- * @returns {boolean} True if this range is bounded, false otherwise
291
- */
292
-
293
-
294
- static isBounded(range) {
295
- return range.startRow != null && range.startColumn != null && range.endRow != null && range.endColumn != null;
296
- }
297
- /**
298
- * Converts any GridRange passed in that is a full row or column selection to be bound
299
- * to the `columnCount` and `rowCount` passed in
300
- *
301
- * @param {GridRange} range The range to get the bounded range of
302
- * @param {number} columnCount The number of columns
303
- * @param {number} rowCount The number of rows
304
- * @returns {GridRange} The passed in GridRange with any null values filled in
305
- */
306
-
307
-
308
- static boundedRange(range, columnCount, rowCount) {
309
- var _range$startColumn, _range$startRow, _range$endColumn, _range$endRow;
272
+ }, {
273
+ key: "makeNormalized",
274
+ value: function makeNormalized() {
275
+ return _construct(GridRange, _toConsumableArray(GridRange.normalize.apply(GridRange, arguments)));
276
+ }
277
+ }, {
278
+ key: "makeCell",
279
+ value: function makeCell(column, row) {
280
+ return new GridRange(column, row, column, row);
281
+ }
282
+ }, {
283
+ key: "makeColumn",
284
+ value: function makeColumn(column) {
285
+ return new GridRange(column, null, column, null);
286
+ }
287
+ }, {
288
+ key: "makeRow",
289
+ value: function makeRow(row) {
290
+ return new GridRange(null, row, null, row);
291
+ }
292
+ }, {
293
+ key: "minOrNull",
294
+ value: function minOrNull(value1, value2) {
295
+ if (value1 == null || value2 == null) {
296
+ return null;
297
+ }
310
298
 
311
- if (GridRange.isBounded(range)) {
312
- return range;
299
+ return Math.min(value1, value2);
313
300
  }
301
+ }, {
302
+ key: "maxOrNull",
303
+ value: function maxOrNull(value1, value2) {
304
+ if (value1 == null || value2 == null) {
305
+ return null;
306
+ }
314
307
 
315
- return new GridRange((_range$startColumn = range.startColumn) !== null && _range$startColumn !== void 0 ? _range$startColumn : 0, (_range$startRow = range.startRow) !== null && _range$startRow !== void 0 ? _range$startRow : 0, (_range$endColumn = range.endColumn) !== null && _range$endColumn !== void 0 ? _range$endColumn : columnCount - 1, (_range$endRow = range.endRow) !== null && _range$endRow !== void 0 ? _range$endRow : rowCount - 1);
316
- }
317
- /**
318
- * Converts the GridRanges passed in to be bound to the `columnCount` and `rowCount` passed in
319
- *
320
- * @param {GridRange[]} ranges The ranges to get the bounded ranges of
321
- * @param {number} columnCount The number of columns
322
- * @param {number} rowCount The number of rows
323
- * @returns {GridRange} The passed in GridRange with any null values filled in
324
- */
325
-
326
-
327
- static boundedRanges(ranges, columnCount, rowCount) {
328
- return ranges.map(r => GridRange.boundedRange(r, columnCount, rowCount));
329
- }
330
- /**
331
- * Offsets a GridRange by the specified amount in the x and y directions
332
- *
333
- * @param {GridRange} range The range to offset
334
- * @param {number} columnOffset The number of columns to offset
335
- * @param {number} rowOffset The number of rows to offset
336
- * @returns {GridRange} The new grid range offset from the original
337
- */
338
-
339
-
340
- static offset(range, columnOffset, rowOffset) {
341
- return new GridRange(range.startColumn != null ? range.startColumn + columnOffset : null, range.startRow != null ? range.startRow + rowOffset : null, range.endColumn != null ? range.endColumn + columnOffset : null, range.endRow != null ? range.endRow + rowOffset : null);
342
- }
343
- /**
344
- * Get the next cell given the selected ranges and the current cell
345
- * @param {GridRange[]} ranges The selected bounded ranges within the grid
346
- * @param {number|null} column The cursor column, or null if none focused
347
- * @param {number|null} row The cursor row, or null if none focused
348
- * @param {SELECTION_DIRECTION} direction The direction in which to select next
349
- * @returns {Cell} The next cell to focus, or null if there should be no more focus
350
- */
351
-
352
-
353
- static nextCell(ranges) {
354
- var column = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
355
- var row = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
356
- var direction = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : GridRange.SELECTION_DIRECTION.DOWN;
357
-
358
- if (ranges.length === 0) {
359
- return null;
308
+ return Math.max(value1, value2);
360
309
  }
310
+ /**
311
+ * Consolidate the passed in ranges to the minimum set, merging overlapping ranges.
312
+ * @param {[GridRange]} ranges The ranges to consolidate
313
+ */
314
+
315
+ }, {
316
+ key: "consolidate",
317
+ value: function consolidate(ranges) {
318
+ var result = ranges.slice();
319
+ var wasModified = true;
361
320
 
362
- var rangeIndex = -1;
321
+ while (wasModified) {
322
+ wasModified = false;
363
323
 
364
- if (column != null && row != null) {
365
- rangeIndex = ranges.findIndex(r => r.containsCell(column, row));
324
+ for (var i = 0; i < result.length && !wasModified; i += 1) {
325
+ var range = result[i];
366
326
 
367
- if (rangeIndex >= 0) {
368
- var range = ranges[rangeIndex];
369
- var nextCell = range.nextCell(column, row, direction);
327
+ for (var j = result.length - 1; j > i; j -= 1) {
328
+ var other = result[j]; // If one contains the other, we can just keep the bigger one
370
329
 
371
- if (nextCell != null) {
372
- return nextCell;
330
+ if (range.contains(other)) {
331
+ result.splice(j, 1);
332
+ } else if (other.contains(range)) {
333
+ wasModified = true;
334
+ result[i] = other;
335
+ result.splice(j, 1);
336
+ break;
337
+ } else if (range.startRow === other.startRow && range.endRow === other.endRow) {
338
+ if (range.touches(other)) {
339
+ // If the start/end rows match, and columns touch, consolidate
340
+ var startRow = range.startRow,
341
+ endRow = range.endRow;
342
+ var startColumn = GridRange.minOrNull(range.startColumn, other.startColumn);
343
+ var endColumn = GridRange.maxOrNull(range.endColumn, other.endColumn);
344
+ wasModified = true;
345
+ result[i] = new GridRange(startColumn, startRow, endColumn, endRow);
346
+ result.splice(j, 1);
347
+ break;
348
+ }
349
+ } else if (range.startColumn === other.startColumn && range.endColumn === other.endColumn) {
350
+ if (range.touches(other)) {
351
+ // If the start/end rows match, and columns touch, consolidate
352
+ var _startColumn = range.startColumn,
353
+ _endColumn = range.endColumn;
354
+
355
+ var _startRow = GridRange.minOrNull(range.startRow, other.startRow);
356
+
357
+ var _endRow = GridRange.maxOrNull(range.endRow, other.endRow);
358
+
359
+ wasModified = true;
360
+ result[i] = new GridRange(_startColumn, _startRow, _endColumn, _endRow);
361
+ result.splice(j, 1);
362
+ break;
363
+ }
364
+ }
365
+ }
373
366
  }
374
367
  }
375
- } // Otherwise go to the start of the next range (could be same range if only one range)
376
-
377
368
 
378
- switch (direction) {
379
- case GridRange.SELECTION_DIRECTION.DOWN:
380
- case GridRange.SELECTION_DIRECTION.RIGHT:
381
- {
382
- var nextRangeIndex = rangeIndex < ranges.length - 1 ? rangeIndex + 1 : 0;
383
- var nextRange = ranges[nextRangeIndex];
384
- return nextRange.startCell(direction);
369
+ return result;
370
+ }
371
+ }, {
372
+ key: "isAxisRangeTouching",
373
+ value: function isAxisRangeTouching(start, end, otherStart, otherEnd) {
374
+ if (start == null) {
375
+ if (end == null) {
376
+ return true;
385
377
  }
386
378
 
387
- case GridRange.SELECTION_DIRECTION.LEFT:
388
- case GridRange.SELECTION_DIRECTION.UP:
389
- {
390
- var _nextRangeIndex = rangeIndex > 0 ? rangeIndex - 1 : ranges.length - 1;
391
-
392
- var _nextRange = ranges[_nextRangeIndex];
393
- return _nextRange.startCell(direction);
379
+ if (otherStart == null) {
380
+ return true;
394
381
  }
395
382
 
396
- default:
397
- throw new Error("Invalid direction: ".concat(direction));
398
- }
399
- }
400
- /**
401
- * Count the number of cells in the provided grid ranges
402
- * @param {GridRange[]} ranges The ranges to count the rows of
403
- * @returns {number|NaN} The number of cells in the ranges, or `NaN` if any of the ranges were unbounded
404
- */
405
-
406
-
407
- static cellCount(ranges) {
408
- return ranges.reduce((cellCount, range) => {
409
- var _range$endRow2, _range$startRow2, _range$endColumn2, _range$startColumn2;
410
-
411
- return cellCount + (((_range$endRow2 = range.endRow) !== null && _range$endRow2 !== void 0 ? _range$endRow2 : NaN) - ((_range$startRow2 = range.startRow) !== null && _range$startRow2 !== void 0 ? _range$startRow2 : NaN) + 1) * (((_range$endColumn2 = range.endColumn) !== null && _range$endColumn2 !== void 0 ? _range$endColumn2 : NaN) - ((_range$startColumn2 = range.startColumn) !== null && _range$startColumn2 !== void 0 ? _range$startColumn2 : NaN) + 1);
412
- }, 0);
413
- }
414
- /**
415
- * Count the number of rows in the provided grid ranges
416
- * @param {GridRange[]} ranges The ranges to count the rows of
417
- * @returns {number|NaN} The number of rows in the ranges, or `NaN` if any of the ranges were unbounded
418
- */
419
-
420
-
421
- static rowCount(ranges) {
422
- return ranges.reduce((rowCount, range) => {
423
- var _range$endRow3, _range$startRow3;
383
+ return otherStart <= end + 1;
384
+ }
424
385
 
425
- return rowCount + ((_range$endRow3 = range.endRow) !== null && _range$endRow3 !== void 0 ? _range$endRow3 : NaN) - ((_range$startRow3 = range.startRow) !== null && _range$startRow3 !== void 0 ? _range$startRow3 : NaN) + 1;
426
- }, 0);
427
- }
428
- /**
429
- * Count the number of columns in the provided grid ranges
430
- * @param {GridRange[]} ranges The ranges to count the columns of
431
- * @returns {number|NaN} The number of columns in the ranges, or `NaN` if any of the ranges were unbounded
432
- */
386
+ if (end == null) {
387
+ if (otherEnd == null) {
388
+ return true;
389
+ }
433
390
 
391
+ return otherEnd >= start - 1;
392
+ }
434
393
 
435
- static columnCount(ranges) {
436
- return ranges.reduce((columnCount, range) => {
437
- var _range$endColumn3, _range$startColumn3;
394
+ if (otherStart == null) {
395
+ if (otherEnd == null) {
396
+ return true;
397
+ }
438
398
 
439
- return columnCount + ((_range$endColumn3 = range.endColumn) !== null && _range$endColumn3 !== void 0 ? _range$endColumn3 : NaN) - ((_range$startColumn3 = range.startColumn) !== null && _range$startColumn3 !== void 0 ? _range$startColumn3 : NaN) + 1;
440
- }, 0);
441
- }
442
- /**
443
- * Check if the provided ranges contain the provided cell
444
- * @param {GridRange[]} ranges The ranges to check
445
- * @param {number} column The column index
446
- * @param {number} row The row index
447
- * @returns {boolean} True if the cell is within the provided ranges, false otherwise.
448
- */
399
+ return start <= otherEnd + 1;
400
+ }
449
401
 
402
+ if (otherEnd == null) {
403
+ return end >= otherStart - 1;
404
+ }
450
405
 
451
- static containsCell(ranges, column, row) {
452
- for (var i = 0; i < ranges.length; i += 1) {
453
- var range = ranges[i];
406
+ if (otherStart >= start - 1) {
407
+ return otherStart <= end + 1;
408
+ }
454
409
 
455
- if (range.containsCell(column, row)) {
410
+ return otherEnd >= start - 1;
411
+ }
412
+ }, {
413
+ key: "rangeArraysEqual",
414
+ value: function rangeArraysEqual(ranges1, ranges2) {
415
+ if (ranges1 === ranges2) {
456
416
  return true;
457
417
  }
458
- }
459
-
460
- return false;
461
- }
462
- /**
463
- * Iterate through each cell in the provided ranges
464
- * @param {GridRange[]} ranges The ranges to iterate through
465
- * @param {(column: number, row: number, index: number) => void} callback The callback to execute. `index` is the index within that range
466
- * @param {GridRange.SELECTION_DIRECTION} direction The direction to iterate in
467
- */
468
418
 
419
+ if (ranges1 == null || ranges2 == null || ranges1.length !== ranges2.length) {
420
+ return false;
421
+ }
469
422
 
470
- static forEachCell(ranges, callback) {
471
- var direction = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : GridRange.SELECTION_DIRECTION.RIGHT;
423
+ for (var i = 0; i < ranges1.length; i += 1) {
424
+ if (!ranges1[i].equals(ranges2[i])) {
425
+ return false;
426
+ }
427
+ }
472
428
 
473
- for (var i = 0; i < ranges.length; i += 1) {
474
- ranges[i].forEach(callback, direction);
429
+ return true;
475
430
  }
476
- }
431
+ /**
432
+ * Get the intersection (overlapping area) of two ranges
433
+ * @param {GridRange} range One range to check for the intersection
434
+ * @param {GridRange} otherRange The other range to check for the intersection
435
+ * @returns {GridRange|null} Intersection of the two ranges. If they do not intersect, returns `null`.
436
+ */
437
+
438
+ }, {
439
+ key: "intersection",
440
+ value: function intersection(range, otherRange) {
441
+ var _startColumn2, _endColumn2, _startRow2, _endRow2;
442
+
443
+ if (range.equals(otherRange)) {
444
+ return range;
445
+ }
477
446
 
478
- constructor(startColumn, startRow, endColumn, endRow) {
479
- this.startColumn = startColumn;
480
- this.startRow = startRow;
481
- this.endColumn = endColumn;
482
- this.endRow = endRow;
483
- }
447
+ var startColumn = range.startColumn,
448
+ startRow = range.startRow,
449
+ endColumn = range.endColumn,
450
+ endRow = range.endRow;
451
+ startColumn = startColumn != null && otherRange.startColumn != null ? Math.max(startColumn, otherRange.startColumn) : (_startColumn2 = startColumn) !== null && _startColumn2 !== void 0 ? _startColumn2 : otherRange.startColumn;
452
+ endColumn = endColumn != null && otherRange.endColumn != null ? Math.min(endColumn, otherRange.endColumn) : (_endColumn2 = endColumn) !== null && _endColumn2 !== void 0 ? _endColumn2 : otherRange.endColumn;
453
+ startRow = startRow != null && otherRange.startRow != null ? Math.max(startRow, otherRange.startRow) : (_startRow2 = startRow) !== null && _startRow2 !== void 0 ? _startRow2 : otherRange.startRow;
454
+ endRow = endRow != null && otherRange.endRow != null ? Math.min(endRow, otherRange.endRow) : (_endRow2 = endRow) !== null && _endRow2 !== void 0 ? _endRow2 : otherRange.endRow;
455
+
456
+ if (startColumn != null && startColumn > endColumn || startRow != null && startRow > endRow) {
457
+ return null;
458
+ }
484
459
 
485
- equals(other) {
486
- return this.startColumn === other.startColumn && this.startRow === other.startRow && this.endColumn === other.endColumn && this.endRow === other.endRow;
487
- }
488
- /** @returns {boolean} true if this GridRange completely contains `other` */
460
+ return new GridRange(startColumn, startRow, endColumn, endRow);
461
+ }
462
+ /**
463
+ * @param {GridRange} range The range to be subtracted from
464
+ * @param {GridRange} subtractRange The range to subtract from within this range
465
+ * @returns {GridRange[]} The ranges needed to represent the remaining
466
+ */
489
467
 
468
+ }, {
469
+ key: "subtractFromRange",
470
+ value: function subtractFromRange(range, subtractRange) {
471
+ var result = []; // Make it a little easier by finding only the part the subtraction range intersects
490
472
 
491
- contains(other) {
492
- return (this.startColumn == null || other.startColumn != null && this.startColumn <= other.startColumn) && (this.startRow == null || other.startRow != null && this.startRow <= other.startRow) && (this.endColumn == null || other.endColumn != null && this.endColumn >= other.endColumn) && (this.endRow == null || other.endRow != null && this.endRow >= other.endRow);
493
- }
494
- /**
495
- * Check if the provided cell is in this range
496
- * @param {number} column The column to check
497
- * @param {number} row The row to check
498
- * @returns {boolean} True if this cell is within this range
499
- */
473
+ var subtract = GridRange.intersection(range, subtractRange);
500
474
 
475
+ if (subtract == null) {
476
+ return [range];
477
+ } // Go through each of the quadrants for deselection, there can be up to 4
478
+ // Top quadrant (above the subtracted area)
501
479
 
502
- containsCell(column, row) {
503
- if (column == null || row == null) {
504
- return false;
505
- }
506
480
 
507
- return (this.startColumn == null || this.startColumn <= column) && (this.endColumn == null || this.endColumn >= column) && (this.startRow == null || this.startRow <= row) && (this.endRow == null || this.endRow >= row);
508
- }
509
- /** @returns {boolean} true if this GridRange touches `other` */
481
+ if (subtract.startRow != null && (range.startRow == null || range.startRow < subtract.startRow)) {
482
+ result.push(new GridRange(range.startColumn, range.startRow, range.endColumn, subtract.startRow - 1));
483
+ } // middle left
510
484
 
511
485
 
512
- touches(other) {
513
- return GridRange.isAxisRangeTouching(this.startRow, this.endRow, other.startRow, other.endRow) && GridRange.isAxisRangeTouching(this.startColumn, this.endColumn, other.startColumn, other.endColumn);
514
- }
515
- /**
516
- * @param {GridRange} other The range to deselect from within this range
517
- * @returns {[GridRange]} The ranges needed to represent the remaining
518
- */
486
+ if (subtract.startColumn != null && (range.startColumn == null || range.startColumn < subtract.startColumn)) {
487
+ result.push(new GridRange(range.startColumn, subtract.startRow, subtract.startColumn - 1, subtract.endRow));
488
+ } // middle right
519
489
 
520
490
 
521
- subtract(other) {
522
- return GridRange.subtractFromRange(this, other);
523
- }
524
- /**
525
- * Get the first cell in this range. Throws if this range is unbounded.
526
- *
527
- * @param {GridRange.SELECTION_DIRECTION?} direction The direction to get the starting cell in. Defaults to DOWN
528
- * @returns {{column: number, row: number}} The first cell in this range in the direction specified
529
- */
491
+ if (subtract.endColumn != null && (range.endColumn == null || range.endColumn > subtract.endColumn)) {
492
+ result.push(new GridRange(subtract.endColumn + 1, subtract.startRow, range.endColumn, subtract.endRow));
493
+ } // Bottom quadrant
530
494
 
531
495
 
532
- startCell() {
533
- var direction = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : GridRange.SELECTION_DIRECTION.DOWN;
496
+ if (subtract.endRow != null && (range.endRow == null || range.endRow > subtract.endRow)) {
497
+ result.push(new GridRange(range.startColumn, subtract.endRow + 1, range.endColumn, range.endRow));
498
+ }
534
499
 
535
- if (!GridRange.isBounded(this)) {
536
- throw new Error('Cannot get the startCell of an unbounded range');
500
+ return result;
537
501
  }
502
+ /**
503
+ * Subtract a range from multiple ranges
504
+ * @param {GridRange[]} ranges The ranges to be subtracted from
505
+ * @param {GridRange} subtractRange The range to subtract from within these ranges
506
+ * @returns {GridRange[]} The ranges needed to represent the remaining
507
+ */
508
+
509
+ }, {
510
+ key: "subtractFromRanges",
511
+ value: function subtractFromRanges(ranges, subtractRange) {
512
+ var result = [];
513
+
514
+ for (var i = 0; i < ranges.length; i += 1) {
515
+ result.push.apply(result, _toConsumableArray(GridRange.subtractFromRange(ranges[i], subtractRange)));
516
+ }
538
517
 
539
- switch (direction) {
540
- case GridRange.SELECTION_DIRECTION.DOWN:
541
- case GridRange.SELECTION_DIRECTION.RIGHT:
542
- return {
543
- column: this.startColumn,
544
- row: this.startRow
545
- };
546
-
547
- case GridRange.SELECTION_DIRECTION.LEFT:
548
- case GridRange.SELECTION_DIRECTION.UP:
549
- {
550
- return {
551
- column: this.endColumn,
552
- row: this.endRow
553
- };
554
- }
555
-
556
- default:
557
- throw new Error("Invalid direction: ".concat(direction));
518
+ return result;
558
519
  }
559
- }
560
- /**
561
- * Get the next cell in the direction specified. Throws if this range is unbounded.
562
- * If already at the bounds of the range in that direction, wrap to the next column or row
563
- * If at the end of the entire range, return null
564
- * If outside of the range, returns the next cell closest within this range.
565
- *
566
- * @param {number} column The cursor column
567
- * @param {number} row The cursor row
568
- * @param {SELECTION_DIRECTION} direction The direction to go in
569
- * @returns {GridCell|null} The next cell in the direction specified, or `null` if at the end of the range
570
- */
571
-
572
-
573
- nextCell(column, row, direction) {
574
- if (!GridRange.isBounded(this)) {
575
- throw new Error('Bounded range required');
576
- }
577
-
578
- if (column == null || row == null) {
579
- throw new Error('Require a non-null cursor');
580
- }
581
-
582
- var {
583
- startColumn,
584
- endColumn,
585
- startRow,
586
- endRow
587
- } = this;
588
-
589
- switch (direction) {
590
- case GridRange.SELECTION_DIRECTION.DOWN:
591
- if (row < endRow) {
592
- return {
593
- column,
594
- row: Math.max(row + 1, startRow)
595
- };
596
- }
520
+ /**
521
+ * Subtract multiple ranges from multiple ranges
522
+ * @param {GridRange[]} ranges The ranges to be subtracted from
523
+ * @param {GridRange[]} subtractRanges The ranges to subtract from within these ranges
524
+ * @returns {GridRange[]} The ranges needed to represent the remaining
525
+ */
526
+
527
+ }, {
528
+ key: "subtractRangesFromRanges",
529
+ value: function subtractRangesFromRanges(ranges, subtractRanges) {
530
+ if (!subtractRanges || subtractRanges.length === 0) {
531
+ return ranges;
532
+ }
597
533
 
598
- if (column < endColumn) {
599
- return {
600
- column: Math.max(column + 1, startColumn),
601
- row: startRow
602
- };
603
- }
534
+ var result = _toConsumableArray(ranges);
604
535
 
605
- break;
536
+ for (var i = 0; i < subtractRanges.length; i += 1) {
537
+ result = GridRange.subtractFromRanges(result, subtractRanges[i]);
538
+ }
606
539
 
607
- case GridRange.SELECTION_DIRECTION.UP:
608
- if (row > startRow) {
609
- return {
610
- column,
611
- row: Math.min(row - 1, endRow)
612
- };
613
- }
540
+ return result;
541
+ }
542
+ /**
543
+ * Test if a given range is bounded (all values are non-null)
544
+ * @param {GridRange} range The range to test
545
+ * @returns {boolean} True if this range is bounded, false otherwise
546
+ */
547
+
548
+ }, {
549
+ key: "isBounded",
550
+ value: function isBounded(range) {
551
+ return range.startRow != null && range.startColumn != null && range.endRow != null && range.endColumn != null;
552
+ }
553
+ /**
554
+ * Converts any GridRange passed in that is a full row or column selection to be bound
555
+ * to the `columnCount` and `rowCount` passed in
556
+ *
557
+ * @param {GridRange} range The range to get the bounded range of
558
+ * @param {number} columnCount The number of columns
559
+ * @param {number} rowCount The number of rows
560
+ * @returns {GridRange} The passed in GridRange with any null values filled in
561
+ */
562
+
563
+ }, {
564
+ key: "boundedRange",
565
+ value: function boundedRange(range, columnCount, rowCount) {
566
+ var _range$startColumn, _range$startRow, _range$endColumn, _range$endRow;
567
+
568
+ if (GridRange.isBounded(range)) {
569
+ return range;
570
+ }
614
571
 
615
- if (column > startColumn) {
616
- return {
617
- column: Math.min(column - 1, endColumn),
618
- row: endRow
619
- };
620
- }
572
+ return new GridRange((_range$startColumn = range.startColumn) !== null && _range$startColumn !== void 0 ? _range$startColumn : 0, (_range$startRow = range.startRow) !== null && _range$startRow !== void 0 ? _range$startRow : 0, (_range$endColumn = range.endColumn) !== null && _range$endColumn !== void 0 ? _range$endColumn : columnCount - 1, (_range$endRow = range.endRow) !== null && _range$endRow !== void 0 ? _range$endRow : rowCount - 1);
573
+ }
574
+ /**
575
+ * Converts the GridRanges passed in to be bound to the `columnCount` and `rowCount` passed in
576
+ *
577
+ * @param {GridRange[]} ranges The ranges to get the bounded ranges of
578
+ * @param {number} columnCount The number of columns
579
+ * @param {number} rowCount The number of rows
580
+ * @returns {GridRange} The passed in GridRange with any null values filled in
581
+ */
582
+
583
+ }, {
584
+ key: "boundedRanges",
585
+ value: function boundedRanges(ranges, columnCount, rowCount) {
586
+ return ranges.map(function (r) {
587
+ return GridRange.boundedRange(r, columnCount, rowCount);
588
+ });
589
+ }
590
+ /**
591
+ * Offsets a GridRange by the specified amount in the x and y directions
592
+ *
593
+ * @param {GridRange} range The range to offset
594
+ * @param {number} columnOffset The number of columns to offset
595
+ * @param {number} rowOffset The number of rows to offset
596
+ * @returns {GridRange} The new grid range offset from the original
597
+ */
598
+
599
+ }, {
600
+ key: "offset",
601
+ value: function offset(range, columnOffset, rowOffset) {
602
+ return new GridRange(range.startColumn != null ? range.startColumn + columnOffset : null, range.startRow != null ? range.startRow + rowOffset : null, range.endColumn != null ? range.endColumn + columnOffset : null, range.endRow != null ? range.endRow + rowOffset : null);
603
+ }
604
+ /**
605
+ * Get the next cell given the selected ranges and the current cell
606
+ * @param {GridRange[]} ranges The selected bounded ranges within the grid
607
+ * @param {number|null} column The cursor column, or null if none focused
608
+ * @param {number|null} row The cursor row, or null if none focused
609
+ * @param {SELECTION_DIRECTION} direction The direction in which to select next
610
+ * @returns {Cell} The next cell to focus, or null if there should be no more focus
611
+ */
612
+
613
+ }, {
614
+ key: "nextCell",
615
+ value: function nextCell(ranges) {
616
+ var column = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
617
+ var row = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
618
+ var direction = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : GridRange.SELECTION_DIRECTION.DOWN;
619
+
620
+ if (ranges.length === 0) {
621
+ return null;
622
+ }
621
623
 
622
- break;
624
+ var rangeIndex = -1;
623
625
 
624
- case GridRange.SELECTION_DIRECTION.RIGHT:
625
- if (column < endColumn) {
626
- return {
627
- column: Math.max(column + 1, startColumn),
628
- row
629
- };
630
- }
626
+ if (column != null && row != null) {
627
+ rangeIndex = ranges.findIndex(function (r) {
628
+ return r.containsCell(column, row);
629
+ });
631
630
 
632
- if (row < endRow) {
633
- return {
634
- column: startColumn,
635
- row: Math.max(row + 1, startRow)
636
- };
631
+ if (rangeIndex >= 0) {
632
+ var range = ranges[rangeIndex];
633
+ var nextCell = range.nextCell(column, row, direction);
634
+
635
+ if (nextCell != null) {
636
+ return nextCell;
637
+ }
637
638
  }
639
+ } // Otherwise go to the start of the next range (could be same range if only one range)
638
640
 
639
- break;
640
641
 
641
- case GridRange.SELECTION_DIRECTION.LEFT:
642
- if (column > startColumn) {
643
- return {
644
- column: Math.min(column - 1, endColumn),
645
- row
646
- };
647
- }
642
+ switch (direction) {
643
+ case GridRange.SELECTION_DIRECTION.DOWN:
644
+ case GridRange.SELECTION_DIRECTION.RIGHT:
645
+ {
646
+ var nextRangeIndex = rangeIndex < ranges.length - 1 ? rangeIndex + 1 : 0;
647
+ var nextRange = ranges[nextRangeIndex];
648
+ return nextRange.startCell(direction);
649
+ }
648
650
 
649
- if (row > startRow) {
650
- return {
651
- column: endColumn,
652
- row: Math.min(row - 1, endRow)
653
- };
654
- }
651
+ case GridRange.SELECTION_DIRECTION.LEFT:
652
+ case GridRange.SELECTION_DIRECTION.UP:
653
+ {
654
+ var _nextRangeIndex = rangeIndex > 0 ? rangeIndex - 1 : ranges.length - 1;
655
655
 
656
- break;
656
+ var _nextRange = ranges[_nextRangeIndex];
657
+ return _nextRange.startCell(direction);
658
+ }
657
659
 
658
- default:
659
- throw new Error("Invalid direction: ".concat(direction));
660
+ default:
661
+ throw new Error("Invalid direction: ".concat(direction));
662
+ }
663
+ }
664
+ /**
665
+ * Count the number of cells in the provided grid ranges
666
+ * @param {GridRange[]} ranges The ranges to count the rows of
667
+ * @returns {number|NaN} The number of cells in the ranges, or `NaN` if any of the ranges were unbounded
668
+ */
669
+
670
+ }, {
671
+ key: "cellCount",
672
+ value: function cellCount(ranges) {
673
+ return ranges.reduce(function (cellCount, range) {
674
+ var _range$endRow2, _range$startRow2, _range$endColumn2, _range$startColumn2;
675
+
676
+ return cellCount + (((_range$endRow2 = range.endRow) !== null && _range$endRow2 !== void 0 ? _range$endRow2 : NaN) - ((_range$startRow2 = range.startRow) !== null && _range$startRow2 !== void 0 ? _range$startRow2 : NaN) + 1) * (((_range$endColumn2 = range.endColumn) !== null && _range$endColumn2 !== void 0 ? _range$endColumn2 : NaN) - ((_range$startColumn2 = range.startColumn) !== null && _range$startColumn2 !== void 0 ? _range$startColumn2 : NaN) + 1);
677
+ }, 0);
660
678
  }
679
+ /**
680
+ * Count the number of rows in the provided grid ranges
681
+ * @param {GridRange[]} ranges The ranges to count the rows of
682
+ * @returns {number|NaN} The number of rows in the ranges, or `NaN` if any of the ranges were unbounded
683
+ */
684
+
685
+ }, {
686
+ key: "rowCount",
687
+ value: function rowCount(ranges) {
688
+ return ranges.reduce(function (rowCount, range) {
689
+ var _range$endRow3, _range$startRow3;
690
+
691
+ return rowCount + ((_range$endRow3 = range.endRow) !== null && _range$endRow3 !== void 0 ? _range$endRow3 : NaN) - ((_range$startRow3 = range.startRow) !== null && _range$startRow3 !== void 0 ? _range$startRow3 : NaN) + 1;
692
+ }, 0);
693
+ }
694
+ /**
695
+ * Count the number of columns in the provided grid ranges
696
+ * @param {GridRange[]} ranges The ranges to count the columns of
697
+ * @returns {number|NaN} The number of columns in the ranges, or `NaN` if any of the ranges were unbounded
698
+ */
699
+
700
+ }, {
701
+ key: "columnCount",
702
+ value: function columnCount(ranges) {
703
+ return ranges.reduce(function (columnCount, range) {
704
+ var _range$endColumn3, _range$startColumn3;
705
+
706
+ return columnCount + ((_range$endColumn3 = range.endColumn) !== null && _range$endColumn3 !== void 0 ? _range$endColumn3 : NaN) - ((_range$startColumn3 = range.startColumn) !== null && _range$startColumn3 !== void 0 ? _range$startColumn3 : NaN) + 1;
707
+ }, 0);
708
+ }
709
+ /**
710
+ * Check if the provided ranges contain the provided cell
711
+ * @param {GridRange[]} ranges The ranges to check
712
+ * @param {number} column The column index
713
+ * @param {number} row The row index
714
+ * @returns {boolean} True if the cell is within the provided ranges, false otherwise.
715
+ */
716
+
717
+ }, {
718
+ key: "containsCell",
719
+ value: function containsCell(ranges, column, row) {
720
+ for (var i = 0; i < ranges.length; i += 1) {
721
+ var range = ranges[i];
722
+
723
+ if (range.containsCell(column, row)) {
724
+ return true;
725
+ }
726
+ }
661
727
 
662
- return null;
663
- }
664
- /**
665
- * Iterate through each cell in the range
666
- * @param {(column:number, row:number, index:number) => void} callback Callback to execute. `index` is the index within this range
667
- * @param {GridRange.SELECTION_DIRECTION} direction The direction to iterate in
668
- */
669
-
670
-
671
- forEach(callback) {
672
- var direction = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : GridRange.SELECTION_DIRECTION.RIGHT;
673
- var i = 0;
674
- var {
675
- column: c,
676
- row: r
677
- } = this.startCell(direction);
678
-
679
- while (c != null && r != null) {
680
- var _this$nextCell;
681
-
682
- callback(c, r, i);
683
- i += 1;
684
- ({
685
- column: c,
686
- row: r
687
- } = (_this$nextCell = this.nextCell(c, r, direction)) !== null && _this$nextCell !== void 0 ? _this$nextCell : {});
728
+ return false;
688
729
  }
689
- }
730
+ /**
731
+ * Iterate through each cell in the provided ranges
732
+ * @param {GridRange[]} ranges The ranges to iterate through
733
+ * @param {(column: number, row: number, index: number) => void} callback The callback to execute. `index` is the index within that range
734
+ * @param {GridRange.SELECTION_DIRECTION} direction The direction to iterate in
735
+ */
736
+
737
+ }, {
738
+ key: "forEachCell",
739
+ value: function forEachCell(ranges, callback) {
740
+ var direction = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : GridRange.SELECTION_DIRECTION.RIGHT;
741
+
742
+ for (var i = 0; i < ranges.length; i += 1) {
743
+ ranges[i].forEach(callback, direction);
744
+ }
745
+ }
746
+ }]);
690
747
 
691
- }
748
+ return GridRange;
749
+ }();
692
750
 
693
751
  _defineProperty(GridRange, "SELECTION_DIRECTION", Object.freeze({
694
752
  DOWN: 'DOWN',