Skip to content

Commit

Permalink
Scroll to an exact position when clicking the scrollbar track doesn't…
Browse files Browse the repository at this point in the history
… work in case of variable row heights and isVerticalScrollExact = true (#712)

Co-authored-by: Daniela Buzatu <daniela.buzatu@crispico.com>
  • Loading branch information
daniela-mateescu and daniela-buzatu committed Jan 10, 2024
1 parent 9614676 commit 149f0ef
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 12 deletions.
38 changes: 26 additions & 12 deletions src/reducers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -213,12 +213,16 @@ const slice = createSlice({
state.scrollX = scrollX;
},
updateRowHeights(state, action) {
const firstUpdatedRowIndex = action.payload || 0;
if (firstUpdatedRowIndex >= state.getInternal().rowUntilOffsetsAreExact) {
let firstUpdatedRowIndex = action.payload || 0;
if (firstUpdatedRowIndex >= state.rowSettings.rowsCount) {
return;
}
// Invalidate all the previous computed row heights till the updated row
state.getInternal().rowUntilOffsetsAreExact = firstUpdatedRowIndex;

// Recompute all the updated rows heights
while (firstUpdatedRowIndex < state.rowSettings.rowsCount) {
updateRowHeight(state, firstUpdatedRowIndex++);
}

// Refresh the current scroll position according to the new row heights
const currentScrollY =
state
Expand All @@ -237,18 +241,28 @@ const slice = createSlice({
* @param {!Object} state
* @private
*/
function initializeRowHeightsAndOffsets(state) {
const { rowHeight, rowsCount, subRowHeight } = state.rowSettings;
const defaultFullRowHeight = rowHeight + subRowHeight;
const rowOffsetIntervalTree = PrefixIntervalTree.uniform(
export function initializeRowHeightsAndOffsets(state) {
const {
rowHeight,
rowsCount,
defaultFullRowHeight
);
const scrollContentHeight = rowsCount * defaultFullRowHeight;
subRowHeight,
rowHeightGetter,
subRowHeightGetter,
} = state.rowSettings;
const defaultFullRowHeight = rowHeight + subRowHeight;
let scrollContentHeight = 0;
const storedHeights = new Array(rowsCount);
for (let idx = 0; idx < rowsCount; idx++) {
storedHeights[idx] = defaultFullRowHeight;
if (state.isVerticalScrollExact) {
storedHeights[idx] = rowHeightGetter(idx) + subRowHeightGetter(idx);
} else {
storedHeights[idx] = defaultFullRowHeight;
}
scrollContentHeight += storedHeights[idx];
}

const rowOffsetIntervalTree = new PrefixIntervalTree(storedHeights);

state.scrollContentHeight = scrollContentHeight;
Object.assign(state.getInternal(), {
rowOffsetIntervalTree,
Expand Down
72 changes: 72 additions & 0 deletions test/reducers/initializeRowHeightsAndOffsets-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { initializeRowHeightsAndOffsets } from '../../src/reducers';
import { assert } from 'chai';
import clone from 'lodash/clone';

describe('initializeRowHeightsAndOffsets', function () {
let oldState;
let newState;
beforeEach(function () {
const createInternalStateGetter = () => {
const internalState = {};
return () => internalState;
};
oldState = {
getInternal: createInternalStateGetter(),
rowSettings: {
rowsCount: 80,
rowHeight: 125,
subRowHeight: 0,
rowHeightGetter: (rowIndex) => (rowIndex % 2 == 0 ? 100 : 200),
subRowHeightGetter: () => 0,
},
};
newState = clone(oldState);
newState.getInternal = createInternalStateGetter();
});
it('if isVerticalScrollExact = false then rowheight is used instead of rowHeightGetter() for all the rows', function () {
initializeRowHeightsAndOffsets(newState);
for (let rowIdx = 0; rowIdx < 80; rowIdx++) {
assert.strictEqual(
newState.getInternal().storedHeights[rowIdx],
125,
'expected stored height of 125 for each row'
);
assert.strictEqual(
newState.getInternal().rowOffsetIntervalTree.get(rowIdx),
125,
'expected row offsets for each row to be set to 125'
);
}
assert.strictEqual(
newState.scrollContentHeight,
10000,
'expected scrollContentHeight to be 10000'
);
});

it('if isVerticalScrollExact = true then rowHeightGetter() is used for all the rows', function () {
newState.isVerticalScrollExact = true;
initializeRowHeightsAndOffsets(newState);
for (let rowIdx = 0; rowIdx < 80; rowIdx++) {
const expectedRowHeight = rowIdx % 2 == 0 ? 100 : 200;
assert.strictEqual(
newState.getInternal().storedHeights[rowIdx],
expectedRowHeight,
'expected stored height of ' + expectedRowHeight + ' for row ' + rowIdx
);
assert.strictEqual(
newState.getInternal().rowOffsetIntervalTree.get(rowIdx),
expectedRowHeight,
'expected row offsets for row ' +
rowIdx +
' to be set to ' +
expectedRowHeight
);
}
assert.strictEqual(
newState.scrollContentHeight,
12000,
'expected scrollContentHeight to be 12000'
);
});
});

0 comments on commit 149f0ef

Please sign in to comment.