fix(layout): keep covered text flagged when the occlusion waiver is on a wrapper (#4380)

Cause: text_occluded walked from the covered text up to any ancestor with
data-layout-allow-occlusion, so a mark on a wrapper cleared text a sibling
node was still covering.

Rationale: the waiver still clears the finding when it is on the covered text
itself. A mark on an outer wrapper no longer does.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Xuanru Li
2026-09-24 01:28:42 +00:00
committed by GitHub
co-authored by Cursor
parent 01601d1105
commit 625bdd66fa
2 changed files with 20 additions and 1 deletions
@@ -911,7 +911,7 @@
}
function hasAllowOcclusionFlag(element) {
return !!element.closest("[data-layout-allow-occlusion]");
return element.hasAttribute("data-layout-allow-occlusion");
}
// A foreign element is one painted independently of the text — not the text
@@ -2481,6 +2481,25 @@ describe("layout-audit.browser occlusion", () => {
expect(issues.some((issue) => issue.code === "text_occluded")).toBe(false);
});
it("still flags covered text when only an ancestor allows occlusion", () => {
document.body.innerHTML = `
<div id="root" data-composition-id="main" data-width="1920" data-height="1080">
<div id="node-top" data-layout-allow-occlusion>
<div id="headline">Typed Answers</div>
</div>
<div id="overlay"></div>
</div>
`;
installOcclusionGeometry({
styleOverrides: { overlay: { backgroundColor: "rgb(10, 10, 10)" } },
headlineTextRect: rect({ left: 200, top: 500, width: 600, height: 80 }),
topmostId: "overlay",
});
installAuditScript();
const occluded = runAudit().find((issue) => issue.code === "text_occluded");
expect(occluded).toMatchObject({ selector: "#headline", containerSelector: "#overlay" });
});
it("does not treat a visible container as painted text when its only text child is hidden", () => {
document.body.innerHTML = `
<div id="root" data-composition-id="main" data-width="1920" data-height="1080">