Composed-tree shadow DOM capture, sized invisible spacers, track re-anchoring, block fill-width slides, javascript: href sanitization

- Walker serializes the composed (flattened) tree: open shadow roots walk
  as host children with <slot> replaced by its assigned light nodes (or
  fallback), so custom-element content (product cards, web components) is
  captured instead of arriving childless
- In-flow visibility:hidden nodes with a nonzero border box survive the
  prune as sized invisible placeholders - ghost spacers carry load-bearing
  geometry
- When pruning drops leading in-flow children of a horizontally-translated
  track, the baked translateX is re-anchored by their aggregate margin-box
  width (settled carousel tracks return to origin instead of pushing real
  content off-screen); animation-owned transforms unaffected
- Circular-shrink slide guard counts block-level fill children as
  width-deriving regardless of wAuto (block auto-width IS fill), pinning
  library-sized slide widths uniformly
- javascript: hrefs emit as "#" and the link gate normalizes both sides

382 tests pass (18 new), typecheck clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Samraaj Bath
2026-07-04 02:41:00 -07:00
co-authored by Claude Fable 5
parent 6e4921884c
commit 762855664c
10 changed files with 509 additions and 13 deletions
+14 -5
View File
@@ -369,11 +369,20 @@ export function propsList(node: IRNode, assetMap: Map<string, string>, sourceUrl
if (kept.length === 0) continue;
value = kept.join(", ");
} else if (key === "href") {
// Preserve in-page anchors. For multi-route sites a linkRewrite maps internal
// links to the generated clone routes (and collapsed-collection links to their
// representative); otherwise absolutize so it never 404s inside the clone
// (external navigation is allowed by the rubric).
if (!value.startsWith("#")) value = ctx?.linkRewrite ? ctx.linkRewrite(value) : resolveUrl(value, sourceUrl);
// A `javascript:*` href (announcement bars, JS-driven buttons authored as links) is a
// script trigger, not a navigable URL. React refuses to render one: it rewrites the
// attribute to a long `javascript:throw new Error('React has blocked a javascript: URL…')`
// string, which no longer matches the source href in the link gate. The behaviour is
// script we don't reproduce anyway, so emit an inert `#` and keep the anchor navigable-inert.
if (/^\s*javascript:/i.test(value)) {
value = "#";
} else if (!value.startsWith("#")) {
// Preserve in-page anchors. For multi-route sites a linkRewrite maps internal
// links to the generated clone routes (and collapsed-collection links to their
// representative); otherwise absolutize so it never 404s inside the clone
// (external navigation is allowed by the rubric).
value = ctx?.linkRewrite ? ctx.linkRewrite(value) : resolveUrl(value, sourceUrl);
}
}
let reactName = isCustom ? key : (ATTR_RENAME[key] ?? key);
+10 -1
View File
@@ -1034,7 +1034,16 @@ function isCircularShrinkSlide(node: IRNode, parentNode: IRNode | undefined, vie
const cpos = ccs.position || "static";
if (cpos === "absolute" || cpos === "fixed") continue; // out of flow → no width contribution
const csz = c.sizingByVp?.[vp];
if (csz && csz.wFill === true && csz.wAuto === false) { fillChildren++; continue; } // fills the slide → derives width from it
// A block-level in-flow box (block/flex/grid/table/list-item) takes its width FROM its
// container by definition: its `width:auto` computed size IS the fill size, so the probe
// reports wAuto AND wFill both true — indistinguishable from a genuine content-sized source.
// Such a child still DERIVES its width from the slide (it never establishes one), so it must
// count as a fill child, not veto the circular case. Only wFill matters for a block child;
// wAuto is redundant with it. Inline / inline-block children (whose auto width is genuinely
// content-derived and can size the slide) keep the strict wFill && !wAuto test.
const cDisp = ccs.display || "";
const blockLevel = /^(block|flex|grid|table|list-item|flow-root)$/.test(cDisp);
if (csz && csz.wFill === true && (blockLevel || csz.wAuto === false)) { fillChildren++; continue; } // fills/derives width from the slide
return false; // a genuine in-flow width source → not circular
}
if (fillChildren === 0) return false;