Skip to content

Commit

Permalink
feat!: remove(add) optional elements from(in) DOM
Browse files Browse the repository at this point in the history
  • Loading branch information
infodusha committed Sep 2, 2023
1 parent 28b4e4f commit b305c72
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 18 deletions.
14 changes: 14 additions & 0 deletions example/components/card.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,31 @@
<h3 data-attr="header">No header</h3>
</slot>
<slot>No data</slot>
<button data-if="action">Action</button>
<span data-if="action" data-if-not>No action</span>
</template>

<style>
:host {
display: flex;
flex-direction: column;
row-gap: 6px;
border-radius: 3px;
border: solid 1px black;
padding: 12px;
}
</style>

<script>
setInterval(() => {
const hasAction = this.hasAttribute('action');
if (hasAction) {
this.removeAttribute('action');
} else {
this.setAttribute('action', '');
}
}, 1500);
</script>

<script src="../scripts/card.js"></script>
<script src="../scripts/card.js" type="module"></script>
2 changes: 1 addition & 1 deletion example/components/root.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<app-card header="Easy to install">
Just add script tag and it works
</app-card>
<app-card></app-card>
<app-card action></app-card>
<app-card>
<i slot="header">Easy to understand</i>
No complex parts at all - just plain HTML
Expand Down
52 changes: 35 additions & 17 deletions src/create-component.ts
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down Expand Up @@ -46,7 +42,10 @@ export function createComponent(definedElement: Document, relativeTo: string): [

readonly #attrElements: HTMLElement[] = [];
readonly #attrDefaults = new WeakMap<HTMLElement, ChildNode[]>();
readonly #optionalElements: Element[] = [];

readonly #optionalElements: HTMLElement[] = [];
readonly #optionalMarkers = new WeakMap<HTMLElement, Comment>();

readonly #cleanupFns = new Set<CleanupFn>();

constructor() {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}
}
}
Expand All @@ -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)));
Expand All @@ -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);
Expand Down

0 comments on commit b305c72

Please sign in to comment.