Stabilize collector scrolling for large package sets
Reserve each offscreen collector package with its exact expanded or collapsed block height so content-visibility cannot collapse flex items to zero and rebuild the scroll geometry while moving through the list. Add a regression test for the rendered intrinsic block-size contract.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { memo, useEffect, useState, type ChangeEvent, type ReactElement } from "react";
|
||||
import { memo, useEffect, useState, type ChangeEvent, type CSSProperties, type ReactElement } from "react";
|
||||
import { formatDateTime, formatHosterLabel, humanSize } from "../../download-format";
|
||||
import { DataTable, DataTableBody, DataTableEmpty, DataTableHeader } from "../../ui/DataTable";
|
||||
import { Dialog } from "../../ui/Dialog";
|
||||
@@ -81,6 +81,10 @@ function linkAvailability(availability: "online" | "offline" | "unknown"): strin
|
||||
return "Ungeprüft";
|
||||
}
|
||||
|
||||
export function collectorPackageIntrinsicBlockSize(row: CollectorWorkspacePackageRow): number {
|
||||
return 46 + (row.collapsed ? 0 : row.links.length * 40);
|
||||
}
|
||||
|
||||
export function toggleAllCollectorPackageIds(
|
||||
packageIds: readonly string[],
|
||||
collapsedPackageIds: ReadonlySet<string>
|
||||
@@ -166,6 +170,10 @@ function CollectorPackageGroup({ row, model, actions, selected }: {
|
||||
const partiallySelected = row.selectedCount > 0 && !allSelected;
|
||||
const animateItems = model.animationsEnabled && row.allLinks.length <= 64;
|
||||
const [renderItems, setRenderItems] = useState(!row.collapsed);
|
||||
const packageStyle: CSSProperties = {
|
||||
containIntrinsicBlockSize: `auto ${collectorPackageIntrinsicBlockSize(row)}px`,
|
||||
flex: "0 0 auto"
|
||||
};
|
||||
useEffect(() => {
|
||||
if (!row.collapsed) {
|
||||
setRenderItems(true);
|
||||
@@ -179,7 +187,7 @@ function CollectorPackageGroup({ row, model, actions, selected }: {
|
||||
return () => window.clearTimeout(timer);
|
||||
}, [animateItems, row.collapsed]);
|
||||
return (
|
||||
<div className={`collector-package-group${row.collapsed ? " is-collapsed" : ""}${model.animationsEnabled ? " is-motion-enabled" : ""}`} role="rowgroup">
|
||||
<div className={`collector-package-group${row.collapsed ? " is-collapsed" : ""}${model.animationsEnabled ? " is-motion-enabled" : ""}`} role="rowgroup" style={packageStyle}>
|
||||
<div className={`collector-package-row${row.selectedCount > 0 ? " is-selected" : ""}`} role="row">
|
||||
<span className="collector-column-select" role="cell">
|
||||
<input
|
||||
|
||||
@@ -216,7 +216,6 @@
|
||||
}
|
||||
|
||||
.collector-package-group {
|
||||
contain-intrinsic-size: 46px 654px;
|
||||
content-visibility: auto;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
CollectorSidebar,
|
||||
CollectorToolbar,
|
||||
CollectorView,
|
||||
collectorPackageIntrinsicBlockSize,
|
||||
toggleAllCollectorPackageIds,
|
||||
type CollectorViewActions
|
||||
} from "../src/renderer/views/collector/CollectorView";
|
||||
@@ -286,6 +287,15 @@ describe("collector workspace model", () => {
|
||||
});
|
||||
|
||||
describe("CollectorView", () => {
|
||||
it("reserves the exact package height while content visibility skips offscreen rows", () => {
|
||||
const expanded = buildCollectorWorkspaceViewModel([packages[0]], "all", "", false, [], [], "", true).packages[0];
|
||||
const collapsed = { ...expanded, collapsed: true };
|
||||
|
||||
expect(collectorPackageIntrinsicBlockSize(expanded)).toBe(126);
|
||||
expect(collectorPackageIntrinsicBlockSize(collapsed)).toBe(46);
|
||||
expect(renderToStaticMarkup(<CollectorContent actions={createActions()} model={buildCollectorWorkspaceViewModel([packages[0]], "all", "", false, [], [], "", true)} />)).toContain("contain-intrinsic-block-size:auto 126px");
|
||||
});
|
||||
|
||||
it("renders expandable package and file rows with preview columns", () => {
|
||||
const html = renderToStaticMarkup(<CollectorView actions={createActions()} model={buildCollectorWorkspaceViewModel(packages, "all", "", false, [], [], "", true)} />);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user