Skip to content

Commit 6652fae

Browse files
committed
fix(#969): producer path propagates data-hf-authored-id to host element
When the producer inlines a sub-composition with compId match, it takes innerRoot.innerHTML which strips the wrapper div and its id attribute. CSS/GSAP selectors rewritten from #ID to [data-hf-authored-id=ID] then match nothing. Fix: after innerHTML injection, copy the inner root's id as data-hf-authored-id on the host element. This makes #ID selectors work identically in both preview (bundler) and render (producer) paths. Closes #969
1 parent c44b1aa commit 6652fae

2 files changed

Lines changed: 12 additions & 28 deletions

File tree

packages/core/src/compiler/inlineSubCompositions.test.ts

Lines changed: 6 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -131,46 +131,24 @@ describe("inlineSubCompositions – #ID selector scoping divergence", () => {
131131
expect(scopedCss).toContain('[data-hf-authored-id="intro"]');
132132
});
133133

134-
/**
135-
* Known divergence: the producer path strips the inner root element via
136-
* innerHTML (line 307 of inlineSubCompositions.ts), losing the id attribute.
137-
* The bundler path preserves it via flattenInnerRoot + data-hf-authored-id.
138-
*
139-
* Both paths rewrite CSS and GSAP selectors from `#intro` to
140-
* `[data-hf-authored-id="intro"]`, but only the bundler path actually adds
141-
* that attribute to an element. In the producer path, no element carries
142-
* `data-hf-authored-id`, so the rewritten selectors match nothing.
143-
*
144-
* Workaround: use [data-composition-id="name"] as scope in sub-compositions
145-
* instead of #name.
146-
*
147-
* Proper fix (follow-up): make the producer path add data-hf-authored-id
148-
* to the host element when the inner root has an id attribute.
149-
*/
150-
// FIXME(#969): flip these assertions once the producer path adds
151-
// data-hf-authored-id to the host element. See PR #965 "Proper fix (follow-up)".
152-
it("documents the divergence: producer path lacks data-hf-authored-id element", () => {
134+
it("producer path propagates data-hf-authored-id to host when inner root has id", () => {
153135
const document = makeHostDocument("intro");
154136
const host = document.querySelector('[data-composition-src="intro.html"]')!;
155137

156-
// Producer path: no flattenInnerRoot
157138
inlineSubCompositions(document, [host], {
158139
resolveHtml: () => SUB_COMP_HTML,
159140
parseHtml: (html) => parseHTML(html).document,
160141
});
161142

162-
// After producer inlining, no element inside the host has
163-
// data-hf-authored-id="intro". The rewritten CSS/GSAP selectors
164-
// targeting [data-hf-authored-id="intro"] will match nothing.
165-
const authoredIdElement = host.querySelector('[data-hf-authored-id="intro"]');
166-
expect(authoredIdElement).toBeNull();
143+
// The inner root's id="intro" is stripped (innerHTML), but the producer
144+
// now propagates it as data-hf-authored-id on the host element so that
145+
// rewritten #ID selectors ([data-hf-authored-id="intro"]) resolve.
146+
expect(host.getAttribute("data-hf-authored-id")).toBe("intro");
167147

168-
// The original #intro element is gone — innerHTML stripped it.
148+
// The original #intro element is still gone — innerHTML stripped it.
169149
const introById = host.querySelector("#intro");
170150
expect(introById).toBeNull();
171151

172-
// Only the host itself has data-composition-id="intro", which is the
173-
// correct workaround scope to use.
174152
expect(host.getAttribute("data-composition-id")).toBe("intro");
175153
});
176154
});

packages/core/src/compiler/inlineSubCompositions.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,12 @@ export function inlineSubCompositions(
305305
hostEl.innerHTML = prepared.outerHTML || "";
306306
} else {
307307
hostEl.innerHTML = compId ? innerRoot.innerHTML || "" : innerRoot.outerHTML || "";
308+
// When the producer path strips the inner root (innerHTML), the
309+
// authored id attribute is lost. Propagate it to the host so that
310+
// rewritten #ID selectors ([data-hf-authored-id="X"]) still resolve.
311+
if (compId && authoredRootId) {
312+
hostEl.setAttribute("data-hf-authored-id", authoredRootId);
313+
}
308314
}
309315
} else {
310316
for (const child of [...contentDoc.querySelectorAll("style, script")]) child.remove();

0 commit comments

Comments
 (0)