import { $el } from "rgthree/common/utils_dom.js"; const CSS_STYLE_SHEETS = new Map(); const HTML_TEMPLATE_FILES = new Map(); /** * Fetches the stylesheet for the component, matched by the element name (minus the "rgthree-" * prefix). */ async function getStyleSheet(name: string) { if (!CSS_STYLE_SHEETS.has(name)) { try { const response = await fetch( `rgthree/common/components/${name.replace("rgthree-", "").replace(/\-/g, "_")}.css`, ); const text = await response.text(); CSS_STYLE_SHEETS.set(name, text); } catch (e) { alert("Error loading rgthree custom component css."); } } return CSS_STYLE_SHEETS.get(name)!; } /** * Fetches the stylesheet for the component, matched by the element name (minus the "rgthree-" * prefix). */ async function getTemplateMarkup(name: string) { if (!HTML_TEMPLATE_FILES.has(name)) { try { const response = await fetch( `rgthree/common/components/${name.replace("rgthree-", "").replace(/\-/g, "_")}.html`, ); const text = await response.text(); HTML_TEMPLATE_FILES.set(name, text); } catch (e) { // alert("Error loading rgthree custom component markup."); } } return HTML_TEMPLATE_FILES.get(name)!; } /** * A base custom element. */ export abstract class RgthreeCustomElement extends HTMLElement { static NAME = "rgthree-override"; static create(): T { if (this.name === "rgthree-override") { throw new Error("Must override component NAME"); } if (!customElements.get(this.name)) { customElements.define(this.NAME, this as unknown as CustomElementConstructor); } return document.createElement(this.NAME) as T; } protected connected: boolean = false; protected shadow!: ShadowRoot; protected readonly templates = new Map(); onFirstConnected(): void { // Optionally overridden. }; onReconnected(): void { // Optionally overridden. }; onConnected(): void { // Optionally overridden. }; onDisconnected(): void { // Optionally overridden. }; async connectedCallback() { const elementName = (this.constructor as any).NAME as string; const wasConnected = this.connected; if (!wasConnected) { this.connected = true; } if (!this.shadow) { const [stylesheet, markup] = await Promise.all([ getStyleSheet(elementName), getTemplateMarkup(elementName), ]); if (markup) { const temp = $el('div') const templatesMarkup = markup.match(//gm) || []; for(const markup of templatesMarkup) { temp.innerHTML = markup; const template = temp.children[0]; if (!(template instanceof HTMLTemplateElement)) { throw new Error('Not a template element.'); } const id = template.getAttribute('id'); if (!id) { throw new Error('Not template id.'); } this.templates.set(id, template); } } this.shadow = this.attachShadow({mode: "open"}); const sheet = new CSSStyleSheet(); sheet.replaceSync(stylesheet); this.shadow.adoptedStyleSheets = [sheet]; let template; if (this.templates.has(elementName)) { template = this.templates.get(elementName); } else if (this.templates.has(elementName.replace('rgthree-', ''))) { template = this.templates.get(elementName.replace('rgthree-', '')) } if (template) { this.shadow.appendChild(template.content.cloneNode(true)); } this.onFirstConnected(); } else { this.onReconnected(); } this.onConnected(); } disconnectedCallback() { this.connected = false; this.onDisconnected() } }