Skip to content

Commit 73a4be4

Browse files
web-padawanvaadin-bot
authored andcommitted
fix: restore scroll position when virtualizer used in dialog (#8642)
1 parent 17738c2 commit 73a4be4

File tree

2 files changed

+31
-1
lines changed

2 files changed

+31
-1
lines changed

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,20 @@ export class IronListAdapter {
5252
this.__resizeObserver.observe(this.scrollTarget);
5353
this.scrollTarget.addEventListener('scroll', () => this._scrollHandler());
5454

55+
const attachObserver = new ResizeObserver(([{ contentRect }]) => {
56+
const isHidden = contentRect.width === 0 && contentRect.height === 0;
57+
if (!isHidden && this.__scrollTargetHidden && this.scrollTarget.scrollTop !== this._scrollPosition) {
58+
// When removing element from DOM, its scroll position is lost and
59+
// virtualizer doesn't re-render when adding it to the DOM again.
60+
// Restore scroll position when the scroll target becomes visible,
61+
// which is the case e.g. when virtualizer is used inside a dialog.
62+
this.scrollTarget.scrollTop = this._scrollPosition;
63+
}
64+
65+
this.__scrollTargetHidden = isHidden;
66+
});
67+
attachObserver.observe(this.scrollTarget);
68+
5569
this._scrollLineHeight = this._getScrollLineHeight();
5670
this.scrollTarget.addEventListener('wheel', (e) => this.__onWheel(e));
5771

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

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { expect } from '@vaadin/chai-plugins';
2-
import { aTimeout, fixtureSync, nextFrame, oneEvent } from '@vaadin/testing-helpers';
2+
import { aTimeout, fixtureSync, nextFrame, nextResize, oneEvent } from '@vaadin/testing-helpers';
33
import sinon from 'sinon';
44
import { Virtualizer } from '../src/virtualizer.js';
55

@@ -350,6 +350,22 @@ describe('virtualizer', () => {
350350
expect(initialCount).not.to.be.above(expectedCount);
351351
});
352352

353+
it('should preserve scroll position when moving within DOM and changing visibility', async () => {
354+
scrollTarget.scrollTop = 100;
355+
await oneEvent(scrollTarget, 'scroll');
356+
357+
scrollTarget.hidden = true;
358+
await nextResize(scrollTarget);
359+
360+
const wrapper = fixtureSync('<div></div>');
361+
wrapper.appendChild(scrollTarget);
362+
363+
scrollTarget.hidden = false;
364+
await nextResize(scrollTarget);
365+
366+
expect(scrollTarget.scrollTop).to.equal(100);
367+
});
368+
353369
describe('lazy rendering', () => {
354370
let render = false;
355371

0 commit comments

Comments
 (0)