diff --git a/example/components/card.html b/example/components/card.html index b5f053a..7d78acd 100644 --- a/example/components/card.html +++ b/example/components/card.html @@ -3,17 +3,31 @@

No header

No data + + No action + + diff --git a/example/components/root.html b/example/components/root.html index 57436f1..d8bd718 100644 --- a/example/components/root.html +++ b/example/components/root.html @@ -4,7 +4,7 @@ Just add script tag and it works - + Easy to understand No complex parts at all - just plain HTML diff --git a/src/create-component.ts b/src/create-component.ts index c1969d4..916ca50 100644 --- a/src/create-component.ts +++ b/src/create-component.ts @@ -1,9 +1,5 @@ import {appendCssLink, applyGlobalStyles, getEncapsulatedCss} from './css-helpers.js'; -import { - cloneNode, - returnIfDefined, - throwIfNotDefined, -} from './helpers.js'; +import {cloneNode, returnIfDefined, throwIfNotDefined} from './helpers.js'; import {CleanupFn, executeScript} from "./execute-script.js"; interface AttributeChanged { @@ -46,7 +42,10 @@ export function createComponent(definedElement: Document, relativeTo: string): [ readonly #attrElements: HTMLElement[] = []; readonly #attrDefaults = new WeakMap(); - readonly #optionalElements: Element[] = []; + + readonly #optionalElements: HTMLElement[] = []; + readonly #optionalMarkers = new WeakMap(); + readonly #cleanupFns = new Set(); constructor() { @@ -74,11 +73,23 @@ export function createComponent(definedElement: Document, relativeTo: string): [ #initOptionality(): void { for (const element of this.#optionalElements) { if (!this.#isElementVisible(element)) { - element.setAttribute('hidden', ''); + this.#hideOptional(element); } } } + #hideOptional(element: HTMLElement): void { + if (this.#optionalMarkers.has(element)) { + // Already hidden + return; + } + const text = ` data-if="${element.getAttribute('data-if')}" `; + const marker = document.createComment(text) + element.before(marker); + this.#optionalMarkers.set(element, marker); + element.remove(); + } + #isElementVisible(element: Element): boolean { const name = element.getAttribute('data-if'); throwIfNotDefined(name); @@ -158,10 +169,17 @@ export function createComponent(definedElement: Document, relativeTo: string): [ #applyOptionality(name: string): void { const optionalForElements = this.#optionalElements.filter((element) => element.getAttribute('data-if') === name); for (const element of optionalForElements) { - if (!this.#isElementVisible(element)) { - element.setAttribute('hidden', ''); + if (this.#isElementVisible(element)) { + const marker = this.#optionalMarkers.get(element); + if (!marker) { + // Already visible + continue; + } + marker.after(element); + marker.remove(); + this.#optionalMarkers.delete(element); } else { - element.removeAttribute('hidden'); + this.#hideOptional(element); } } } @@ -182,8 +200,8 @@ export function createComponent(definedElement: Document, relativeTo: string): [ } #setAttrs(): void { - for (const attrElement of this.#attrElements) { - this.#attrDefaults.set(attrElement, Array.from(attrElement.childNodes)); + for (const element of this.#attrElements) { + this.#attrDefaults.set(element, Array.from(element.childNodes)); } for (const name of this.getAttributeNames()) { this.#applyAttr(name, returnIfDefined(this.getAttribute(name))); @@ -209,11 +227,11 @@ export function createComponent(definedElement: Document, relativeTo: string): [ return [selector, Component]; } -function getUsedAttributes(template: HTMLTemplateElement, dataAttributeNames: string[]): string[] { - return dataAttributeNames - .map((dataAttributeName) => { - return Array.from(template.content.querySelectorAll(`[${dataAttributeName}]`)) - .map((element) => returnIfDefined(element.getAttribute(dataAttributeName))) +function getUsedAttributes(template: HTMLTemplateElement, attributeNames: string[]): string[] { + return attributeNames + .map((attributeName) => { + return Array.from(template.content.querySelectorAll(`[${attributeName}]`)) + .map((element) => returnIfDefined(element.getAttribute(attributeName))) }) .flat() .filter((v, i, arr) => arr.indexOf(v) === i);