feat: use shadow mode (#39)

This commit is contained in:
Ayo Ayco 2023-12-26 23:48:54 +01:00 committed by GitHub
parent d4dcea4503
commit 29fa864ca2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 83 additions and 5 deletions

View file

@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>WC demo</title>
<script type="module" src="./index.js"></script>
</head>
<body>
<h2>With our html</h2>
<my-counter></my-counter>
</body>
</html>

View file

@ -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`
<button
class="hey"
id="btn"
onClick=${() => ++this.props.count}
style=${{ backgroundColor: "green", color: "white" }}
about="Elephant"
data-name="thing"
aria-name="thingz"
>
<span>${this.props.count}</span>
</button>
<form style="margin: 1em 0;">
<label data-my-name="Ayo" for="the-input">Name</label>
<input id="the-input" type="foo" value="Name:" />
</form>
${list.map((item) => html`<p>${item}</p>`)}
<h3 about="Elephant">Links</h3>
<ul>
${links.map(
(link) =>
html`<li>
<a href=${link.url} target="_blank">${link.text}</a>
</li>`
)}
</ul>
`;
}
}
customElements.define("my-counter", Counter);

View file

@ -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": {

View file

@ -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;
}