diff --git a/attach-effect/Counter.mjs b/attach-effect/Counter.mjs new file mode 100644 index 0000000..0c44864 --- /dev/null +++ b/attach-effect/Counter.mjs @@ -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 ``; + } +} + +customElements.define("my-counter", Counter); diff --git a/attach-effect/index.html b/attach-effect/index.html new file mode 100644 index 0000000..0b077eb --- /dev/null +++ b/attach-effect/index.html @@ -0,0 +1,13 @@ + + + + + + WC demo + + + +

Attach Effect Test

+ + + diff --git a/site/.npmrc b/site/.npmrc deleted file mode 100644 index cf04042..0000000 --- a/site/.npmrc +++ /dev/null @@ -1,2 +0,0 @@ -shamefully-hoist=true -strict-peer-dependencies=false diff --git a/site/nitro.config.mjs b/site/nitro.config.mjs index 1064497..82a71b7 100644 --- a/site/nitro.config.mjs +++ b/site/nitro.config.mjs @@ -1,2 +1 @@ -import McFly from "@mcflyjs/config"; -export default defineNitroConfig({ ...McFly() }); +export default defineNitroConfig({ extends: '@mcflyjs/config' }); diff --git a/src/WebComponent.js b/src/WebComponent.js index 65e1fcb..526975f 100644 --- a/src/WebComponent.js +++ b/src/WebComponent.js @@ -87,75 +87,77 @@ export class WebComponent extends HTMLElement { this.onDestroy(); } - /** - * @param {string} property - * @param {any} previousValue - * @param {any} currentValue - */ - attributeChangedCallback(property, previousValue, currentValue) { + attributeChangedCallback(property, previousValue, currentValue) { const camelCaps = this.#getCamelCaps(property); if (previousValue !== currentValue) { this[property] = currentValue === "" || currentValue; this[camelCaps] = this[property]; // remove on v2 - this.props[camelCaps] = this[property]; + this.props[camelCaps] = { + attributeChanged: true, + value: this[property], + } this.render(); this.onChanges({ property, previousValue, currentValue }); } } - - /** - * Converts a kebab-cased string into camelCaps - * @param {string} kebab string in kebab-case - * @returns {string} - */ + #getCamelCaps(kebab) { return kebab.replace(/-./g, (x) => x[1].toUpperCase()); } - /** - * Proxy handler for observed attribute - property counterpart - * @param {(qualifiedName: string, value: string) => void} setter - * @returns - */ - #handler = (setter) => ({ - set(obj, prop, newValue) { + #typeMap = {} + #handler = (setter, typeMap) => ({ + set(obj, prop, value) { + const attributeChanged = value?.attributeChanged ?? false; + let newValue = attributeChanged ? value.value : value; const oldValue = obj[prop]; + + console.log(">>>", newValue, oldValue); - obj[prop] = newValue; + if (!(prop in typeMap)) { + typeMap[prop] = typeof newValue; + } - /** - * 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() - ); + obj[prop] = restoreType(newValue, typeMap[prop]) - if (oldValue != newValue) { + if (attributeChanged && !oldValue != newValue) { const kebab = getKebab(prop); 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; }, }); - /** - * Initialize the `props` proxy object - */ #initializeProps() { if (!this.#props) { 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; \ No newline at end of file +export default WebComponent; diff --git a/src/attach-effect.js b/src/attach-effect.js new file mode 100644 index 0000000..330212a --- /dev/null +++ b/src/attach-effect.js @@ -0,0 +1,6 @@ +export function attachEffect(proxy, prop, callback) { + proxy[prop] = { + attach: 'effect', + callback + } +} \ No newline at end of file