Skip to content

Instantly share code, notes, and snippets.

@minecrawler
Created December 13, 2019 08:39
Show Gist options
  • Save minecrawler/e988a1abc9dec09943b4a247faddf2a6 to your computer and use it in GitHub Desktop.
Save minecrawler/e988a1abc9dec09943b4a247faddf2a6 to your computer and use it in GitHub Desktop.
export class BaseElement extends HTMLElement {
dirty: boolean = true;
root: ShadowRoot;
constructor(hideInternals: boolean = true) {
super();
this.root = this.attachShadow({ mode: hideInternals ? 'closed' : 'open' });
const observer = new MutationObserver(() => {
this.dirty = true;
this.tryRender().catch(err => this.fireError(err));
});
observer.observe(this, {
attributes: true,
childList: true,
subtree: true,
});
}
clear() {
while (this.root.firstChild) {
this.root.removeChild(this.root.firstChild);
}
}
connectedCallback() {
this.tryRender().catch(err => this.fireError(err));
}
protected draw(html: string = '', css: string = '') {
const styleEle = document.createElement('style');
const contentFragment = document.createRange().createContextualFragment(html);
styleEle.innerHTML = css;
this.root.appendChild(styleEle);
this.root.appendChild(contentFragment);
}
protected fireError(error: Error) {
this.dispatchEvent(new ErrorEvent('error', {
error,
message: error.message,
}));
}
protected render() { /* overwrite me */ }
static get observedAttributes(): string[] { return []; /* overwrite me */ }
static registerTag(tagName: string) {
if (customElements.get(tagName)) return;
customElements.define(tagName, this);
}
async tryRender() {
if (this.dirty) {
this.clear();
await this.render();
this.dirty = false;
}
}
queryInternalElement<T extends Element>(query: string): T | null {
return this.root.querySelector<T>(query);
}
queryInternalElements<T extends Element>(query: string): NodeListOf<T> {
return this.root.querySelectorAll<T>(query);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment