diff --git a/src/FixedSizeGrid.js b/src/FixedSizeGrid.js
index 452536a9..69f9bd0e 100644
--- a/src/FixedSizeGrid.js
+++ b/src/FixedSizeGrid.js
@@ -65,6 +65,8 @@ const FixedSizeGrid = createGridComponent({
default:
if (scrollLeft >= minOffset && scrollLeft <= maxOffset) {
return scrollLeft;
+ } else if (minOffset > maxOffset) {
+ return minOffset;
} else if (scrollLeft - minOffset < maxOffset - scrollLeft) {
return minOffset;
} else {
@@ -115,6 +117,10 @@ const FixedSizeGrid = createGridComponent({
default:
if (scrollTop >= minOffset && scrollTop <= maxOffset) {
return scrollTop;
+ // Because we only take into account the scrollbar size when calculating minOffset
+ // this value can be larger than maxOffset when at the end of the list
+ } else if (minOffset > maxOffset) {
+ return minOffset;
} else if (scrollTop - minOffset < maxOffset - scrollTop) {
return minOffset;
} else {
diff --git a/src/VariableSizeGrid.js b/src/VariableSizeGrid.js
index a1273e19..11f5eb01 100644
--- a/src/VariableSizeGrid.js
+++ b/src/VariableSizeGrid.js
@@ -274,6 +274,10 @@ const getOffsetForIndexAndAlignment = (
default:
if (scrollOffset >= minOffset && scrollOffset <= maxOffset) {
return scrollOffset;
+ // Because we only take into account the scrollbar size when calculating minOffset
+ // this value can be larger than maxOffset when at the end of the list
+ } else if (minOffset > maxOffset) {
+ return minOffset;
} else if (scrollOffset - minOffset < maxOffset - scrollOffset) {
return minOffset;
} else {
diff --git a/src/__tests__/FixedSizeGrid.js b/src/__tests__/FixedSizeGrid.js
index a214bd0f..05c3498e 100644
--- a/src/__tests__/FixedSizeGrid.js
+++ b/src/__tests__/FixedSizeGrid.js
@@ -569,6 +569,81 @@ describe('FixedSizeGrid', () => {
expect(onItemsRendered.mock.calls).toMatchSnapshot();
});
+ it('should scroll to the correct item for align = "auto" at the bottom of the grid', () => {
+ getScrollbarSize.mockImplementation(() => 20);
+
+ const rendered = ReactTestRenderer.create(
+
+ );
+ onItemsRendered.mockClear();
+
+ // Scroll down to the last row in the list.
+ rendered
+ .getInstance()
+ .scrollToItem({ columnIndex: 5, rowIndex: 19, align: 'auto' });
+
+ expect(onItemsRendered).toHaveBeenCalledTimes(1);
+ expect(onItemsRendered).toHaveBeenLastCalledWith(
+ expect.objectContaining({
+ visibleRowStartIndex: 17,
+ visibleRowStopIndex: 19,
+ })
+ );
+ // Repeat the previous scrollToItem call.
+ rendered
+ .getInstance()
+ .scrollToItem({ columnIndex: 5, rowIndex: 19, align: 'auto' });
+
+ // Shouldn't have been called again
+ expect(onItemsRendered).toHaveBeenCalledTimes(1);
+ expect(onItemsRendered).toHaveBeenLastCalledWith(
+ expect.objectContaining({
+ visibleRowStartIndex: 17,
+ visibleRowStopIndex: 19,
+ })
+ );
+ });
+
+ it('should scroll to the correct item for align = "auto" at the end of the grid', () => {
+ getScrollbarSize.mockImplementation(() => 20);
+
+ const rendered = ReactTestRenderer.create(
+
+ );
+ onItemsRendered.mockClear();
+
+ // Scroll across to the last row in the list.
+ rendered
+ .getInstance()
+ .scrollToItem({ columnIndex: 19, rowIndex: 19, align: 'auto' });
+
+ expect(onItemsRendered).toHaveBeenCalledTimes(1);
+ expect(onItemsRendered).toHaveBeenLastCalledWith(
+ expect.objectContaining({
+ visibleColumnStartIndex: 18,
+ visibleColumnStopIndex: 19,
+ })
+ );
+ // Repeat the previous scrollToItem call.
+ rendered
+ .getInstance()
+ .scrollToItem({ columnIndex: 19, rowIndex: 19, align: 'auto' });
+
+ // Shouldn't have been called again
+ expect(onItemsRendered).toHaveBeenCalledTimes(1);
+ expect(onItemsRendered).toHaveBeenLastCalledWith(
+ expect.objectContaining({
+ visibleColumnStartIndex: 18,
+ visibleColumnStopIndex: 19,
+ })
+ );
+ });
+
it('should scroll to the correct item for align = "start"', () => {
const rendered = ReactTestRenderer.create(
diff --git a/src/__tests__/VariableSizeGrid.js b/src/__tests__/VariableSizeGrid.js
index 871321cf..2c4d66fd 100644
--- a/src/__tests__/VariableSizeGrid.js
+++ b/src/__tests__/VariableSizeGrid.js
@@ -189,6 +189,76 @@ describe('VariableSizeGrid', () => {
expect(onItemsRendered.mock.calls).toMatchSnapshot();
});
+ it('should scroll to the correct item for align = "auto" at the bottom of the grid', () => {
+ getScrollbarSize.mockImplementation(() => 20);
+
+ const rendered = ReactTestRenderer.create(
+
+ );
+ onItemsRendered.mockClear();
+
+ // Scroll down to the last row in the list.
+ rendered
+ .getInstance()
+ .scrollToItem({ columnIndex: 5, rowIndex: 19, align: 'auto' });
+
+ expect(onItemsRendered).toHaveBeenCalledTimes(1);
+ expect(onItemsRendered).toHaveBeenLastCalledWith(
+ expect.objectContaining({
+ visibleRowStartIndex: 18,
+ visibleRowStopIndex: 19,
+ })
+ );
+ // Repeat the previous scrollToItem call.
+ rendered
+ .getInstance()
+ .scrollToItem({ columnIndex: 5, rowIndex: 19, align: 'auto' });
+
+ // Shouldn't have been called again
+ expect(onItemsRendered).toHaveBeenCalledTimes(1);
+ expect(onItemsRendered).toHaveBeenLastCalledWith(
+ expect.objectContaining({
+ visibleRowStartIndex: 18,
+ visibleRowStopIndex: 19,
+ })
+ );
+ });
+
+ it('should scroll to the correct item for align = "auto" at the end of the grid', () => {
+ getScrollbarSize.mockImplementation(() => 20);
+
+ const rendered = ReactTestRenderer.create(
+
+ );
+ onItemsRendered.mockClear();
+
+ // Scroll scross to the last row in the list.
+ rendered
+ .getInstance()
+ .scrollToItem({ columnIndex: 9, rowIndex: 10, align: 'auto' });
+
+ expect(onItemsRendered).toHaveBeenCalledTimes(1);
+ expect(onItemsRendered).toHaveBeenLastCalledWith(
+ expect.objectContaining({
+ visibleColumnStartIndex: 8,
+ visibleColumnStopIndex: 9,
+ })
+ );
+ // Repeat the previous scrollToItem call.
+ rendered
+ .getInstance()
+ .scrollToItem({ columnIndex: 9, rowIndex: 10, align: 'auto' });
+
+ // Shouldn't have been called again
+ expect(onItemsRendered).toHaveBeenCalledTimes(1);
+ expect(onItemsRendered).toHaveBeenLastCalledWith(
+ expect.objectContaining({
+ visibleColumnStartIndex: 8,
+ visibleColumnStopIndex: 9,
+ })
+ );
+ });
+
it('should scroll to the correct item for align = "start"', () => {
const rendered = ReactTestRenderer.create(