mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-24 12:42:49 +00:00
d1ef487e09
On `/proxmox` with 140 workload rows, 859 window `resize` listeners were active after load (203 at phone width with 36 rows), so every window resize ran one callback per listener: - 699 from `useTooltipState.ts` (`useTooltipLayoutState`), which registered a listener for every tooltip instance, including the hidden `TooltipPortal` on each row's metric bars and sparklines. - 156 from `useBreakpoint.ts`, where every call added its own listener and width signal. ## Change - Tooltip layout state listens only while its tooltip is visible and re-reads the viewport when it opens. `useTooltipPortalState` uses the same visibility gate as the portal's render (`when && supportsHoverTooltips()`), so a portal suppressed on a touch device holds no listener either. - `useBreakpoint` keeps one module-level width signal and shared memos, fed by a single rAF-debounced listener while at least one caller is mounted. A new caller syncs to the live `innerWidth`, so a caller created after resizes nobody heard starts correct. ## Evidence Live pass on a private mock-mode stack (headless Chromium, add/removeEventListener wrapped to track live listeners by registering frame): | | before | after | |---|---|---| | 1440×900, 140 rows | 859 active, 859 callbacks per resize | 5 active, 5 callbacks | | 390×844, 36 rows | 203 active | 5 active | - An open row tooltip adds exactly one listener, stays open through window resizes (its viewBox follows 1440×700 and 1380×640), and its listener is removed on close. - Crossing the phone breakpoint in both directions still switches the workload table (`workload-table--desktop` ↔ `--mobile`) and each row's layout. - New tests: `useBreakpoint.test.ts` (one listener for 50 callers, back-to-back resizes leave one pending frame, every caller crosses a breakpoint, a new caller starts from the live width) and `TooltipPortal.test.tsx` (hidden and touch-suppressed portals add no listener, an open portal re-clamps on resize, a portal opened after an unheard resize uses the live viewport). The listener assertions fail against main. - 198 frontend test files / 3620 tests pass across `components/shared`, `components/Workloads`, the hooks, AppLayout, AIChat, Docker tables and the boundary tests; prettier, eslint and tsc are clean. Contract notes: `frontend-primitives.md` (tooltip owner) and `performance-and-scalability.md` (new current-state section). `useBreakpoint.ts` has no owning subsystem, so its rule lives in the performance contract.