Skip to content

Commit

Permalink
fix: debounce an update after virtualizer size change (#7400) (CP: 24…
Browse files Browse the repository at this point in the history
….3) (#7405)

Co-authored-by: Tomi Virkki <[email protected]>
  • Loading branch information
vaadin-bot and tomivirkki committed May 14, 2024
1 parent a9551e4 commit 6621458
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 3 deletions.
5 changes: 4 additions & 1 deletion packages/component-base/src/virtualizer-iron-list-adapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/
/* eslint-disable @typescript-eslint/member-ordering */
// https://github.com/vaadin/eslint-config-vaadin/issues/33
import { animationFrame, timeOut } from './async.js';
import { animationFrame, microTask, timeOut } from './async.js';
import { isSafari } from './browser-utils.js';
import { Debouncer, flush } from './debounce.js';
import { ironList } from './iron-list-core.js';
Expand Down Expand Up @@ -350,6 +350,9 @@ export class IronListAdapter {
// Schedule and flush a resize handler
this._resizeHandler();
flush();
// Schedule an update to ensure item positions are correct after subsequent size changes
// Fix for https://github.com/vaadin/flow-components/issues/6269
this._debounce('_update', this._update, microTask);
}

/** @private */
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { expect } from '@esm-bundle/chai';
import { fixtureSync, nextFrame } from '@vaadin/testing-helpers';
import { aTimeout, fixtureSync, isFirefox, nextFrame } from '@vaadin/testing-helpers';
import sinon from 'sinon';
import { Virtualizer } from '../src/virtualizer.js';

Expand Down Expand Up @@ -204,7 +204,12 @@ describe('virtualizer - variable row height - large variance', () => {
await fixItemPositioningTimeout();
const targetScrollTop = scrollTarget.scrollHeight - scrollTarget.offsetHeight;

expect(scrollTarget.scrollTop).to.equal(targetScrollTop);
if (isFirefox) {
// Firfox has a rounding issue that requires a small tolerance
expect(scrollTarget.scrollTop).to.be.closeTo(targetScrollTop, 1);
} else {
expect(scrollTarget.scrollTop).to.equal(targetScrollTop);
}
});

it('should allow scrolling to start', async () => {
Expand Down Expand Up @@ -233,3 +238,52 @@ describe('virtualizer - variable row height - large variance', () => {
expect(virtualizer.__adapter.__fixInvalidItemPositioning.callCount).to.equal(0);
});
});

describe('virtualizer - variable row height - size changes', () => {
let virtualizer;

beforeEach(async () => {
const reverseItemHeights = [50, 30];

const scrollTarget = fixtureSync(`
<div style="height: 500px; width: 200px;">
<div></div>
</div>
`);
const scrollContainer = scrollTarget.firstElementChild;

virtualizer = new Virtualizer({
createElements: (count) => Array.from(Array(count)).map(() => document.createElement('div')),
updateElement: (el, index) => {
el.style.height = `${reverseItemHeights[virtualizer.size - index - 1]}px`;
el.style.outline = '1px solid black';
el.style.outlineOffset = '-1px';
el.style.width = '100%';
el.textContent = `Item ${index}`;
el.id = `item-${index}`;
},
scrollTarget,
scrollContainer,
});

virtualizer.size = 2;
// Wait for a possible resize observer flush
await aTimeout(100);
});

it('should position the items correctly after subsequent size changes', async () => {
virtualizer.size = 1;
virtualizer.update();

virtualizer.size = 2;
virtualizer.update();

await nextFrame();

const item0 = document.getElementById('item-0');
const item1 = document.getElementById('item-1');
expect(item0.clientHeight).to.equal(30);
expect(item1.clientHeight).to.equal(50);
expect(item1.getBoundingClientRect().top).to.equal(item0.getBoundingClientRect().bottom);
});
});

0 comments on commit 6621458

Please sign in to comment.