Notes app :)
1// To be paired with a server-side rendering step.
2class DeclarativeElement extends HTMLElement {
3 static element_name = "never";
4
5 static attrs = [];
6 dryAttributes = [];
7
8 constructor() {
9 super();
10 }
11
12 connectedCallback() {
13 const supportsDeclarative = HTMLElement.prototype.hasOwnProperty("attachInternals");
14 const internals = supportsDeclarative ? this.attachInternals() : undefined;
15
16 // check for a Declarative Shadow Root.
17 let shadow = internals?.shadowRoot;
18
19 if (!shadow) {
20 // there wasn't one. create a new Shadow Root:
21 shadow = this.attachShadow({
22 mode: "closed",
23 });
24 const templateEl = document.querySelector(`template[element="${this.constructor.element_name}"]`);
25 shadow.append(templateEl.content.cloneNode(true));
26 }
27
28 this.shadow = shadow;
29
30 this.dryAttributes.forEach(element => {
31 this.attributeSet(element.property, element.oldValue, element.newValue);
32 });
33 this.start(shadow);
34 }
35
36 static get observedAttributes() {
37 return this.attrs;
38 }
39 attributeChangedCallback(property, oldValue, newValue) {
40 if (oldValue === newValue) return;
41 this[property] = newValue;
42
43 if (this.shadow == null) {
44 this.dryAttributes.push({ property: property, oldValue: oldValue, newValue: newValue });
45 } else {
46 this.attributeSet(property, oldValue, newValue);
47 }
48 }
49
50 static define() {
51 if (this.element_name === undefined) {
52 console.warn("No template!");
53 }
54 customElements.define(this.element_name, this);
55 }
56
57 start(shadow) {
58 // ...
59 }
60
61 attributeSet(property, oldValue, newValue) {
62 // ...
63 }
64}
65
66
67export { DeclarativeElement };