1// @ts-check 2 3import { hydrate } from "./helpers.9905f63b.js"; 4 5/** 6 * Requires a `template` element to be present on page with the custom element's 7 * client-side template. The `template` element should have an `id` of the custom 8 * element's name prefixed with `template-`, e.g. `template-my-custom-element`. 9 */ 10export class CustomHTMLElement extends HTMLElement { 11 /** 12 * Custom element's name 13 * @type {string | undefined} 14 */ 15 static get is() { return undefined; } 16 17 /** 18 * Ensures custom elements are only defined once per page load and pass along 19 * the promise created with `customElements.whenDefined`. 20 * 21 * A rejected promise is returned when the custom element's name is not defined 22 * via `is` or when custom elements are not available for the current browser. 23 */ 24 static async register() { 25 if (this.is === undefined) { 26 throw new Error('No defined name'); 27 } 28 29 if (!window.customElements) { 30 throw new Error('window.customElements not available'); 31 } 32 33 const elementName = this.is; 34 const promise = window.customElements.whenDefined(elementName); 35 const isDefined = window.customElements.get(elementName) !== undefined; 36 37 if (!isDefined) { 38 window.customElements.define(elementName, this); 39 } 40 41 return promise; 42 } 43 44 constructor() { 45 super(); 46 47 /** @type {HTMLTemplateElement} */ 48 // @ts-ignore 49 this.template = document.getElementById(`template-${this.constructor.is}`); 50 this.attachShadow({ mode: 'open' }); 51 52 /** @type {string[]} */ 53 this.knownCustomElements = []; 54 } 55 56 /** 57 * When extending `CustomHTMLElement` and defining your own `connectedCallback`,
58 * be sure to call `super.connectedCallback()` to support hydration of child 59 * elements in both the regular and shadow DOMs. 60 */ 61 connectedCallback() { 62 if (!this.shadowRoot || !this.isConnected || !this.template) { 63 return; 64 } 65 66 this.shadowRoot.appendChild( 67 this.template.content.cloneNode(true), 68 ); 69 70 [ 71 ...this.querySelectorAll('[data-template]'), 72 ...this.shadowRoot.querySelectorAll('[data-template]'), 73 ] 74 .forEach(this.hydrateSubComponents.bind(this)); 75 } 76 77 /** 78 * @param {Element} el 79 */ 80 hydrateSubComponents(el) { 81 const name = el.getAttribute('data-template'); 82 83 // skip if missing element name or already hydrated elements 84 if (!name || this.knownCustomElements.indexOf(name) !== -1) { 85 return; 86 } 87 88 this.knownCustomElements.push(name); 89 hydrate(name); 90 } 91}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.