From 29fa864ca25ebd03d5eaadcdaf89f2514e94d5cf Mon Sep 17 00:00:00 2001 From: Ayo Ayco Date: Tue, 26 Dec 2023 23:48:54 +0100 Subject: [PATCH] feat: use shadow mode (#39) --- examples/use-shadow/index.html | 13 ++++++++ examples/use-shadow/index.js | 55 ++++++++++++++++++++++++++++++++++ package.json | 2 +- src/WebComponent.js | 18 ++++++++--- 4 files changed, 83 insertions(+), 5 deletions(-) create mode 100644 examples/use-shadow/index.html create mode 100644 examples/use-shadow/index.js diff --git a/examples/use-shadow/index.html b/examples/use-shadow/index.html new file mode 100644 index 0000000..3493307 --- /dev/null +++ b/examples/use-shadow/index.html @@ -0,0 +1,13 @@ + + + + + + WC demo + + + +

With our html

+ + + diff --git a/examples/use-shadow/index.js b/examples/use-shadow/index.js new file mode 100644 index 0000000..5057c56 --- /dev/null +++ b/examples/use-shadow/index.js @@ -0,0 +1,55 @@ +// @ts-check +import { WebComponent, html } from "../../src/index.js"; + +export class Counter extends WebComponent { + static props = { + count: 123, + }; + static shadowRootInit = { + mode: "closed", + }; + + get template() { + const list = ["a", "b", "c", "what"]; + const links = [ + { + url: "https://ayco.io", + text: "Ayo Ayco", + }, + { + url: "https://ayco.io/gh/McFly", + text: "McFly", + }, + ]; + + return html` + +
+ + +
+ ${list.map((item) => html`

${item}

`)} +

Links

+ + `; + } +} + +customElements.define("my-counter", Counter); diff --git a/package.json b/package.json index eb6bbae..b73d4f0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "web-component-base", - "version": "2.1.0-beta.1", + "version": "2.1.0-beta.2", "description": "A zero-dependency & tiny JS base class for creating reactive custom elements easily", "type": "module", "exports": { diff --git a/src/WebComponent.js b/src/WebComponent.js index 652b1e9..e8fff55 100644 --- a/src/WebComponent.js +++ b/src/WebComponent.js @@ -38,6 +38,12 @@ export class WebComponent extends HTMLElement { return ""; } + /** + * Shadow root initialization options + * @type {ShadowRootInit} + */ + static shadowRootInit; + /** * Read-only property containing camelCase counterparts of observed attributes. * @see https://www.npmjs.com/package/web-component-base#prop-access @@ -146,7 +152,7 @@ export class WebComponent extends HTMLElement { throw TypeError( `Cannot assign ${typeof value} to ${ typeMap[prop] - } property (setting '${prop}' of ${meta.constructor.name})`, + } property (setting '${prop}' of ${meta.constructor.name})` ); } else if (oldValue !== value) { obj[prop] = value; @@ -178,7 +184,7 @@ export class WebComponent extends HTMLElement { if (!this.#props) { this.#props = new Proxy( initialProps, - this.#handler((key, value) => this.setAttribute(key, value), this), + this.#handler((key, value) => this.setAttribute(key, value), this) ); } } @@ -188,14 +194,18 @@ export class WebComponent extends HTMLElement { if (typeof this.template === "string") { this.innerHTML = this.template; } else if (typeof this.template === "object") { + let host = this; + if (this.constructor.shadowRootInit) { + host = this.attachShadow(this.constructor.shadowRootInit); + } const tree = this.template; // TODO: smart diffing if (JSON.stringify(this.#prevDOM) !== JSON.stringify(tree)) { const el = createElement(tree); if (el) { - if (Array.isArray(el)) this.replaceChildren(...el); - else this.replaceChildren(el); + if (Array.isArray(el)) host.replaceChildren(...el); + else host.replaceChildren(el); } this.#prevDOM = tree; }