Skip to content

Commit 4e8f960

Browse files
authored
fix: calculate vidxOffset correctly when clientHeight != offsetHeight (#7268) (#7272)
* refactor: extract _maxVirtualIndexOffset getter (#7227) * fix: calculate vidxOffset correctly when clientHeight != offsetHeight (#7268)
1 parent 32a4f32 commit 4e8f960

File tree

2 files changed

+19
-5
lines changed

2 files changed

+19
-5
lines changed

packages/component-base/src/virtualizer-iron-list-adapter.js

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ export class IronListAdapter {
8282
return this.lastVisibleIndex + this._vidxOffset;
8383
}
8484

85+
get _maxVirtualIndexOffset() {
86+
return this.size - this._virtualCount;
87+
}
88+
8589
__hasPlaceholders() {
8690
return this.__getVisibleElements().some((el) => el.__virtualizerPlaceholder);
8791
}
@@ -106,7 +110,7 @@ export class IronListAdapter {
106110
let targetVirtualIndex = Math.floor((index / this.size) * this._virtualCount);
107111
if (this._virtualCount - targetVirtualIndex < visibleElementCount) {
108112
targetVirtualIndex = this._virtualCount - (this.size - index);
109-
this._vidxOffset = this.size - this._virtualCount;
113+
this._vidxOffset = this._maxVirtualIndexOffset;
110114
} else if (targetVirtualIndex < visibleElementCount) {
111115
if (index < OFFSET_ADJUST_MIN_THRESHOLD) {
112116
targetVirtualIndex = index;
@@ -719,15 +723,16 @@ export class IronListAdapter {
719723

720724
/** @private */
721725
_adjustVirtualIndexOffset(delta) {
726+
const maxOffset = this._maxVirtualIndexOffset;
727+
722728
if (this._virtualCount >= this.size) {
723729
this._vidxOffset = 0;
724730
} else if (this.__skipNextVirtualIndexAdjust) {
725731
this.__skipNextVirtualIndexAdjust = false;
726732
} else if (Math.abs(delta) > 10000) {
727733
// Process a large scroll position change
728-
const scale = this._scrollTop / (this.scrollTarget.scrollHeight - this.scrollTarget.offsetHeight);
729-
const offset = scale * this.size;
730-
this._vidxOffset = Math.round(offset - scale * this._virtualCount);
734+
const scale = this._scrollTop / (this.scrollTarget.scrollHeight - this.scrollTarget.clientHeight);
735+
this._vidxOffset = Math.round(scale * maxOffset);
731736
} else {
732737
// Make sure user can always swipe/wheel scroll to the start and end
733738
const oldOffset = this._vidxOffset;
@@ -746,7 +751,6 @@ export class IronListAdapter {
746751
}
747752

748753
// Near end
749-
const maxOffset = this.size - this._virtualCount;
750754
if (this._scrollTop >= this._maxScrollTop && this._maxScrollTop > 0) {
751755
this._vidxOffset = maxOffset;
752756
if (oldOffset !== this._vidxOffset) {

packages/component-base/test/virtualizer-unlimited-size.test.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,16 @@ describe('unlimited size', () => {
102102
expect(item.getBoundingClientRect().top).to.equal(scrollTarget.getBoundingClientRect().top);
103103
});
104104

105+
it('should manually scroll to end when the scroll target has a border', async () => {
106+
scrollTarget.style.borderTop = '20px solid black';
107+
108+
scrollTarget.scrollTop = scrollTarget.scrollHeight;
109+
await oneEvent(scrollTarget, 'scroll');
110+
111+
const item = elementsContainer.querySelector(`#item-${virtualizer.size - 1}`);
112+
expect(item.getBoundingClientRect().bottom).to.be.closeTo(scrollTarget.getBoundingClientRect().bottom, 1);
113+
});
114+
105115
it('should manually scroll to start after scroll to index', async () => {
106116
virtualizer.scrollToIndex(virtualizer.size / 400);
107117

0 commit comments

Comments
 (0)