1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Fix selecting items always scrolling to top (#5728)

This commit is contained in:
Sebastian Malton 2022-06-29 05:21:57 -07:00 committed by GitHub
parent 657119b22b
commit 7ab3d419b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 439 additions and 4 deletions

View File

@ -0,0 +1,355 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`VirtualList renders 1`] = `
<body>
<div>
<div
class="VirtualList"
>
<div
class="list"
style="position: relative; height: 45px; width: 100%; overflow: auto; will-change: transform; direction: ltr;"
>
<div
style="height: 4545px; width: 100%;"
>
<div
data-testid="some-id-0"
style="position: absolute; left: 0px; top: 0px; height: 15px; width: 100%;"
>
some-id-0
</div>
<div
data-testid="some-id-1"
style="position: absolute; left: 0px; top: 15px; height: 15px; width: 100%;"
>
some-id-1
</div>
<div
data-testid="some-id-2"
style="position: absolute; left: 0px; top: 30px; height: 15px; width: 100%;"
>
some-id-2
</div>
<div
data-testid="some-id-3"
style="position: absolute; left: 0px; top: 45px; height: 15px; width: 100%;"
>
some-id-3
</div>
<div
data-testid="some-id-4"
style="position: absolute; left: 0px; top: 60px; height: 15px; width: 100%;"
>
some-id-4
</div>
<div
data-testid="some-id-5"
style="position: absolute; left: 0px; top: 75px; height: 15px; width: 100%;"
>
some-id-5
</div>
<div
data-testid="some-id-6"
style="position: absolute; left: 0px; top: 90px; height: 15px; width: 100%;"
>
some-id-6
</div>
<div
data-testid="some-id-7"
style="position: absolute; left: 0px; top: 105px; height: 15px; width: 100%;"
>
some-id-7
</div>
<div
data-testid="some-id-8"
style="position: absolute; left: 0px; top: 120px; height: 15px; width: 100%;"
>
some-id-8
</div>
<div
data-testid="some-id-9"
style="position: absolute; left: 0px; top: 135px; height: 15px; width: 100%;"
>
some-id-9
</div>
<div
data-testid="some-id-10"
style="position: absolute; left: 0px; top: 150px; height: 15px; width: 100%;"
>
some-id-10
</div>
<div
data-testid="some-id-11"
style="position: absolute; left: 0px; top: 165px; height: 15px; width: 100%;"
>
some-id-11
</div>
<div
data-testid="some-id-12"
style="position: absolute; left: 0px; top: 180px; height: 15px; width: 100%;"
>
some-id-12
</div>
</div>
</div>
</div>
</div>
</body>
`;
exports[`VirtualList when non-visable item is selected renders 1`] = `
<body>
<div>
<div
class="VirtualList"
>
<div
class="list"
style="position: relative; height: 45px; width: 100%; overflow: auto; will-change: transform; direction: ltr;"
>
<div
style="height: 3530px; width: 100%;"
>
<div
data-testid="some-id-19"
style="position: absolute; left: 0px; top: 285px; height: 15px; width: 100%;"
>
some-id-19
</div>
<div
data-testid="some-id-20"
style="position: absolute; left: 0px; top: 300px; height: 15px; width: 100%;"
>
some-id-20
</div>
<div
data-testid="some-id-21"
style="position: absolute; left: 0px; top: 315px; height: 15px; width: 100%;"
>
some-id-21
</div>
<div
data-testid="some-id-22"
style="position: absolute; left: 0px; top: 330px; height: 15px; width: 100%;"
>
some-id-22
</div>
<div
data-testid="some-id-23"
style="position: absolute; left: 0px; top: 345px; height: 15px; width: 100%;"
>
some-id-23
</div>
<div
data-testid="some-id-24"
style="position: absolute; left: 0px; top: 360px; height: 15px; width: 100%;"
>
some-id-24
</div>
<div
data-testid="some-id-25"
style="position: absolute; left: 0px; top: 375px; height: 15px; width: 100%;"
>
some-id-25
</div>
<div
data-testid="some-id-26"
style="position: absolute; left: 0px; top: 390px; height: 15px; width: 100%;"
>
some-id-26
</div>
<div
data-testid="some-id-27"
style="position: absolute; left: 0px; top: 405px; height: 15px; width: 100%;"
>
some-id-27
</div>
<div
data-testid="some-id-28"
style="position: absolute; left: 0px; top: 420px; height: 15px; width: 100%;"
>
some-id-28
</div>
<div
data-testid="some-id-29"
style="position: absolute; left: 0px; top: 435px; height: 15px; width: 100%;"
>
some-id-29
</div>
<div
data-testid="some-id-30"
style="position: absolute; left: 0px; top: 450px; height: 15px; width: 100%;"
>
some-id-30
</div>
<div
data-testid="some-id-31"
style="position: absolute; left: 0px; top: 465px; height: 15px; width: 100%;"
>
some-id-31
</div>
<div
data-testid="some-id-32"
style="position: absolute; left: 0px; top: 480px; height: 15px; width: 100%;"
>
some-id-32
</div>
<div
data-testid="some-id-33"
style="position: absolute; left: 0px; top: 495px; height: 15px; width: 100%;"
>
some-id-33
</div>
<div
data-testid="some-id-34"
style="position: absolute; left: 0px; top: 510px; height: 15px; width: 100%;"
>
some-id-34
</div>
<div
data-testid="some-id-35"
style="position: absolute; left: 0px; top: 525px; height: 15px; width: 100%;"
>
some-id-35
</div>
<div
data-testid="some-id-36"
style="position: absolute; left: 0px; top: 540px; height: 15px; width: 100%;"
>
some-id-36
</div>
<div
data-testid="some-id-37"
style="position: absolute; left: 0px; top: 555px; height: 15px; width: 100%;"
>
some-id-37
</div>
<div
data-testid="some-id-38"
style="position: absolute; left: 0px; top: 570px; height: 15px; width: 100%;"
>
some-id-38
</div>
<div
data-testid="some-id-39"
style="position: absolute; left: 0px; top: 585px; height: 15px; width: 100%;"
>
some-id-39
</div>
<div
data-testid="some-id-40"
style="position: absolute; left: 0px; top: 600px; height: 15px; width: 100%;"
>
some-id-40
</div>
<div
data-testid="some-id-41"
style="position: absolute; left: 0px; top: 615px; height: 15px; width: 100%;"
>
some-id-41
</div>
</div>
</div>
</div>
</div>
</body>
`;
exports[`VirtualList when visible item is selected renders 1`] = `
<body>
<div>
<div
class="VirtualList"
>
<div
class="list"
style="position: relative; height: 45px; width: 100%; overflow: auto; will-change: transform; direction: ltr;"
>
<div
style="height: 4545px; width: 100%;"
>
<div
data-testid="some-id-0"
style="position: absolute; left: 0px; top: 0px; height: 15px; width: 100%;"
>
some-id-0
</div>
<div
data-testid="some-id-1"
style="position: absolute; left: 0px; top: 15px; height: 15px; width: 100%;"
>
some-id-1
</div>
<div
data-testid="some-id-2"
style="position: absolute; left: 0px; top: 30px; height: 15px; width: 100%;"
>
some-id-2
</div>
<div
data-testid="some-id-3"
style="position: absolute; left: 0px; top: 45px; height: 15px; width: 100%;"
>
some-id-3
</div>
<div
data-testid="some-id-4"
style="position: absolute; left: 0px; top: 60px; height: 15px; width: 100%;"
>
some-id-4
</div>
<div
data-testid="some-id-5"
style="position: absolute; left: 0px; top: 75px; height: 15px; width: 100%;"
>
some-id-5
</div>
<div
data-testid="some-id-6"
style="position: absolute; left: 0px; top: 90px; height: 15px; width: 100%;"
>
some-id-6
</div>
<div
data-testid="some-id-7"
style="position: absolute; left: 0px; top: 105px; height: 15px; width: 100%;"
>
some-id-7
</div>
<div
data-testid="some-id-8"
style="position: absolute; left: 0px; top: 120px; height: 15px; width: 100%;"
>
some-id-8
</div>
<div
data-testid="some-id-9"
style="position: absolute; left: 0px; top: 135px; height: 15px; width: 100%;"
>
some-id-9
</div>
<div
data-testid="some-id-10"
style="position: absolute; left: 0px; top: 150px; height: 15px; width: 100%;"
>
some-id-10
</div>
<div
data-testid="some-id-11"
style="position: absolute; left: 0px; top: 165px; height: 15px; width: 100%;"
>
some-id-11
</div>
<div
data-testid="some-id-12"
style="position: absolute; left: 0px; top: 180px; height: 15px; width: 100%;"
>
some-id-12
</div>
</div>
</div>
</div>
</div>
</body>
`;

