feat: remove attach-effect

This commit is contained in:
Ayo Ayco 2025-03-09 00:34:10 +01:00
parent d41affd709
commit 9ead44babe
12 changed files with 2135 additions and 681 deletions

View file

@ -52,9 +52,9 @@ The result is a reactive UI on property changes.
## Project Status
It is ready for many cases we see people use custom elements for. If you have a cool project built on **WebComponent.io** we'd love to know! :)
It is ready for many simple cases we see people use custom elements for. If you have a cool project built on **WebComponent.io** we'd love to know! :)
For building some advanced interactions, we have a few issues that are still open: [#24 smart diffing](https://github.com/ayoayco/web-component-base/issues/24) & [#4 attachEffect improvements](https://github.com/ayoayco/web-component-base/issues/4)
For building advanced interactions, we have an in-progress work on smart diffing to prevent component children being wiped on interaction.
In the mean time, if you have some complex needs, we recommend using the `WebComponent` base class with a more mature rendering approach like `lit-html`... and here's a demo for that: [View on CodePen ↗](https://codepen.io/ayoayco-the-styleful/pen/ZEwNJBR?editors=1010).
@ -91,15 +91,13 @@ You can import everything separately, or in a single file each for the main expo
```js
// all in a single file
import { WebComponent, html, attachEffect } from 'web-component-base'
import { WebComponent, html } from 'web-component-base'
// in separate files
import { WebComponent } from 'web-component-base/WebComponent.js'
import { html } from 'web-component-base/html.js'
import { attachEffect } from 'web-component-base/attach-effect.js'
```
### Utilities
@ -221,7 +219,6 @@ Some feature-specific demos:
1. [Using dynamic style objects](https://codepen.io/ayoayco-the-styleful/pen/bGzXjwQ?editors=1010)
1. [Using the Shadow DOM](https://codepen.io/ayoayco-the-styleful/pen/VwRYVPv?editors=1010)
1. [Using tagged templates in your vanilla custom element](https://codepen.io/ayoayco-the-styleful/pen/bGzJQJg?editors=1010)
1. [Using attachEffect (experimental)](https://codepen.io/ayoayco-the-styleful/pen/ExrdWPv?editors=1011)
## `template` vs `render()`
@ -448,9 +445,9 @@ class ClickableText extends WebComponent {
All the functions and the base class in the library are minimalist by design and only contains what is needed for their purpose.
As of v2.0.0, the main export (with `WebComponent` + `html` + `attachEffect`) is 1.7 kB (min + gzip) according to [bundlephobia.com](https://bundlephobia.com/package/web-component-base@2.0.0), and the `WebComponent` base class is just 1.1 kB (min + brotli) according to [size-limit](http://github.com/ai/size-limit).
As of v3, the main export (with `WebComponent` + `html`) is 1.7 kB (min + gzip) according to [bundlephobia.com](https://bundlephobia.com/package/web-component-base@2.0.0), and the `WebComponent` base class is just 1.08 kB (min + brotli) according to [size-limit](http://github.com/ai/size-limit).
There is an increase in size compared to that of before this release, primarily because of advanced features (e.g., effects, html tagged templates, and props blueprints) in building complex applications.
There is an increase in size compared to that of before this release, primarily because of advanced features (e.g., html tagged templates, and props blueprints) in building complex applications.
## Inspirations and thanks

View file

@ -1,23 +0,0 @@
// @ts-check
import { WebComponent, attachEffect, html } from '../../src/index.js'
export class Counter extends WebComponent {
static props = {
count: 0,
}
onInit() {
attachEffect(this.props.count, (count) => console.log(count))
}
afterViewInit() {
attachEffect(this.props.count, (count) => console.log(count + 100))
}
get template() {
return html`<button onclick=${() => ++this.props.count} id="btn">
${this.props.count}
</button>`
}
}
customElements.define('my-counter', Counter)

View file

@ -1,24 +0,0 @@
// @ts-check
import { WebComponent, attachEffect, html } from '../../src/index.js'
export class Decrease extends WebComponent {
static props = {
count: 999,
}
onInit() {
attachEffect(this.props.count, (count) => console.log(count))
}
afterViewInit() {
attachEffect(this.props.count, (count) => console.log(count + 100))
}
get template() {
return html`<button onclick=${() => --this.props.count} id="btn">
${this.props.count}
</button>`
}
}
customElements.define('my-decrement', Decrease)

View file

@ -1,15 +0,0 @@
<!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="./Counter.mjs"></script>
<script type="module" src="./Decrease.mjs"></script>
</head>
<body>
<h1>Attach Effect Test</h1>
<my-counter></my-counter>
<my-decrement></my-decrement>
</body>
</html>

View file

@ -1,6 +1,7 @@
<!doctype html>
<html lang="en">
<head>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>WC demo</title>
@ -13,8 +14,9 @@
font-size: larger;
}
</style>
</head>
<body>
</head>
<body>
<div>Counter: <my-counter></my-counter></div>
<div>Toggle: <my-toggle></my-toggle></div>
<div>String: <my-hello-world></my-hello-world></div>
@ -23,14 +25,20 @@
<p id="display-panel"></p>
</div>
<script type="module">
import { attachEffect } from '../../src/index.js'
const myObjectEl = document.querySelector('my-object')
const objectProp = myObjectEl.props.object
const displayPanelEl = document.querySelector('#display-panel')
displayPanelEl.textContent = JSON.stringify(objectProp)
attachEffect(objectProp, (object) => {
displayPanelEl.textContent = JSON.stringify(object)
})
/**
* TODO: fix using custom events
*/
// import { attachEffect } from '../../src/index.js'
// const myObjectEl = document.querySelector('my-object')
// const objectProp = myObjectEl.props.object
// const displayPanelEl = document.querySelector('#display-panel')
// displayPanelEl.textContent = JSON.stringify(objectProp)
// attachEffect(objectProp, (object) => {
// displayPanelEl.textContent = JSON.stringify(object)
// })
// console.log(JSON.stringify(object))
</script>
</body>
</body>
</html>

View file

@ -101,5 +101,8 @@
"path": "./dist/utils/get-kebab-case.js",
"limit": "0.5 KB"
}
]
],
"dependencies": {
"release-it": "^18.1.2"
}
}

File diff suppressed because it is too large Load diff

View file

@ -25,13 +25,6 @@ class FeatureSet extends WebComponent {
'Use the built-in JSX-like syntax or bring your own custom templating',
url: 'https://codepen.io/ayoayco-the-styleful/pen/ZEwNJBR?editors=1010',
},
{
icon: '️🛜',
title: 'Powerful.',
description:
"Attach 'side effects' that gets triggered on property value changes",
url: '',
},
]
/**

View file

@ -1,10 +1,10 @@
<!doctype html>
<html lang="en">
<!--
<!--
Hello! This page is an example McFly page.
See more on https://ayco.io/gh/McFly
-->
<my-head>
<my-head>
<title>WebComponent.io: Web Components in Easy Mode</title>
<link rel="stylesheet" href="prism.css" />
<script src="prism.js" defer></script>
@ -25,6 +25,7 @@
symbols: '️✅';
suffix: ' ';
}
main {
font-size: large;
@ -42,13 +43,15 @@
text-align: center;
}
}
& code-block {
overflow: auto;
}
}
</style>
</my-head>
<body>
</my-head>
<body>
<awesome-header>
<span>{{ project.name }}</span>
<span slot="description">{{ project.description }}</span>
@ -78,10 +81,6 @@
Use the built-in JSX-like syntax or bring your own custom
templating
</li>
<li>
Attach 'side effects' that gets triggered on property value
changes
</li>
</ul>
</feature-set>
</div>
@ -90,11 +89,8 @@
<h2>Why use this base class?</h2>
<p>
Often times, when simple websites need a quick
<a
href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Components/Using_custom_elements"
target="_blank"
>custom element</a
>, the best way is still to create one extending from
<a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Components/Using_custom_elements"
target="_blank">custom element</a>, the best way is still to create one extending from
<code-block inline>HTMLElement</code-block>. However, it can quickly
reach a point where writing the code from scratch can seem confusing
and hard to maintain especially when compared to other projects with
@ -136,20 +132,18 @@ export class Counter extends WebComponent {
}
}
customElements.define(&quot;my-counter&quot;, Counter);</pre
>
customElements.define(&quot;my-counter&quot;, Counter);</pre>
</code-block>
</section>
</main>
<my-footer>
<small>
<a href="https://ayco.io/sh/wcb/tree/main/site"
>Website</a
>
<a href="https://ayco.io/sh/wcb/tree/main/site">Website</a>
built with <a href="https://mcfly.js.org">McFly</a>.<br />
Copyright &copy; {{author.year}}
<a href="{{ author.url }}">{{ author.name }}</a>.
</small>
</my-footer>
</body>
</body>
</html>

View file

@ -20,7 +20,6 @@ export class WebComponent extends HTMLElement {
#prevDOM
#props
#typeMap = {}
#effectsMap = {}
/**
* Array of strings that tells the browsers which attributes will cause a render
@ -130,7 +129,6 @@ export class WebComponent extends HTMLElement {
}
#handler(setter, meta) {
const effectsMap = meta.#effectsMap
const typeMap = meta.#typeMap
return {
@ -141,12 +139,7 @@ export class WebComponent extends HTMLElement {
typeMap[prop] = typeof value
}
if (value.attach === 'effect') {
if (!effectsMap[prop]) {
effectsMap[prop] = []
}
effectsMap[prop].push(value.callback)
} else if (typeMap[prop] !== typeof value) {
if (typeMap[prop] !== typeof value) {
throw TypeError(
`Cannot assign ${typeof value} to ${
typeMap[prop]
@ -154,7 +147,6 @@ export class WebComponent extends HTMLElement {
)
} else if (oldValue !== value) {
obj[prop] = value
effectsMap[prop]?.forEach((f) => f(value))
const kebab = getKebabCase(prop)
setter(kebab, serialize(value))
}

View file

@ -1,13 +0,0 @@
/**
* Attach a "side effect" function that gets triggered on property value changes
* @param {Object} obj
* @param {(newValue: any) => void} callback
*/
export function attachEffect(obj, callback) {
const { proxy, prop } = Object.getPrototypeOf(obj)
proxy[prop] = {
attach: 'effect',
callback,
}
}

View file

@ -1,3 +1,2 @@
export { attachEffect } from './attach-effect.js'
export { WebComponent } from './WebComponent.js'
export { html } from './html.js'