react-window 1.8.1 → 1.8.5

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.
package/dist/index.cjs.js CHANGED
@@ -59,6 +59,50 @@ function getScrollbarSize(recalculate) {
59
59
 
60
60
  return size;
61
61
  }
62
+ var cachedRTLResult = null; // TRICKY According to the spec, scrollLeft should be negative for RTL aligned elements.
63
+ // Chrome does not seem to adhere; its scrollLeft values are positive (measured relative to the left).
64
+ // Safari's elastic bounce makes detecting this even more complicated wrt potential false positives.
65
+ // The safest way to check this is to intentionally set a negative offset,
66
+ // and then verify that the subsequent "scroll" event matches the negative offset.
67
+ // If it does not match, then we can assume a non-standard RTL scroll implementation.
68
+
69
+ function getRTLOffsetType(recalculate) {
70
+ if (recalculate === void 0) {
71
+ recalculate = false;
72
+ }
73
+
74
+ if (cachedRTLResult === null || recalculate) {
75
+ var outerDiv = document.createElement('div');
76
+ var outerStyle = outerDiv.style;
77
+ outerStyle.width = '50px';
78
+ outerStyle.height = '50px';
79
+ outerStyle.overflow = 'scroll';
80
+ outerStyle.direction = 'rtl';
81
+ var innerDiv = document.createElement('div');
82
+ var innerStyle = innerDiv.style;
83
+ innerStyle.width = '100px';
84
+ innerStyle.height = '100px';
85
+ outerDiv.appendChild(innerDiv);
86
+ document.body.appendChild(outerDiv);
87
+
88
+ if (outerDiv.scrollLeft > 0) {
89
+ cachedRTLResult = 'positive-descending';
90
+ } else {
91
+ outerDiv.scrollLeft = 1;
92
+
93
+ if (outerDiv.scrollLeft === 0) {
94
+ cachedRTLResult = 'negative';
95
+ } else {
96
+ cachedRTLResult = 'positive-ascending';
97
+ }
98
+ }
99
+
100
+ document.body.removeChild(outerDiv);
101
+ return cachedRTLResult;
102
+ }
103
+
104
+ return cachedRTLResult;
105
+ }
62
106
 
63
107
  var IS_SCROLLING_DEBOUNCE_INTERVAL = 150;
64
108
 
