initial attach effect
This commit is contained in:
parent
0209095d0a
commit
d2a96b4fa4
6 changed files with 76 additions and 41 deletions
17
attach-effect/Counter.mjs
Normal file
17
attach-effect/Counter.mjs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// @ts-check
|
||||||
|
import WebComponent from "../src/WebComponent.js";
|
||||||
|
// import { attachEffect } from "../src/attach-effect.js";
|
||||||
|
|
||||||
|
export class Counter extends WebComponent {
|
||||||
|
static properties = ["count"];
|
||||||
|
onInit() {
|
||||||
|
this.props.count = 0;
|
||||||
|
this.onclick = () => ++this.props.count;
|
||||||
|
// attachEffect(this.props, 'count', console.log);
|
||||||
|
}
|
||||||
|
get template() {
|
||||||
|
return `<button id="btn">${this.props.count}</button>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define("my-counter", Counter);
|
13
attach-effect/index.html
Normal file
13
attach-effect/index.html
Normal 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="Counter.mjs"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Attach Effect Test</h1>
|
||||||
|
<my-counter></my-counter>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -1,2 +0,0 @@
|
||||||
shamefully-hoist=true
|
|
||||||
strict-peer-dependencies=false
|
|
|
@ -1,2 +1 @@
|
||||||
import McFly from "@mcflyjs/config";
|
export default defineNitroConfig({ extends: '@mcflyjs/config' });
|
||||||
export default defineNitroConfig({ ...McFly() });
|
|
||||||
|
|
|
@ -87,75 +87,77 @@ export class WebComponent extends HTMLElement {
|
||||||
this.onDestroy();
|
this.onDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
attributeChangedCallback(property, previousValue, currentValue) {
|
||||||
* @param {string} property
|
|
||||||
* @param {any} previousValue
|
|
||||||
* @param {any} currentValue
|
|
||||||
*/
|
|
||||||
attributeChangedCallback(property, previousValue, currentValue) {
|
|
||||||
const camelCaps = this.#getCamelCaps(property);
|
const camelCaps = this.#getCamelCaps(property);
|
||||||
|
|
||||||
if (previousValue !== currentValue) {
|
if (previousValue !== currentValue) {
|
||||||
this[property] = currentValue === "" || currentValue;
|
this[property] = currentValue === "" || currentValue;
|
||||||
this[camelCaps] = this[property]; // remove on v2
|
this[camelCaps] = this[property]; // remove on v2
|
||||||
this.props[camelCaps] = this[property];
|
this.props[camelCaps] = {
|
||||||
|
attributeChanged: true,
|
||||||
|
value: this[property],
|
||||||
|
}
|
||||||
|
|
||||||
this.render();
|
this.render();
|
||||||
this.onChanges({ property, previousValue, currentValue });
|
this.onChanges({ property, previousValue, currentValue });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a kebab-cased string into camelCaps
|
|
||||||
* @param {string} kebab string in kebab-case
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
#getCamelCaps(kebab) {
|
#getCamelCaps(kebab) {
|
||||||
return kebab.replace(/-./g, (x) => x[1].toUpperCase());
|
return kebab.replace(/-./g, (x) => x[1].toUpperCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
#typeMap = {}
|
||||||
* Proxy handler for observed attribute - property counterpart
|
#handler = (setter, typeMap) => ({
|
||||||
* @param {(qualifiedName: string, value: string) => void} setter
|
set(obj, prop, value) {
|
||||||
* @returns
|
const attributeChanged = value?.attributeChanged ?? false;
|
||||||
*/
|
let newValue = attributeChanged ? value.value : value;
|
||||||
#handler = (setter) => ({
|
|
||||||
set(obj, prop, newValue) {
|
|
||||||
const oldValue = obj[prop];
|
const oldValue = obj[prop];
|
||||||
|
|
||||||
|
console.log(">>>", newValue, oldValue);
|
||||||
|
|
||||||
obj[prop] = newValue;
|
if (!(prop in typeMap)) {
|
||||||
|
typeMap[prop] = typeof newValue;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
obj[prop] = restoreType(newValue, typeMap[prop])
|
||||||
* Converts camelCaps string into kebab-case
|
|
||||||
* @param {string} str
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
const getKebab = (str) =>
|
|
||||||
str.replace(
|
|
||||||
/[A-Z]+(?![a-z])|[A-Z]/g,
|
|
||||||
($, ofs) => (ofs ? "-" : "") + $.toLowerCase()
|
|
||||||
);
|
|
||||||
|
|
||||||
if (oldValue != newValue) {
|
if (attributeChanged && !oldValue != newValue) {
|
||||||
const kebab = getKebab(prop);
|
const kebab = getKebab(prop);
|
||||||
setter(kebab, newValue);
|
setter(kebab, newValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function getKebab(str) {
|
||||||
|
return str.replace(
|
||||||
|
/[A-Z]+(?![a-z])|[A-Z]/g,
|
||||||
|
($, ofs) => (ofs ? "-" : "") + $.toLowerCase()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function restoreType(value, type) {
|
||||||
|
switch(type) {
|
||||||
|
case 'string': return value;
|
||||||
|
case 'number': return parseInt(value);
|
||||||
|
case 'boolean': return JSON.parse(value);
|
||||||
|
default: return value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the `props` proxy object
|
|
||||||
*/
|
|
||||||
#initializeProps() {
|
#initializeProps() {
|
||||||
if (!this.#props) {
|
if (!this.#props) {
|
||||||
this.#props = new Proxy(
|
this.#props = new Proxy(
|
||||||
{},
|
{},
|
||||||
this.#handler((key, value) => this.setAttribute(key, value))
|
this.#handler((key, value) => this.setAttribute(key, value), this.#typeMap)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default WebComponent;
|
export default WebComponent;
|
||||||
|
|
6
src/attach-effect.js
Normal file
6
src/attach-effect.js
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
export function attachEffect(proxy, prop, callback) {
|
||||||
|
proxy[prop] = {
|
||||||
|
attach: 'effect',
|
||||||
|
callback
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue