fix(ui): a sticky table header turns the scroller's top fade off itself; DataTable renders one layout
- "A page with a sticky ColumnHead must declare fadeTop: false" lived in prose: a registry flag on three pages plus an App special case for the Channels card layout, and the next table page would have re-acquired the fade-on-the-header defect with every lane green. ColumnHead now registers itself with the enclosing PageScroller (ui/stickyTop) while mounted; the registry flag, the App branch and the prop plumbing are gone. Measured on localdev: the top mask is 0px under Channels' and Audit's headers, 20px on Home and the Feed. - ui/DataTable mounted its table AND its card list at every width, one hidden by CSS: double DOM and render cost, duplicate ids, two keyboard copies of every row. It now mounts the one the `md` media query calls for (lib/useMediaQuery); the keyboard test asserts one layout at each width. - The Plex module's content width went px → rem with the rest of the page.
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
// @vitest-environment jsdom
|
||||
//
|
||||
// The page scroller's top fade sits ON a sticky table header, so a page with one used to opt out by
|
||||
// hand (`fadeTop: false` in the module registry, plus an App special case for the Channels card
|
||||
// layout) — and the next table page would have re-acquired the defect with every lane green. The
|
||||
// header now says so itself: while a `ColumnHead` is mounted the scroller asks for no top fade.
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { cleanup, render } from "@testing-library/react";
|
||||
|
||||
const fadeTopArgs: boolean[] = [];
|
||||
vi.mock("../../lib/useScrollFade", () => ({
|
||||
useScrollFade: (_px: number, fadeTop: boolean) => {
|
||||
fadeTopArgs.push(fadeTop);
|
||||
return { ref: () => {}, style: {} };
|
||||
},
|
||||
}));
|
||||
vi.mock("react-i18next", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("react-i18next")>();
|
||||
return { ...actual, useTranslation: () => ({ t: (key: string) => key }) };
|
||||
});
|
||||
|
||||
import PageScroller from "./PageScroller";
|
||||
import { ColumnHead } from "./tableHeader";
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
fadeTopArgs.length = 0;
|
||||
});
|
||||
|
||||
function page(withTable: boolean) {
|
||||
return (
|
||||
<PageScroller scrollKey="k">
|
||||
{withTable ? (
|
||||
<table>
|
||||
<ColumnHead
|
||||
columns={[]}
|
||||
sort={null}
|
||||
onToggleSort={() => {}}
|
||||
filters={{}}
|
||||
onFilter={() => {}}
|
||||
/>
|
||||
</table>
|
||||
) : (
|
||||
<div>cards</div>
|
||||
)}
|
||||
</PageScroller>
|
||||
);
|
||||
}
|
||||
|
||||
describe("the page scroller's top fade and a sticky table header", () => {
|
||||
it("is off while the header is mounted, and back on the moment it is gone", () => {
|
||||
const view = render(page(true));
|
||||
expect(fadeTopArgs.at(-1)).toBe(false);
|
||||
view.rerender(page(false)); // e.g. the Channels card layout, or a narrow DataTable
|
||||
expect(fadeTopArgs.at(-1)).toBe(true);
|
||||
});
|
||||
|
||||
it("is on for a page with no sticky header at all", () => {
|
||||
render(page(false));
|
||||
expect(fadeTopArgs.at(-1)).toBe(true);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user