View File

@ -0,0 +1,81 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { RenderResult } from "@testing-library/react";
import { render } from "@testing-library/react";
import React from "react";
import { VirtualList } from "./virtual-list";
const generateListOfIdObjects = (count: number) => [...new Array(count)].map((v, index) => ({
getId() {
return `some-id-${index}`;
},
}));
const generateListOfRowHeights = (count: number, size: number) => [...new Array(count)].map(() => size);
const renderList = (selectedId?: string) => (
<VirtualList
items={generateListOfIdObjects(100)}
rowHeights={generateListOfRowHeights(100, 15)}
fixedHeight={45}
selectedItemId={selectedId}
getRow={(id) => <div data-testid={id}>{id}</div>}
/>
);
describe("VirtualList", () => {
let result: RenderResult;
beforeEach(() => {
result = render(renderList());
});
it("renders", () => {
expect(result.baseElement).toMatchSnapshot();
});
it("shows the first item", () => {
expect(result.queryByTestId("some-id-0")).toBeInTheDocument();
});
it("shows the second item", () => {
expect(result.queryByTestId("some-id-1")).toBeInTheDocument();
});
it("shows the third item", () => {
expect(result.queryByTestId("some-id-2")).toBeInTheDocument();
});
describe("when non-visable item is selected", () => {
beforeEach(() => {
result.rerender(renderList("some-id-30"));
});
it("renders", () => {
expect(result.baseElement).toMatchSnapshot();
});
it("shows selected item", () => {
expect(result.queryByTestId("some-id-30")).toBeInTheDocument();
});
it("does not show the first item", () => {
expect(result.queryByTestId("some-id-0")).not.toBeInTheDocument();
});
});
describe("when visible item is selected", () => {
beforeEach(() => {
result.rerender(renderList("some-id-2"));
});
it("renders", () => {
expect(result.baseElement).toMatchSnapshot();
});
it("shows selected item", () => {
expect(result.queryByTestId("some-id-2")).toBeInTheDocument();
});
});
});

