+ {/* List container */}
+
+ {/* Upper placeholder */}
+
+ {/* Lower placeholder */}
+
+ {/* List items subset */}
+ {items.slice(start, end).map(i => (
+ -
+ Item {i}
+
+ ))}
+
+
+ >
+ );
+
+ // Emulate the browser window viewport height
+ window.innerHeight = viewportHeight;
+
+ // Emulate RAF with immediate callback
+ window.requestAnimationFrame = cb => cb(0);
+
+ // Emulate IntersectionObserver with immediate callback
+ window.IntersectionObserver = function(cb) {
+ return {
+ observe: () => cb(),
+ disconnect: () => null
+ };
+ };
+
+ // Gets the React instance for a React node
+ const getInstance = node => {
+ const key = Object.keys(node).find(key =>
+ key.startsWith('__reactInternalInstance')
+ );
+ return node[key];
+ };
+
+ // Emulate element bounds as if rendered
+ window.Element.prototype.getBoundingClientRect = function() {
+ const instance = getInstance(this);
+
+ // Check which element this is
+ const isList = instance.type === 'ul';
+
+ // Set by `style` in `listRender`
+ const width = Number.parseInt(this.style.width);
+ const height = Number.parseInt(this.style.height);
+
+ // Find offset for viewport scroll and container scroll
+ const offsetY = -viewportScrollY - (isList ? containerScrollY : 0);
+
+ // Return bounds in screen space as expected
+ return {
+ x: 0,
+ left: 0,
+ y: offsetY,
+ top: offsetY,
+ width: width,
+ right: width,
+ height: height,
+ bottom: height + offsetY
+ };
+ };
+
+ // Return the test setup
+ return {
+ items,
+ visibleCount,
+ itemHeights,
+ listRender
+ };
+};
From a77e7014625888ef0df68f59e07c85eff5fab8e3 Mon Sep 17 00:00:00 2001
From: bru5 <45365769+bru5@users.noreply.github.com>
Date: Mon, 7 Dec 2020 13:24:31 +0000
Subject: [PATCH 14/20] [KED-1923] Simplify LazyList clipping
---
src/components/lazy-list/index.js | 28 ++++++++++------------------
1 file changed, 10 insertions(+), 18 deletions(-)
diff --git a/src/components/lazy-list/index.js b/src/components/lazy-list/index.js
index 93dda8facf..ee0f9a3ca5 100644
--- a/src/components/lazy-list/index.js
+++ b/src/components/lazy-list/index.js
@@ -235,13 +235,13 @@ const visibleRangeOf = (
const clip = container.getBoundingClientRect();
// Find element bounds (e.g. list container inside scroll container)
- const rect = element.getBoundingClientRect();
+ const list = element.getBoundingClientRect();
// Find the number of items to buffer
const bufferCount = Math.ceil((buffer * clip.height) / childHeight);
// When clip is fully above viewport or element is fully above clip
- if (clip.bottom < 0 || rect.bottom < clip.top) {
+ if (clip.bottom < 0 || list.bottom < clip.top) {
// Only bottom part of the buffer in range
return range(childTotal - bufferCount, childTotal, 0, childTotal);
}
@@ -253,28 +253,20 @@ const visibleRangeOf = (
};
// When clip is fully below viewport or element is fully below clip
- if (clip.top > viewport.bottom || rect.top > clip.bottom) {
+ if (clip.top > viewport.bottom || list.top > clip.bottom) {
// Only top part of the buffer in range
return range(0, bufferCount, 0, childTotal);
}
- // Find visible rendered bounds inside scroll clip and inside viewport clip
- const top = Math.min(
- Math.max(rect.top, clip.top, viewport.top),
- clip.bottom,
- viewport.bottom
- );
- const bottom = Math.max(
- Math.min(rect.bottom, clip.bottom, viewport.bottom),
- clip.top,
- viewport.bottom
- );
+ // Find intersection of clip and viewport now overlap guaranteed
+ const top = Math.max(clip.top, viewport.top);
+ const bottom = Math.min(clip.bottom, viewport.bottom);
- // Find visible item range inside visible rendered bounds
- const start = Math.floor((top - rect.top) / childHeight);
- const end = Math.ceil((bottom - rect.top) / childHeight);
+ // Find unbounded item range within the intersection
+ const start = Math.floor((top - list.top) / childHeight);
+ const end = Math.ceil((bottom - list.top) / childHeight);
- // Apply buffer and clamp final range
+ // Apply buffer and clamp unbounded range to list bounds
return range(start - bufferCount, end + bufferCount, 0, childTotal);
};
From 307e4e90d476aa8d5663faddef4199605959fee0 Mon Sep 17 00:00:00 2001
From: bru5 <45365769+bru5@users.noreply.github.com>
Date: Mon, 7 Dec 2020 13:28:35 +0000
Subject: [PATCH 15/20] [KED-1923] Improve tests for LazyList
---
src/components/lazy-list/lazy-list.test.js | 56 +++++++++++--------
.../node-list/node-list-group.test.js | 1 -
2 files changed, 33 insertions(+), 24 deletions(-)
diff --git a/src/components/lazy-list/lazy-list.test.js b/src/components/lazy-list/lazy-list.test.js
index fcd98172ee..7415ee1698 100644
--- a/src/components/lazy-list/lazy-list.test.js
+++ b/src/components/lazy-list/lazy-list.test.js
@@ -4,19 +4,27 @@ import { setup } from '../../utils/state.mock';
describe('LazyList', () => {
it('renders expected visible child items with padding for non-visible items', () => {
+ // Settings for all test items
const itemCount = 500;
const itemHeight = 30;
+
+ // The specific range of items to make visible in this test
const visibleStart = 10;
const visibleEnd = 40;
const visibleCount = visibleEnd - visibleStart;
+ // Configure test to include some clipping and scroll conditions
const test = setupTest({
itemCount,
itemHeight,
visibleCount,
- containerHeight: itemHeight * visibleCount,
- viewportHeight: itemHeight * visibleCount, // * 1.25,
+ // Viewport to fit exactly desired number of visible items
+ viewportHeight: itemHeight * visibleCount,
+ // Container larger than viewport to test clipping
+ containerHeight: itemHeight * visibleCount * 2,
+ // Container scrolled half way to desired start item to test
containerScrollY: itemHeight * visibleStart * 0.5,
+ // Viewport scrolled remaining half way to desired start item
viewportScrollY: itemHeight * visibleStart * 0.5
});
@@ -31,23 +39,25 @@ describe('LazyList', () => {