Grid plan equality guard, named-token px validation, breakpoint-ordered source variants, hidden-text diagnostic
- A grid-cols-N recipe plan may only override the authored template when computed tracks are near-equal - asymmetric sidebar templates (260px 1fr) keep their authored geometry - Source-intent named tokens (max-w-md etc.) re-emit only when their Tailwind-4 value matches the captured computed px; mismatches (older token scales) emit the captured value instead - Per-axis source-variant selection keeps the highest-min-width active variant instead of last-in-class-order, matching real Tailwind cascade (lg:grid-cols-3 no longer loses to a later md:grid-cols-2 at desktop) - latent since the initial commit - New non-blocking textHiddenInClone metric in the dom gate: counts capture-visible text that renders hidden in the clone, so silent disappearances surface in reports 435 tests pass (10 new), typecheck clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
f16c3aa4e8
commit
5b60ded62d
@@ -2496,6 +2496,36 @@ function computedTrackCount(value: string | undefined): number {
|
||||
return value.trim().split(/\s+/).filter(Boolean).length;
|
||||
}
|
||||
|
||||
// Resolved px widths of the explicit column tracks in a computed `grid-template-columns` value. The
|
||||
// capture resolves the property to a used track list (`260px 1020px`), so each token is a definite
|
||||
// px length. Non-px tokens (`auto`, `min-content`, a leftover `1fr`) make the track set unquantifiable
|
||||
// and yield null — the plan then cannot claim the tracks are uniform.
|
||||
function computedTrackWidths(value: string | undefined): number[] | null {
|
||||
if (!value || value === "none") return null;
|
||||
const toks = value.trim().split(/\s+/).filter(Boolean);
|
||||
const out: number[] = [];
|
||||
for (const t of toks) {
|
||||
const m = /^(-?\d*\.?\d+)px$/.exec(t);
|
||||
if (!m) return null;
|
||||
out.push(parseFloat(m[1]!));
|
||||
}
|
||||
return out.length ? out : null;
|
||||
}
|
||||
|
||||
// A `grid-cols-N` plan rewrites the container to `repeat(N, minmax(0, 1fr))` — N EQUAL tracks. It is
|
||||
// only a faithful replacement for the authored template when the computed tracks actually are ~equal
|
||||
// width. An asymmetric template (`260px 1fr` → a 260/1020 sidebar layout) has the same track COUNT as
|
||||
// the heuristic column count but a different geometry; collapsing it to equal halves destroys the
|
||||
// authored layout, so such templates always keep their computed tracks.
|
||||
function tracksNearEqual(widths: number[]): boolean {
|
||||
if (widths.length <= 1) return true;
|
||||
const max = Math.max(...widths);
|
||||
const min = Math.min(...widths);
|
||||
if (!(max > 0)) return false;
|
||||
// Tolerance: a couple of px (gap/rounding) or 2% of the widest track, whichever is larger.
|
||||
return max - min <= Math.max(1.5, 0.02 * max);
|
||||
}
|
||||
|
||||
// Track span of a grid item from its resolved `grid-column-start`/`grid-column-end`. A spanning
|
||||
// item (`span 2`, or an explicit line pair `1 / 3`) means row-length item-counting under-reports
|
||||
// the real track count, so the column-count heuristic is not trustworthy for this container.
|
||||
@@ -2536,12 +2566,20 @@ export function recipeResponsiveClassCleaner(ir: IR, recipes: RecipeReport | und
|
||||
if (!parent) return false;
|
||||
const itemCids = (c.repeatedItems ?? []).map((i) => i.cid);
|
||||
for (const vp of regimeVps) {
|
||||
const tracks = computedTrackCount(parent.computedByVp[vp]?.["gridTemplateColumns"]);
|
||||
const gtc = parent.computedByVp[vp]?.["gridTemplateColumns"];
|
||||
const tracks = computedTrackCount(gtc);
|
||||
// Only trust the heuristic where the computed grid actually is a track grid at this viewport.
|
||||
if (tracks === 0) continue;
|
||||
const regime = c.responsiveRegimes.find((r) => r.viewport === vp);
|
||||
const heuristicCols = regime?.columns ?? 0;
|
||||
if (heuristicCols > 0 && heuristicCols !== tracks) return false;
|
||||
// A `grid-cols-N` plan means N EQUAL tracks. If the computed tracks are asymmetric (a sidebar
|
||||
// template like `260px 1020px`), the count agrees but the geometry does not — collapsing to
|
||||
// equal columns would destroy the authored layout. Keep the authored template in that case.
|
||||
if (tracks >= 2) {
|
||||
const widths = computedTrackWidths(gtc);
|
||||
if (!widths || !tracksNearEqual(widths)) return false;
|
||||
}
|
||||
for (const cid of itemCids) {
|
||||
if (computedColumnSpan(nodeByCid.get(cid)?.computedByVp[vp]) > 1) return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user