feat: remove attach-effect
This commit is contained in:
parent
d41affd709
commit
9ead44babe
12 changed files with 2135 additions and 681 deletions
13
README.md
13
README.md
|
@ -52,9 +52,9 @@ The result is a reactive UI on property changes.
|
||||||
|
|
||||||
## Project Status
|
## 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).
|
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
|
```js
|
||||||
// all in a single file
|
// all in a single file
|
||||||
|
|
||||||
import { WebComponent, html, attachEffect } from 'web-component-base'
|
import { WebComponent, html } from 'web-component-base'
|
||||||
|
|
||||||
// in separate files
|
// in separate files
|
||||||
|
|
||||||
import { WebComponent } from 'web-component-base/WebComponent.js'
|
import { WebComponent } from 'web-component-base/WebComponent.js'
|
||||||
|
|
||||||
import { html } from 'web-component-base/html.js'
|
import { html } from 'web-component-base/html.js'
|
||||||
|
|
||||||
import { attachEffect } from 'web-component-base/attach-effect.js'
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Utilities
|
### 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 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 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 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()`
|
## `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.
|
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
|
## Inspirations and thanks
|
||||||
|
|
||||||
|
|
|
@ -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)
|
|
|
@ -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)
|
|
|
@ -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>
|
|
|
@ -1,6 +1,7 @@
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
|
||||||
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>WC demo</title>
|
<title>WC demo</title>
|
||||||
|
@ -13,8 +14,9 @@
|
||||||
font-size: larger;
|
font-size: larger;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
|
||||||
|
<body>
|
||||||
<div>Counter: <my-counter></my-counter></div>
|
<div>Counter: <my-counter></my-counter></div>
|
||||||
<div>Toggle: <my-toggle></my-toggle></div>
|
<div>Toggle: <my-toggle></my-toggle></div>
|
||||||
<div>String: <my-hello-world></my-hello-world></div>
|
<div>String: <my-hello-world></my-hello-world></div>
|
||||||
|
@ -23,14 +25,20 @@
|
||||||
<p id="display-panel"></p>
|
<p id="display-panel"></p>
|
||||||
</div>
|
</div>
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import { attachEffect } from '../../src/index.js'
|
/**
|
||||||
const myObjectEl = document.querySelector('my-object')
|
* TODO: fix using custom events
|
||||||
const objectProp = myObjectEl.props.object
|
*/
|
||||||
const displayPanelEl = document.querySelector('#display-panel')
|
|
||||||
displayPanelEl.textContent = JSON.stringify(objectProp)
|
// import { attachEffect } from '../../src/index.js'
|
||||||
attachEffect(objectProp, (object) => {
|
// const myObjectEl = document.querySelector('my-object')
|
||||||
displayPanelEl.textContent = JSON.stringify(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>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
|
@ -101,5 +101,8 @@
|
||||||
"path": "./dist/utils/get-kebab-case.js",
|
"path": "./dist/utils/get-kebab-case.js",
|
||||||
"limit": "0.5 KB"
|
"limit": "0.5 KB"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"release-it": "^18.1.2"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
2375
pnpm-lock.yaml
2375
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
@ -25,13 +25,6 @@ class FeatureSet extends WebComponent {
|
||||||
'Use the built-in JSX-like syntax or bring your own custom templating',
|
'Use the built-in JSX-like syntax or bring your own custom templating',
|
||||||
url: 'https://codepen.io/ayoayco-the-styleful/pen/ZEwNJBR?editors=1010',
|
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: '',
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<!--
|
<!--
|
||||||
Hello! This page is an example McFly page.
|
Hello! This page is an example McFly page.
|
||||||
See more on https://ayco.io/gh/McFly
|
See more on https://ayco.io/gh/McFly
|
||||||
-->
|
-->
|
||||||
<my-head>
|
<my-head>
|
||||||
<title>WebComponent.io: Web Components in Easy Mode</title>
|
<title>WebComponent.io: Web Components in Easy Mode</title>
|
||||||
<link rel="stylesheet" href="prism.css" />
|
<link rel="stylesheet" href="prism.css" />
|
||||||
<script src="prism.js" defer></script>
|
<script src="prism.js" defer></script>
|
||||||
|
@ -25,6 +25,7 @@
|
||||||
symbols: '️✅';
|
symbols: '️✅';
|
||||||
suffix: ' ';
|
suffix: ' ';
|
||||||
}
|
}
|
||||||
|
|
||||||
main {
|
main {
|
||||||
font-size: large;
|
font-size: large;
|
||||||
|
|
||||||
|
@ -42,13 +43,15 @@
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
& code-block {
|
& code-block {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</my-head>
|
</my-head>
|
||||||
<body>
|
|
||||||
|
<body>
|
||||||
<awesome-header>
|
<awesome-header>
|
||||||
<span>{{ project.name }}</span>
|
<span>{{ project.name }}</span>
|
||||||
<span slot="description">{{ project.description }}</span>
|
<span slot="description">{{ project.description }}</span>
|
||||||
|
@ -78,10 +81,6 @@
|
||||||
Use the built-in JSX-like syntax or bring your own custom
|
Use the built-in JSX-like syntax or bring your own custom
|
||||||
templating
|
templating
|
||||||
</li>
|
</li>
|
||||||
<li>
|
|
||||||
Attach 'side effects' that gets triggered on property value
|
|
||||||
changes
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</feature-set>
|
</feature-set>
|
||||||
</div>
|
</div>
|
||||||
|
@ -90,11 +89,8 @@
|
||||||
<h2>Why use this base class?</h2>
|
<h2>Why use this base class?</h2>
|
||||||
<p>
|
<p>
|
||||||
Often times, when simple websites need a quick
|
Often times, when simple websites need a quick
|
||||||
<a
|
<a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Components/Using_custom_elements"
|
||||||
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
|
||||||
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
|
<code-block inline>HTMLElement</code-block>. However, it can quickly
|
||||||
reach a point where writing the code from scratch can seem confusing
|
reach a point where writing the code from scratch can seem confusing
|
||||||
and hard to maintain especially when compared to other projects with
|
and hard to maintain especially when compared to other projects with
|
||||||
|
@ -136,20 +132,18 @@ export class Counter extends WebComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("my-counter", Counter);</pre
|
customElements.define("my-counter", Counter);</pre>
|
||||||
>
|
|
||||||
</code-block>
|
</code-block>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
<my-footer>
|
<my-footer>
|
||||||
<small>
|
<small>
|
||||||
<a href="https://ayco.io/sh/wcb/tree/main/site"
|
<a href="https://ayco.io/sh/wcb/tree/main/site">Website</a>
|
||||||
>Website</a
|
|
||||||
>
|
|
||||||
built with <a href="https://mcfly.js.org">McFly</a>.<br />
|
built with <a href="https://mcfly.js.org">McFly</a>.<br />
|
||||||
Copyright © {{author.year}}
|
Copyright © {{author.year}}
|
||||||
<a href="{{ author.url }}">{{ author.name }}</a>.
|
<a href="{{ author.url }}">{{ author.name }}</a>.
|
||||||
</small>
|
</small>
|
||||||
</my-footer>
|
</my-footer>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
|
@ -20,7 +20,6 @@ export class WebComponent extends HTMLElement {
|
||||||
#prevDOM
|
#prevDOM
|
||||||
#props
|
#props
|
||||||
#typeMap = {}
|
#typeMap = {}
|
||||||
#effectsMap = {}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Array of strings that tells the browsers which attributes will cause a render
|
* 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) {
|
#handler(setter, meta) {
|
||||||
const effectsMap = meta.#effectsMap
|
|
||||||
const typeMap = meta.#typeMap
|
const typeMap = meta.#typeMap
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -141,12 +139,7 @@ export class WebComponent extends HTMLElement {
|
||||||
typeMap[prop] = typeof value
|
typeMap[prop] = typeof value
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value.attach === 'effect') {
|
if (typeMap[prop] !== typeof value) {
|
||||||
if (!effectsMap[prop]) {
|
|
||||||
effectsMap[prop] = []
|
|
||||||
}
|
|
||||||
effectsMap[prop].push(value.callback)
|
|
||||||
} else if (typeMap[prop] !== typeof value) {
|
|
||||||
throw TypeError(
|
throw TypeError(
|
||||||
`Cannot assign ${typeof value} to ${
|
`Cannot assign ${typeof value} to ${
|
||||||
typeMap[prop]
|
typeMap[prop]
|
||||||
|
@ -154,7 +147,6 @@ export class WebComponent extends HTMLElement {
|
||||||
)
|
)
|
||||||
} else if (oldValue !== value) {
|
} else if (oldValue !== value) {
|
||||||
obj[prop] = value
|
obj[prop] = value
|
||||||
effectsMap[prop]?.forEach((f) => f(value))
|
|
||||||
const kebab = getKebabCase(prop)
|
const kebab = getKebabCase(prop)
|
||||||
setter(kebab, serialize(value))
|
setter(kebab, serialize(value))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,3 +1,2 @@
|
||||||
export { attachEffect } from './attach-effect.js'
|
|
||||||
export { WebComponent } from './WebComponent.js'
|
export { WebComponent } from './WebComponent.js'
|
||||||
export { html } from './html.js'
|
export { html } from './html.js'
|
||||||
|
|
Loading…
Reference in a new issue