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.
This commit is contained in:
2026-10-05 00:19:38 +02:00
parent adaa7dc23c
commit 2eb20ca227
2 changed files with 12 additions and 24 deletions
+8 -12
View File
@@ -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 },