Merge pull request #1377 from ae-utbm/fix-component-nesting

Fix component nesting bug
This commit is contained in:
2026-05-08 13:01:09 +02:00
committed by GitHub
3 changed files with 16 additions and 9 deletions
@@ -84,11 +84,7 @@ const refreshElement = <
return; return;
} }
// This might be called at some bad timing element.refresh();
// This prevents crashes of the observer
if (element.refresh) {
element.refresh();
}
} }
}; };
@@ -134,7 +130,7 @@ startObserver(observer);
export class LinkOnce extends elementOnce("link") { export class LinkOnce extends elementOnce("link") {
getElementQuerySelector(): string { getElementQuerySelector(): string {
// We get href from node.attributes instead of node.href to avoid getting the domain part // We get href from node.attributes instead of node.href to avoid getting the domain part
return `link[href='${this.node.attributes.getNamedItem("href")?.nodeValue}']`; return `link[href='${this.node.attributes.getNamedItem("href").nodeValue}']`;
} }
} }
@@ -146,6 +142,6 @@ export class LinkOnce extends elementOnce("link") {
export class ScriptOnce extends inheritHtmlElement("script") { export class ScriptOnce extends inheritHtmlElement("script") {
getElementQuerySelector(): string { getElementQuerySelector(): string {
// We get href from node.attributes instead of node.src to avoid getting the domain part // We get href from node.attributes instead of node.src to avoid getting the domain part
return `script[src='${this.node.attributes.getNamedItem("src")?.nodeValue}']`; return `script[src='${this.node.attributes.getNamedItem("src").nodeValue}']`;
} }
} }
@@ -28,7 +28,7 @@ export class Tab extends HTMLElement {
return html` return html`
<button <button
role="tab" role="tab"
?aria-selected=${this.active} ?aria-selected="${this.active}"
class="tab-header clickable ${this.active ? "active" : ""}" class="tab-header clickable ${this.active ? "active" : ""}"
@click="${() => this.setActive(true)}" @click="${() => this.setActive(true)}"
> >
@@ -40,7 +40,7 @@ export class Tab extends HTMLElement {
return html` return html`
<section <section
class="tab-section" class="tab-section"
?hidden=${!this.active} ?hidden="${!this.active}"
> >
${unsafeHTML(this.getContentHtml())} ${unsafeHTML(this.getContentHtml())}
</section> </section>
@@ -47,9 +47,18 @@ export function inheritHtmlElement<K extends keyof HTMLElementTagNameMap>(tagNam
implements InheritedHtmlElement<K> implements InheritedHtmlElement<K>
{ {
readonly inheritedTagName = tagName; readonly inheritedTagName = tagName;
private readonly initializedAttribute = "component-initialized";
node: HTMLElementTagNameMap[K]; node: HTMLElementTagNameMap[K];
connectedCallback(autoAddNode?: boolean) { connectedCallback(autoAddNode?: boolean) {
// When nesting inherited elements, we might trigger the wrapping twice
// To avoid this, we tag a created element as initialized
// We then skip the initialization step and grab the inner content as the node
if (this.hasAttribute(this.initializedAttribute)) {
this.node = this.firstChild as HTMLElementTagNameMap[K];
return;
}
this.node = document.createElement(this.inheritedTagName); this.node = document.createElement(this.inheritedTagName);
const attributes: Attr[] = []; // We need to make a copy to delete while iterating const attributes: Attr[] = []; // We need to make a copy to delete while iterating
for (const attr of this.attributes) { for (const attr of this.attributes) {
@@ -58,6 +67,8 @@ export function inheritHtmlElement<K extends keyof HTMLElementTagNameMap>(tagNam
} }
} }
this.setAttribute(this.initializedAttribute, "");
// We move compatible attributes to the child element // We move compatible attributes to the child element
// This avoids weird inconsistencies between attributes // This avoids weird inconsistencies between attributes
// when we manipulate the dom in the future // when we manipulate the dom in the future