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:
parent
657119b22b
commit
7ab3d419b3
@ -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>
|
||||
`;
|
||||
81
src/renderer/components/virtual-list/virtual-list.test.tsx
Normal file
81
src/renderer/components/virtual-list/virtual-list.test.tsx
Normal 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();
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -14,7 +14,6 @@ import type { Align, ListChildComponentProps, ListOnScrollProps } from "react-wi
|
||||
import { VariableSizeList } from "react-window";
|
||||
import { cssNames, noop } from "../../utils";
|
||||
import type { TableRowProps } from "../table/table-row";
|
||||
import debounce from "lodash/debounce";
|
||||
import isEqual from "lodash/isEqual";
|
||||
import AutoSizer from "react-virtualized-auto-sizer";
|
||||
|
||||
@ -59,7 +58,7 @@ function VirtualListInner<T extends { getId(): string } | string>({
|
||||
const listRef = createRef<VariableSizeList>();
|
||||
const prevItems = useRef(items);
|
||||
const prevRowHeights = useRef(rowHeights);
|
||||
const scrollToSelectedItem = useCallback(debounce(() => {
|
||||
const scrollToSelectedItem = useCallback(() => {
|
||||
if (!selectedItemId) {
|
||||
return;
|
||||
}
|
||||
@ -71,9 +70,9 @@ function VirtualListInner<T extends { getId(): string } | string>({
|
||||
));
|
||||
|
||||
if (index >= 0) {
|
||||
listRef.current?.scrollToItem(index, "start");
|
||||
listRef.current?.scrollToItem(index, "smart");
|
||||
}
|
||||
}), [selectedItemId, [items]]);
|
||||
}, [selectedItemId, [items]]);
|
||||
const getItemSize = (index: number) => rowHeights[index];
|
||||
|
||||
useImperativeHandle(forwardedRef, () => ({
|
||||
|
||||
Loading…
Reference in New Issue
Block a user