@@ -72,6 +116,7 @@ var defaultItemKey = function defaultItemKey(_ref) {
72
116
 
73
117
 
74
118
  var devWarningsOverscanCount = null;
119
+ var devWarningsOverscanRowsColumnsCount = null;
75
120
  var devWarningsTagName = null;
76
121
 
77
122
  if (process.env.NODE_ENV !== 'production') {
@@ -79,6 +124,9 @@ if (process.env.NODE_ENV !== 'production') {
79
124
  devWarningsOverscanCount =
80
125
  /*#__PURE__*/
81
126
  new WeakSet();
127
+ devWarningsOverscanRowsColumnsCount =
128
+ /*#__PURE__*/
129
+ new WeakSet();
82
130
  devWarningsTagName =
83
131
  /*#__PURE__*/
84
132
  new WeakSet();
@@ -183,9 +231,11 @@ function createGridComponent(_ref2) {
183
231
 
184
232
  _this._onScroll = function (event) {
185
233
  var _event$currentTarget = event.currentTarget,
234
+ clientHeight = _event$currentTarget.clientHeight,
186
235
  clientWidth = _event$currentTarget.clientWidth,
187
236
  scrollLeft = _event$currentTarget.scrollLeft,
188
237
  scrollTop = _event$currentTarget.scrollTop,
238
+ scrollHeight = _event$currentTarget.scrollHeight,
189
239
  scrollWidth = _event$currentTarget.scrollWidth;
190
240
 
191
241
  _this.setState(function (prevState) {
@@ -196,25 +246,33 @@ function createGridComponent(_ref2) {
196
246
  return null;
197
247
  }
198
248
 
199
- var direction = _this.props.direction; // HACK According to the spec, scrollLeft should be negative for RTL aligned elements.
200
- // Chrome does not seem to adhere; its scrollLeft values are positive (measured relative to the left).
201
- // See https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollLeft
249
+ var direction = _this.props.direction; // TRICKY According to the spec, scrollLeft should be negative for RTL aligned elements.
250
+ // This is not the case for all browsers though (e.g. Chrome reports values as positive, measured relative to the left).
251
+ // It's also easier for this component if we convert offsets to the same format as they would be in for ltr.
252
+ // So the simplest solution is to determine which browser behavior we're dealing with, and convert based on it.
202
253
 
203
254
  var calculatedScrollLeft = scrollLeft;
204
255
 
205
256
  if (direction === 'rtl') {
206
- if (scrollLeft <= 0) {
207
- calculatedScrollLeft = -scrollLeft;
208
- } else {
209
- calculatedScrollLeft = scrollWidth - clientWidth - scrollLeft;
257
+ switch (getRTLOffsetType()) {
258
+ case 'negative':
259
+ calculatedScrollLeft = -scrollLeft;
260
+ break;
261
+
262
+ case 'positive-descending':
263
+ calculatedScrollLeft = scrollWidth - clientWidth - scrollLeft;
264
+ break;
210
265
  }
211
- }
266
+ } // Prevent Safari's elastic scrolling from causing visual shaking when scrolling past bounds.
267
+
212
268
 
269
+ calculatedScrollLeft = Math.max(0, Math.min(calculatedScrollLeft, scrollWidth - clientWidth));
270
+ var calculatedScrollTop = Math.max(0, Math.min(scrollTop, scrollHeight - clientHeight));
213
271
  return {
214
272
  isScrolling: true,
215
273
  horizontalScrollDirection: prevState.scrollLeft < scrollLeft ? 'forward' : 'backward',
216
274
  scrollLeft: calculatedScrollLeft,
217
- scrollTop: scrollTop,
275
+ scrollTop: calculatedScrollTop,
218
276
  verticalScrollDirection: prevState.scrollTop < scrollTop ? 'forward' : 'backward',
219
277
  scrollUpdateWasRequested: false
220
278
  };
@@ -339,26 +397,55 @@ function createGridComponent(_ref2) {
339
397
  initialScrollLeft = _this$props3.initialScrollLeft,
340
398
  initialScrollTop = _this$props3.initialScrollTop;
341
399
 
342
- if (typeof initialScrollLeft === 'number' && this._outerRef != null) {
343
- this._outerRef.scrollLeft = initialScrollLeft;
344
- }
400
+ if (this._outerRef != null) {
401
+ var outerRef = this._outerRef;
402
+
403
+ if (typeof initialScrollLeft === 'number') {
404
+ outerRef.scrollLeft = initialScrollLeft;
405
+ }
345
406
 
346
- if (typeof initialScrollTop === 'number' && this._outerRef != null) {
347
- this._outerRef.scrollTop = initialScrollTop;
407
+ if (typeof initialScrollTop === 'number') {
408
+ outerRef.scrollTop = initialScrollTop;
409
+ }
348
410
  }
349
411
 
350
412
  this._callPropsCallbacks();
351
413
  };
352
414
 
353
415
  _proto.componentDidUpdate = function componentDidUpdate() {
416
+ var direction = this.props.direction;
354
417
  var _this$state2 = this.state,
355
418
  scrollLeft = _this$state2.scrollLeft,
356
419
  scrollTop = _this$state2.scrollTop,
357
420
  scrollUpdateWasRequested = _this$state2.scrollUpdateWasRequested;
358
421
 
359
- if (scrollUpdateWasRequested && this._outerRef !== null) {
360
- this._outerRef.scrollLeft = scrollLeft;
361
- this._outerRef.scrollTop = scrollTop;
422
+ if (scrollUpdateWasRequested && this._outerRef != null) {
423
+ // TRICKY According to the spec, scrollLeft should be negative for RTL aligned elements.
424
+ // This is not the case for all browsers though (e.g. Chrome reports values as positive, measured relative to the left).
425
+ // So we need to determine which browser behavior we're dealing with, and mimic it.
426
+ var outerRef = this._outerRef;
427
+
428
+ if (direction === 'rtl') {
429
+ switch (getRTLOffsetType()) {
430
+ case 'negative':
431
+ outerRef.scrollLeft = -scrollLeft;
432
+ break;
433
+
434
+ case 'positive-ascending':
435
+ outerRef.scrollLeft = scrollLeft;
436
+ break;
437
+
438
+ default:
439
+ var clientWidth = outerRef.clientWidth,
440
+ scrollWidth = outerRef.scrollWidth;
441
+ outerRef.scrollLeft = scrollWidth - clientWidth - scrollLeft;
442
+ break;
443
+ }
444
+ } else {
445
+ outerRef.scrollLeft = Math.max(0, scrollLeft);
446
+ }
447
+
448
+ outerRef.scrollTop = Math.max(0, scrollTop);
362
449
  }
363
450
 
364
451
  this._callPropsCallbacks();
@@ -492,6 +579,7 @@ function createGridComponent(_ref2) {
492
579
  _proto._getHorizontalRangeToRender = function _getHorizontalRangeToRender() {
493
580
  var _this$props6 = this.props,
494
581
  columnCount = _this$props6.columnCount,
582
+ overscanColumnCount = _this$props6.overscanColumnCount,
495
583
  overscanColumnsCount = _this$props6.overscanColumnsCount,
496
584
  overscanCount = _this$props6.overscanCount,
497
585
  rowCount = _this$props6.rowCount;
@@ -499,7 +587,7 @@ function createGridComponent(_ref2) {
499
587
  horizontalScrollDirection = _this$state4.horizontalScrollDirection,
500
588
  isScrolling = _this$state4.isScrolling,
501
589
  scrollLeft = _this$state4.scrollLeft;
502
- var overscanCountResolved = overscanColumnsCount || overscanCount || 1;
590
+ var overscanCountResolved = overscanColumnCount || overscanColumnsCount || overscanCount || 1;
503
591
 
504
592
  if (columnCount === 0 || rowCount === 0) {
505
593
  return [0, 0, 0, 0];
@@ -518,13 +606,14 @@ function createGridComponent(_ref2) {
518
606
  var _this$props7 = this.props,
519
607
  columnCount = _this$props7.columnCount,
520
608
  overscanCount = _this$props7.overscanCount,
609
+ overscanRowCount = _this$props7.overscanRowCount,
521
610
  overscanRowsCount = _this$props7.overscanRowsCount,
522
611
  rowCount = _this$props7.rowCount;
523
612
  var _this$state5 = this.state,
524
613
  isScrolling = _this$state5.isScrolling,
525
614
  verticalScrollDirection = _this$state5.verticalScrollDirection,
526
615
  scrollTop = _this$state5.scrollTop;
527
- var overscanCountResolved = overscanRowsCount || overscanCount || 1;
616
+ var overscanCountResolved = overscanRowCount || overscanRowsCount || overscanCount || 1;
528
617
 
529
618
  if (columnCount === 0 || rowCount === 0) {
530
619
  return [0, 0, 0, 0];
@@ -553,7 +642,9 @@ var validateSharedProps = function validateSharedProps(_ref5, _ref6) {
553
642
  height = _ref5.height,
554
643
  innerTagName = _ref5.innerTagName,
555
644
  outerTagName = _ref5.outerTagName,
645
+ overscanColumnsCount = _ref5.overscanColumnsCount,
556
646
  overscanCount = _ref5.overscanCount,
647
+ overscanRowsCount = _ref5.overscanRowsCount,
557
648
  width = _ref5.width;
558
649
  var instance = _ref6.instance;
559
650
 
@@ -561,7 +652,14 @@ var validateSharedProps = function validateSharedProps(_ref5, _ref6) {
561
652
  if (typeof overscanCount === 'number') {
562
653
  if (devWarningsOverscanCount && !devWarningsOverscanCount.has(instance)) {
563
654
  devWarningsOverscanCount.add(instance);
564
- console.warn('The overscanCount prop has been deprecated. ' + 'Please use the overscanColumnsCount and overscanRowsCount props instead.');
655
+ console.warn('The overscanCount prop has been deprecated. ' + 'Please use the overscanColumnCount and overscanRowCount props instead.');
656
+ }
657
+ }
658
+
659
+ if (typeof overscanColumnsCount === 'number' || typeof overscanRowsCount === 'number') {
660
+ if (devWarningsOverscanRowsColumnsCount && !devWarningsOverscanRowsColumnsCount.has(instance)) {
661
+ devWarningsOverscanRowsColumnsCount.add(instance);
662
+ console.warn('The overscanColumnsCount and overscanRowsCount props have been deprecated. ' + 'Please use the overscanColumnCount and overscanRowCount props instead.');
565
663
  }
566
664
  }
567
665
 
@@ -770,7 +868,11 @@ var getOffsetForIndexAndAlignment = function getOffsetForIndexAndAlignment(itemT
770
868
  default:
771
869
  if (scrollOffset >= minOffset && scrollOffset <= maxOffset) {
772
870
  return scrollOffset;
773
- } else if (scrollOffset - minOffset < maxOffset - scrollOffset) {
871
+ } else if (minOffset > maxOffset) {
872
+ // Because we only take into account the scrollbar size when calculating minOffset
873
+ // this value can be larger than maxOffset when at the end of the list
874
+ return minOffset;
875
+ } else if (scrollOffset < minOffset) {
774
876
  return minOffset;
775
877
  } else {
776
878
  return maxOffset;
@@ -1037,20 +1139,27 @@ function createListComponent(_ref) {
1037
1139
  return null;
1038
1140
  }
1039
1141
 
1040
- var direction = _this.props.direction; // HACK According to the spec, scrollLeft should be negative for RTL aligned elements.
1041
- // Chrome does not seem to adhere; its scrolLeft values are positive (measured relative to the left).
1042
- // See https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollLeft
1043
-
1142
+ var direction = _this.props.direction;
1044
1143
  var scrollOffset = scrollLeft;
1045
1144
 
1046
1145
  if (direction === 'rtl') {
1047
- if (scrollLeft <= 0) {
1048
- scrollOffset = -scrollOffset;
1049
- } else {
1050
- scrollOffset = scrollWidth - clientWidth - scrollLeft;
1146
+ // TRICKY According to the spec, scrollLeft should be negative for RTL aligned elements.
1147
+ // This is not the case for all browsers though (e.g. Chrome reports values as positive, measured relative to the left).
1148
+ // It's also easier for this component if we convert offsets to the same format as they would be in for ltr.
1149
+ // So the simplest solution is to determine which browser behavior we're dealing with, and convert based on it.
1150
+ switch (getRTLOffsetType()) {
1151
+ case 'negative':
1152
+ scrollOffset = -scrollLeft;
1153
+ break;
1154
+
1155
+ case 'positive-descending':
1156
+ scrollOffset = scrollWidth - clientWidth - scrollLeft;
1157
+ break;
1051
1158
  }
1052
- }
1159
+ } // Prevent Safari's elastic scrolling from causing visual shaking when scrolling past bounds.
1160
+
1053
1161
 
1162
+ scrollOffset = Math.max(0, Math.min(scrollOffset, scrollWidth - clientWidth));
1054
1163
  return {
1055
1164
  isScrolling: true,
1056
1165
  scrollDirection: prevState.scrollOffset < scrollLeft ? 'forward' : 'backward',
@@ -1061,7 +1170,10 @@ function createListComponent(_ref) {
1061
1170
  };
1062
1171
 
1063
1172
  _this._onScrollVertical = function (event) {
1064
- var scrollTop = event.currentTarget.scrollTop;
1173
+ var _event$currentTarget2 = event.currentTarget,
1174
+ clientHeight = _event$currentTarget2.clientHeight,
1175
+ scrollHeight = _event$currentTarget2.scrollHeight,
1176
+ scrollTop = _event$currentTarget2.scrollTop;
1065
1177
 
1066
1178
  _this.setState(function (prevState) {
1067
1179
  if (prevState.scrollOffset === scrollTop) {
@@ -1069,12 +1181,14 @@ function createListComponent(_ref) {
1069
1181
  // In which case we don't need to trigger another render,
1070
1182
  // And we don't want to update state.isScrolling.
1071
1183
  return null;
1072
- }
1184
+ } // Prevent Safari's elastic scrolling from causing visual shaking when scrolling past bounds.
1073
1185
 
1186
+
1187
+ var scrollOffset = Math.max(0, Math.min(scrollTop, scrollHeight - clientHeight));
1074
1188
  return {
1075
1189
  isScrolling: true,
1076
- scrollDirection: prevState.scrollOffset < scrollTop ? 'forward' : 'backward',
1077
- scrollOffset: scrollTop,
1190
+ scrollDirection: prevState.scrollOffset < scrollOffset ? 'forward' : 'backward',
1191
+ scrollOffset: scrollOffset,
1078
1192
  scrollUpdateWasRequested: false
1079
1193
  };
1080
1194
  }, _this._resetIsScrollingDebounced);
@@ -1154,12 +1268,13 @@ function createListComponent(_ref) {
1154
1268
  initialScrollOffset = _this$props2.initialScrollOffset,
1155
1269
  layout = _this$props2.layout;
1156
1270
 
1157
- if (typeof initialScrollOffset === 'number' && this._outerRef !== null) {
1158
- // TODO Deprecate direction "horizontal"
1271
+ if (typeof initialScrollOffset === 'number' && this._outerRef != null) {
1272
+ var outerRef = this._outerRef; // TODO Deprecate direction "horizontal"
1273
+
1159
1274
  if (direction === 'horizontal' || layout === 'horizontal') {
1160
- this._outerRef.scrollLeft = initialScrollOffset;
1275
+ outerRef.scrollLeft = initialScrollOffset;
1161
1276
  } else {
1162
- this._outerRef.scrollTop = initialScrollOffset;
1277
+ outerRef.scrollTop = initialScrollOffset;
1163
1278
  }
1164
1279
  }
1165
1280
 
@@ -1174,12 +1289,34 @@ function createListComponent(_ref) {
1174
1289
  scrollOffset = _this$state.scrollOffset,
1175
1290
  scrollUpdateWasRequested = _this$state.scrollUpdateWasRequested;
1176
1291
 
1177
- if (scrollUpdateWasRequested && this._outerRef !== null) {
1178
- // TODO Deprecate direction "horizontal"
1292
+ if (scrollUpdateWasRequested && this._outerRef != null) {
1293
+ var outerRef = this._outerRef; // TODO Deprecate direction "horizontal"
1294
+
1179
1295
  if (direction === 'horizontal' || layout === 'horizontal') {
1180
- this._outerRef.scrollLeft = scrollOffset;
1296
+ if (direction === 'rtl') {
1297
+ // TRICKY According to the spec, scrollLeft should be negative for RTL aligned elements.
1298
+ // This is not the case for all browsers though (e.g. Chrome reports values as positive, measured relative to the left).
1299
+ // So we need to determine which browser behavior we're dealing with, and mimic it.
1300
+ switch (getRTLOffsetType()) {
1301
+ case 'negative':
1302
+ outerRef.scrollLeft = -scrollOffset;
1303
+ break;
1304
+
1305
+ case 'positive-ascending':
1306
+ outerRef.scrollLeft = scrollOffset;
1307
+ break;
1308
+
1309
+ default:
1310
+ var clientWidth = outerRef.clientWidth,
1311
+ scrollWidth = outerRef.scrollWidth;
1312
+ outerRef.scrollLeft = scrollWidth - clientWidth - scrollOffset;
1313
+ break;
1314
+ }
1315
+ } else {
1316
+ outerRef.scrollLeft = scrollOffset;
1317
+ }
1181
1318
  } else {
1182
- this._outerRef.scrollTop = scrollOffset;
1319
+ outerRef.scrollTop = scrollOffset;
1183
1320
  }
1184
1321
  }
1185
1322
 
@@ -1537,7 +1674,7 @@ createListComponent({
1537
1674
  default:
1538
1675
  if (scrollOffset >= minOffset && scrollOffset <= maxOffset) {
1539
1676
  return scrollOffset;
1540
- } else if (scrollOffset - minOffset < maxOffset - scrollOffset) {
1677
+ } else if (scrollOffset < minOffset) {
1541
1678
  return minOffset;
1542
1679
  } else {
1543
1680
  return maxOffset;
@@ -1642,7 +1779,8 @@ createGridComponent({
1642
1779
  var columnCount = _ref7.columnCount,
1643
1780
  columnWidth = _ref7.columnWidth,
1644
1781
  width = _ref7.width;
1645
- var maxOffset = Math.max(0, Math.min(columnCount * columnWidth - width, columnIndex * columnWidth));
1782
+ var lastColumnOffset = Math.max(0, columnCount * columnWidth - width);
1783
+ var maxOffset = Math.min(lastColumnOffset, columnIndex * columnWidth);
1646
1784
  var minOffset = Math.max(0, columnIndex * columnWidth - width + scrollbarSize + columnWidth);
1647
1785
 
1648
1786
  if (align === 'smart') {
@@ -1661,13 +1799,27 @@ createGridComponent({
1661
1799
  return minOffset;
1662
1800
 
1663
1801
  case 'center':
1664
- return Math.round(minOffset + (maxOffset - minOffset) / 2);
1802
+ // "Centered" offset is usually the average of the min and max.
1803
+ // But near the edges of the list, this doesn't hold true.
1804
+ var middleOffset = Math.round(minOffset + (maxOffset - minOffset) / 2);
1805
+
1806
+ if (middleOffset < Math.ceil(width / 2)) {
1807
+ return 0; // near the beginning
1808
+ } else if (middleOffset > lastColumnOffset + Math.floor(width / 2)) {
1809
+ return lastColumnOffset; // near the end
1810
+ } else {
1811
+ return middleOffset;
1812
+ }
1665
1813
 
1666
1814
  case 'auto':
1667
1815
  default:
1668
1816
  if (scrollLeft >= minOffset && scrollLeft <= maxOffset) {
1669
1817
  return scrollLeft;
1670
- } else if (scrollLeft - minOffset < maxOffset - scrollLeft) {
1818
+ } else if (minOffset > maxOffset) {
1819
+ // Because we only take into account the scrollbar size when calculating minOffset
1820
+ // this value can be larger than maxOffset when at the end of the list
1821
+ return minOffset;
1822
+ } else if (scrollLeft < minOffset) {
1671
1823
  return minOffset;
1672
1824
  } else {
1673
1825
  return maxOffset;
@@ -1679,7 +1831,8 @@ createGridComponent({
1679
1831
  var rowHeight = _ref8.rowHeight,
1680
1832
  height = _ref8.height,
1681
1833
  rowCount = _ref8.rowCount;
1682
- var maxOffset = Math.max(0, Math.min(rowCount * rowHeight - height, rowIndex * rowHeight));
1834
+ var lastRowOffset = Math.max(0, rowCount * rowHeight - height);
1835
+ var maxOffset = Math.min(lastRowOffset, rowIndex * rowHeight);
1683
1836
  var minOffset = Math.max(0, rowIndex * rowHeight - height + scrollbarSize + rowHeight);
1684
1837
 
1685
1838
  if (align === 'smart') {
@@ -1698,13 +1851,27 @@ createGridComponent({
1698
1851
  return minOffset;
1699
1852
 
1700
1853
  case 'center':
1701
- return Math.round(minOffset + (maxOffset - minOffset) / 2);
1854
+ // "Centered" offset is usually the average of the min and max.
1855
+ // But near the edges of the list, this doesn't hold true.
1856
+ var middleOffset = Math.round(minOffset + (maxOffset - minOffset) / 2);
1857
+
1858
+ if (middleOffset < Math.ceil(height / 2)) {
1859
+ return 0; // near the beginning
1860
+ } else if (middleOffset > lastRowOffset + Math.floor(height / 2)) {
1861
+ return lastRowOffset; // near the end
1862
+ } else {
1863
+ return middleOffset;
1864
+ }
1702
1865
 
1703
1866
  case 'auto':
1704
1867
  default:
1705
1868
  if (scrollTop >= minOffset && scrollTop <= maxOffset) {
1706
1869
  return scrollTop;
1707
- } else if (scrollTop - minOffset < maxOffset - scrollTop) {
1870
+ } else if (minOffset > maxOffset) {
1871
+ // Because we only take into account the scrollbar size when calculating minOffset
1872
+ // this value can be larger than maxOffset when at the end of the list
1873
+ return minOffset;
1874
+ } else if (scrollTop < minOffset) {
1708
1875
  return minOffset;
1709
1876
  } else {
1710
1877
  return maxOffset;
@@ -1722,7 +1889,9 @@ createGridComponent({
1722
1889
  columnCount = _ref10.columnCount,
1723
1890
  width = _ref10.width;
1724
1891
  var left = startIndex * columnWidth;
1725
- return Math.max(0, Math.min(columnCount - 1, startIndex + Math.floor((width + (scrollLeft - left)) / columnWidth)));
1892
+ var numVisibleColumns = Math.ceil((width + scrollLeft - left) / columnWidth);
1893
+ return Math.max(0, Math.min(columnCount - 1, startIndex + numVisibleColumns - 1 // -1 is because stop index is inclusive
1894
+ ));
1726
1895
  },
1727
1896
  getRowStartIndexForOffset: function getRowStartIndexForOffset(_ref11, scrollTop) {
1728
1897
  var rowHeight = _ref11.rowHeight,
@@ -1733,8 +1902,10 @@ createGridComponent({
1733
1902
  var rowHeight = _ref12.rowHeight,
1734
1903
  rowCount = _ref12.rowCount,
1735
1904
  height = _ref12.height;
1736
- var left = startIndex * rowHeight;
1737
- return Math.max(0, Math.min(rowCount - 1, startIndex + Math.floor((height + (scrollTop - left)) / rowHeight)));
1905
+ var top = startIndex * rowHeight;
1906
+ var numVisibleRows = Math.ceil((height + scrollTop - top) / rowHeight);
1907
+ return Math.max(0, Math.min(rowCount - 1, startIndex + numVisibleRows - 1 // -1 is because stop index is inclusive
1908
+ ));
1738
1909
  },
1739
1910
  initInstanceProps: function initInstanceProps(props) {// Noop
1740
1911
  },
@@ -1759,13 +1930,11 @@ var FixedSizeList =
1759
1930
  /*#__PURE__*/
1760
1931
  createListComponent({
1761
1932
  getItemOffset: function getItemOffset(_ref, index) {
1762
- var itemSize = _ref.itemSize,
1763
- size = _ref.size;
1933
+ var itemSize = _ref.itemSize;
1764
1934
  return index * itemSize;
1765
1935
  },
1766
1936
  getItemSize: function getItemSize(_ref2, index) {
1767
- var itemSize = _ref2.itemSize,
1768
- size = _ref2.size;
1937
+ var itemSize = _ref2.itemSize;
1769
1938
  return itemSize;
1770
1939
  },
1771
1940
  getEstimatedTotalSize: function getEstimatedTotalSize(_ref3) {
@@ -1783,7 +1952,8 @@ createListComponent({
1783
1952
  // TODO Deprecate direction "horizontal"
1784
1953
  var isHorizontal = direction === 'horizontal' || layout === 'horizontal';
1785
1954
  var size = isHorizontal ? width : height;
1786
- var maxOffset = Math.max(0, Math.min(itemCount * itemSize - size, index * itemSize));
1955
+ var lastItemOffset = Math.max(0, itemCount * itemSize - size);
1956
+ var maxOffset = Math.min(lastItemOffset, index * itemSize);
1787
1957
  var minOffset = Math.max(0, index * itemSize - size + itemSize);
1788
1958
 
1789
1959
  if (align === 'smart') {
@@ -1802,13 +1972,25 @@ createListComponent({
1802
1972
  return minOffset;
1803
1973
 
1804
1974
  case 'center':
1805
- return Math.round(minOffset + (maxOffset - minOffset) / 2);
1975
+ {
1976
+ // "Centered" offset is usually the average of the min and max.
1977
+ // But near the edges of the list, this doesn't hold true.
1978
+ var middleOffset = Math.round(minOffset + (maxOffset - minOffset) / 2);
1979
+
1980
+ if (middleOffset < Math.ceil(size / 2)) {
1981
+ return 0; // near the beginning
1982
+ } else if (middleOffset > lastItemOffset + Math.floor(size / 2)) {
1983
+ return lastItemOffset; // near the end
1984
+ } else {
1985
+ return middleOffset;
1986
+ }
1987
+ }
1806
1988
 
1807
1989
  case 'auto':
1808
1990
  default:
1809
1991
  if (scrollOffset >= minOffset && scrollOffset <= maxOffset) {
1810
1992
  return scrollOffset;
1811
- } else if (scrollOffset - minOffset < maxOffset - scrollOffset) {
1993
+ } else if (scrollOffset < minOffset) {
1812
1994
  return minOffset;
1813
1995
  } else {
1814
1996
  return maxOffset;
@@ -1832,7 +2014,9 @@ createListComponent({
1832
2014
  var isHorizontal = direction === 'horizontal' || layout === 'horizontal';
1833
2015
  var offset = startIndex * itemSize;
1834
2016
  var size = isHorizontal ? width : height;
1835
- return Math.max(0, Math.min(itemCount - 1, startIndex + Math.floor((size + (scrollOffset - offset)) / itemSize)));
2017
+ var numVisibleItems = Math.ceil((size + scrollOffset - offset) / itemSize);
2018
+ return Math.max(0, Math.min(itemCount - 1, startIndex + numVisibleItems - 1 // -1 is because stop index is inclusive
2019
+ ));
1836
2020
  },
1837
2021
  initInstanceProps: function initInstanceProps(props) {// Noop
1838
2022
  },
@@ -1892,3 +2076,4 @@ exports.FixedSizeGrid = FixedSizeGrid;
1892
2076
  exports.FixedSizeList = FixedSizeList;
1893
2077
  exports.areEqual = areEqual;
1894
2078
  exports.shouldComponentUpdate = shouldComponentUpdate;
2079
+ //# sourceMappingURL=index.cjs.js.map