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,18 @@
|
||||
import { useSyncExternalStore } from "react";
|
||||
|
||||
/** Whether a CSS media query matches, live. For a component that must RENDER differently at a
|
||||
* breakpoint rather than merely hide one of two renders with CSS (`ui/DataTable` mounted its table
|
||||
* AND its card list at every width: double the DOM, duplicate ids and keyboard targets). Where
|
||||
* `matchMedia` is missing (jsdom) it answers `fallback`. */
|
||||
export function useMediaQuery(query: string, fallback = true): boolean {
|
||||
return useSyncExternalStore(
|
||||
(onChange) => {
|
||||
if (typeof window.matchMedia !== "function") return () => {};
|
||||
const mql = window.matchMedia(query);
|
||||
mql.addEventListener("change", onChange);
|
||||
return () => mql.removeEventListener("change", onChange);
|
||||
},
|
||||
() => (typeof window.matchMedia === "function" ? window.matchMedia(query).matches : fallback),
|
||||
() => fallback,
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user