View File

@ -14,7 +14,6 @@ import type { Align, ListChildComponentProps, ListOnScrollProps } from "react-wi
import { VariableSizeList } from "react-window"; import { VariableSizeList } from "react-window";
import { cssNames, noop } from "../../utils"; import { cssNames, noop } from "../../utils";
import type { TableRowProps } from "../table/table-row"; import type { TableRowProps } from "../table/table-row";
import debounce from "lodash/debounce";
import isEqual from "lodash/isEqual"; import isEqual from "lodash/isEqual";
import AutoSizer from "react-virtualized-auto-sizer"; import AutoSizer from "react-virtualized-auto-sizer";
@ -59,7 +58,7 @@ function VirtualListInner<T extends { getId(): string } | string>({
const listRef = createRef<VariableSizeList>(); const listRef = createRef<VariableSizeList>();
const prevItems = useRef(items); const prevItems = useRef(items);
const prevRowHeights = useRef(rowHeights); const prevRowHeights = useRef(rowHeights);
const scrollToSelectedItem = useCallback(debounce(() => { const scrollToSelectedItem = useCallback(() => {
if (!selectedItemId) { if (!selectedItemId) {
return; return;
} }
@ -71,9 +70,9 @@ function VirtualListInner<T extends { getId(): string } | string>({
)); ));
if (index >= 0) { if (index >= 0) {
listRef.current?.scrollToItem(index, "start"); listRef.current?.scrollToItem(index, "smart");
} }
}), [selectedItemId, [items]]); }, [selectedItemId, [items]]);
const getItemSize = (index: number) => rowHeights[index]; const getItemSize = (index: number) => rowHeights[index];
useImperativeHandle(forwardedRef, () => ({ useImperativeHandle(forwardedRef, () => ({