Skip to content

Commit

Permalink
fix: calculate vidxOffset correctly when clientHeight != offsetHeight (
Browse files Browse the repository at this point in the history
…#7268) (#7272)

* refactor: extract _maxVirtualIndexOffset getter (#7227)
* fix: calculate vidxOffset correctly when clientHeight != offsetHeight (#7268)
  • Loading branch information
vursen authored Mar 26, 2024
1 parent 32a4f32 commit 4e8f960
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 5 deletions.
14 changes: 9 additions & 5 deletions packages/component-base/src/virtualizer-iron-list-adapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ export class IronListAdapter {
return this.lastVisibleIndex + this._vidxOffset;
}

get _maxVirtualIndexOffset() {
return this.size - this._virtualCount;
}

__hasPlaceholders() {
return this.__getVisibleElements().some((el) => el.__virtualizerPlaceholder);
}
Expand All @@ -106,7 +110,7 @@ export class IronListAdapter {
let targetVirtualIndex = Math.floor((index / this.size) * this._virtualCount);
if (this._virtualCount - targetVirtualIndex < visibleElementCount) {
targetVirtualIndex = this._virtualCount - (this.size - index);
this._vidxOffset = this.size - this._virtualCount;
this._vidxOffset = this._maxVirtualIndexOffset;
} else if (targetVirtualIndex < visibleElementCount) {
if (index < OFFSET_ADJUST_MIN_THRESHOLD) {
targetVirtualIndex = index;
Expand Down Expand Up @@ -719,15 +723,16 @@ export class IronListAdapter {

/** @private */
_adjustVirtualIndexOffset(delta) {
const maxOffset = this._maxVirtualIndexOffset;

if (this._virtualCount >= this.size) {
this._vidxOffset = 0;
} else if (this.__skipNextVirtualIndexAdjust) {
this.__skipNextVirtualIndexAdjust = false;
} else if (Math.abs(delta) > 10000) {
// Process a large scroll position change
const scale = this._scrollTop / (this.scrollTarget.scrollHeight - this.scrollTarget.offsetHeight);
const offset = scale * this.size;
this._vidxOffset = Math.round(offset - scale * this._virtualCount);
const scale = this._scrollTop / (this.scrollTarget.scrollHeight - this.scrollTarget.clientHeight);
this._vidxOffset = Math.round(scale * maxOffset);
} else {
// Make sure user can always swipe/wheel scroll to the start and end
const oldOffset = this._vidxOffset;
Expand All @@ -746,7 +751,6 @@ export class IronListAdapter {
}

// Near end
const maxOffset = this.size - this._virtualCount;
if (this._scrollTop >= this._maxScrollTop && this._maxScrollTop > 0) {
this._vidxOffset = maxOffset;
if (oldOffset !== this._vidxOffset) {
Expand Down
10 changes: 10 additions & 0 deletions packages/component-base/test/virtualizer-unlimited-size.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,16 @@ describe('unlimited size', () => {
expect(item.getBoundingClientRect().top).to.equal(scrollTarget.getBoundingClientRect().top);
});

it('should manually scroll to end when the scroll target has a border', async () => {
scrollTarget.style.borderTop = '20px solid black';

scrollTarget.scrollTop = scrollTarget.scrollHeight;
await oneEvent(scrollTarget, 'scroll');

const item = elementsContainer.querySelector(`#item-${virtualizer.size - 1}`);
expect(item.getBoundingClientRect().bottom).to.be.closeTo(scrollTarget.getBoundingClientRect().bottom, 1);
});

it('should manually scroll to start after scroll to index', async () => {
virtualizer.scrollToIndex(virtualizer.size / 400);

Expand Down

0 comments on commit 4e8f960

Please sign in to comment.