Skip to content

Commit b35a2e8

Browse files
authored
fix: manually restore scroll position for grid in Firefox (#6022) (#6026)
1 parent 86c176c commit b35a2e8

2 files changed

Lines changed: 91 additions & 0 deletions

File tree

packages/grid/src/vaadin-grid-scroll-mixin.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import { animationFrame, microTask, timeOut } from '@vaadin/component-base/src/async.js';
77
import { Debouncer } from '@vaadin/component-base/src/debounce.js';
88
import { getNormalizedScrollLeft } from '@vaadin/component-base/src/dir-utils.js';
9+
import { isElementHidden } from '@vaadin/component-base/src/focus-utils.js';
910
import { ResizeMixin } from '@vaadin/component-base/src/resize-mixin.js';
1011

1112
const timeouts = {
@@ -84,6 +85,19 @@ export const ScrollMixin = (superClass) =>
8485
_onResize() {
8586
this._updateOverflow();
8687
this.__updateHorizontalScrollPosition();
88+
89+
// For Firefox, manually restore last scroll position when grid becomes
90+
// visible again. This solves an issue where switching visibility of two
91+
// grids causes Firefox trying to synchronize the scroll positions between
92+
// the two grid's table elements.
93+
// See https://github.com/vaadin/web-components/issues/5796
94+
if (this._firefox) {
95+
const isVisible = !isElementHidden(this);
96+
if (isVisible && this.__previousVisible === false) {
97+
this._scrollTop = this.__memorizedScrollTop || 0;
98+
}
99+
this.__previousVisible = isVisible;
100+
}
87101
}
88102

89103
/**
@@ -143,6 +157,14 @@ export const ScrollMixin = (superClass) =>
143157
}
144158

145159
this._updateOverflow();
160+
161+
// Memorize last scroll position in Firefox
162+
if (this._firefox) {
163+
const isVisible = !isElementHidden(this);
164+
if (isVisible && this.__previousVisible !== false) {
165+
this.__memorizedScrollTop = this._scrollTop;
166+
}
167+
}
146168
}
147169

148170
/** @private */
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { expect } from '@esm-bundle/chai';
2+
import { aTimeout, fixtureSync, isFirefox } from '@vaadin/testing-helpers';
3+
import '../vaadin-grid.js';
4+
import { fire, flushGrid, infiniteDataProvider } from './helpers.js';
5+
6+
if (isFirefox) {
7+
// This suite tests a fix for an issue in Firefox where switching visibility
8+
// of two grids causes the scroll position of the first grid to be reset to 0,
9+
// and the scroll position of the second grid is synchronized from the first
10+
// grid.
11+
// See https://github.com/vaadin/web-components/issues/5796
12+
describe('scroll restoration in Firefox', () => {
13+
let grid1, grid2;
14+
15+
beforeEach(() => {
16+
const fixture = fixtureSync(`
17+
<div>
18+
<vaadin-grid style="height: 200px; width: 200px;" size="100">
19+
<vaadin-grid-column header="foo"></vaadin-grid-column>
20+
</vaadin-grid>
21+
<vaadin-grid style="height: 200px; width: 200px;" hidden size="100">
22+
<vaadin-grid-column header="bar"></vaadin-grid-column>
23+
</vaadin-grid>
24+
</div>
25+
`);
26+
const grids = fixture.querySelectorAll('vaadin-grid');
27+
grids.forEach((grid) => {
28+
grid.querySelector('vaadin-grid-column').renderer = (root, _, model) => {
29+
root.textContent = model.index;
30+
};
31+
grid.dataProvider = infiniteDataProvider;
32+
flushGrid(grid);
33+
});
34+
grid1 = grids[0];
35+
grid2 = grids[1];
36+
});
37+
38+
function toggleVisibility() {
39+
grid1.hidden = !grid1.hidden;
40+
grid2.hidden = !grid2.hidden;
41+
}
42+
43+
it('should restore scroll position when showing grids', async () => {
44+
// Scroll grid
45+
grid1.$.table.scrollTop = 300;
46+
fire('scroll', {}, { node: grid1.$.table });
47+
flushGrid(grid1);
48+
await aTimeout(50);
49+
50+
// Hide first grid, show second grid
51+
toggleVisibility();
52+
await aTimeout(50);
53+
54+
// Hide second grid, show first grid again
55+
toggleVisibility();
56+
await aTimeout(50);
57+
58+
// Scroll position for first grid should still be 300
59+
expect(grid1.$.table.scrollTop).to.equal(300);
60+
61+
// Show second grid again
62+
toggleVisibility();
63+
await aTimeout(50);
64+
65+
// Scroll position for first grid should still be 0
66+
expect(grid2.$.table.scrollTop).to.equal(0);
67+
});
68+
});
69+
}

0 commit comments

Comments
 (0)