From 2eb20ca2273986dc02f8f32276378425bb598d16 Mon Sep 17 00:00:00 2001 From: npeter83 Date: Sun, 4 Oct 2026 22:03:19 +0200 Subject: [PATCH] build(eslint): one px-frozen box selector for box utilities and grid minimums BOX_PX and GRID_MIN_PX were two esquery patterns with two messages for one rule (DESIGN.md: a px box does not scale with --font-scale). They are one alternation now, with one message that names both fixes. Nothing it refused before passes now; pxBox.contract.test.ts pins both shapes unchanged. --- frontend/eslint.config.js | 20 ++++++++------------ frontend/src/lib/gates.snapshot.json | 16 ++++------------ 2 files changed, 12 insertions(+), 24 deletions(-) diff --git a/frontend/eslint.config.js b/frontend/eslint.config.js index e523075a..a2849b6b 100644 --- a/frontend/eslint.config.js +++ b/frontend/eslint.config.js @@ -431,18 +431,16 @@ const localRules = { }, }; -// A px-frozen BOX utility (the no-restricted-syntax block below): an esquery regex, as a string. -// `[\d.]+`, not `\d+`: a fractional `text-[9.5px]` slipped past the integer-only pattern. +// A px-frozen BOX (the no-restricted-syntax block below): an esquery regex, as a string. A box utility +// (`w-[150px]`) or a grid's auto-fill column MINIMUM (`minmax(150px,1fr)`): the text inside grows with +// the slider while the box or the column floor stays, so it re-wraps, clips or cramps at a large text +// size (E30 review for the grid). `[\d.]+`, not `\d+`: a fractional `text-[9.5px]` slipped past the +// integer-only pattern. A fixed track (`grid-cols-[1fr_240px]`) is left alone, as is VirtualGrid's +// measured `minCol` (a number). const BOX_PX = - "/(^|[\\s:])(min-|max-)?(w|h|size|left|right|top|bottom|inset|gap|p[xytrbl]?|m[xytrbl]?)-\\[[\\d.]+px\\]/"; + "/(^|[\\s:])(min-|max-)?(w|h|size|left|right|top|bottom|inset|gap|p[xytrbl]?|m[xytrbl]?)-\\[[\\d.]+px\\]|minmax\\([\\d.]+px,/"; const BOX_PX_MESSAGE = - "px-frozen box size doesn't scale with --font-scale: use the spacing scale (w-37.5, max-w-60), not w-[Npx]."; -// …and a grid's auto-fill column MINIMUM in px (`minmax(150px,1fr)`): the cards' text grows with the -// slider while the column floor stays, so the cards get cramped at a large text size (E30 review). A -// fixed track (`grid-cols-[1fr_240px]`) is left alone, as is VirtualGrid's measured `minCol` (a number). -const GRID_MIN_PX = "/minmax\\([\\d.]+px,/"; -const GRID_MIN_PX_MESSAGE = - "px-frozen box size doesn't scale with --font-scale: give a grid column's minimum in rem (minmax(9.375rem,1fr)), not minmax(Npx,…)."; + "px-frozen box size doesn't scale with --font-scale: use the spacing scale (w-37.5, max-w-60) or rem (minmax(9.375rem,1fr)), not w-[Npx] or minmax(Npx,…)."; // A hover that swaps a colour instead of laying the B3 state layer (DESIGN.md Tokens): `bg-card`, // `bg-border` and `bg-surface` vanish on a light card, an opacity dim reads as "disabled", and // `bg-(--hover)` restates the `state-layer` utility by hand. `group-hover:` (a reveal on a parent's @@ -649,8 +647,6 @@ export default tseslint.config( // 150px at the default size) — 32 of these were swept in the 2026-09 debt burn. { selector: `Literal[value=${BOX_PX}]`, message: BOX_PX_MESSAGE }, { selector: `TemplateElement[value.raw=${BOX_PX}]`, message: BOX_PX_MESSAGE }, - { selector: `Literal[value=${GRID_MIN_PX}]`, message: GRID_MIN_PX_MESSAGE }, - { selector: `TemplateElement[value.raw=${GRID_MIN_PX}]`, message: GRID_MIN_PX_MESSAGE }, { selector: `Literal[value=${HOVER_SWAP}]`, message: HOVER_SWAP_MESSAGE }, { selector: `TemplateElement[value.raw=${HOVER_SWAP}]`, message: HOVER_SWAP_MESSAGE }, { selector: `Literal[value=${PALETTE}]`, message: PALETTE_MESSAGE }, diff --git a/frontend/src/lib/gates.snapshot.json b/frontend/src/lib/gates.snapshot.json index 50ab72b5..b311c0f0 100644 --- a/frontend/src/lib/gates.snapshot.json +++ b/frontend/src/lib/gates.snapshot.json @@ -855,20 +855,12 @@ "selector": "TemplateElement[value.raw=/text-\\[[\\d.]+px\\]/]" }, { - "message": "px-frozen box size doesn't scale with --font-scale: use the spacing scale (w-37.5, max-w-60), not w-[Npx].", - "selector": "Literal[value=/(^|[\\s:])(min-|max-)?(w|h|size|left|right|top|bottom|inset|gap|p[xytrbl]?|m[xytrbl]?)-\\[[\\d.]+px\\]/]" + "message": "px-frozen box size doesn't scale with --font-scale: use the spacing scale (w-37.5, max-w-60) or rem (minmax(9.375rem,1fr)), not w-[Npx] or minmax(Npx,…).", + "selector": "Literal[value=/(^|[\\s:])(min-|max-)?(w|h|size|left|right|top|bottom|inset|gap|p[xytrbl]?|m[xytrbl]?)-\\[[\\d.]+px\\]|minmax\\([\\d.]+px,/]" }, { - "message": "px-frozen box size doesn't scale with --font-scale: use the spacing scale (w-37.5, max-w-60), not w-[Npx].", - "selector": "TemplateElement[value.raw=/(^|[\\s:])(min-|max-)?(w|h|size|left|right|top|bottom|inset|gap|p[xytrbl]?|m[xytrbl]?)-\\[[\\d.]+px\\]/]" - }, - { - "message": "px-frozen box size doesn't scale with --font-scale: give a grid column's minimum in rem (minmax(9.375rem,1fr)), not minmax(Npx,…).", - "selector": "Literal[value=/minmax\\([\\d.]+px,/]" - }, - { - "message": "px-frozen box size doesn't scale with --font-scale: give a grid column's minimum in rem (minmax(9.375rem,1fr)), not minmax(Npx,…).", - "selector": "TemplateElement[value.raw=/minmax\\([\\d.]+px,/]" + "message": "px-frozen box size doesn't scale with --font-scale: use the spacing scale (w-37.5, max-w-60) or rem (minmax(9.375rem,1fr)), not w-[Npx] or minmax(Npx,…).", + "selector": "TemplateElement[value.raw=/(^|[\\s:])(min-|max-)?(w|h|size|left|right|top|bottom|inset|gap|p[xytrbl]?|m[xytrbl]?)-\\[[\\d.]+px\\]|minmax\\([\\d.]+px,/]" }, { "message": "hover by a colour swap: use the B3 layer (`state-layer`, Pressable `layer`, `state-filled` on a fill), not hover:bg-card / bg-border / opacity-N.",