feat: support objects in props

This commit is contained in:
Ayo 2023-12-07 17:30:53 +01:00
parent d6755dd9e3
commit d7651b5f33
17 changed files with 59 additions and 47 deletions

View file

@ -1,5 +1,5 @@
// @ts-check // @ts-check
import WebComponent from "../../src/WebComponent.js"; import { WebComponent } from "../../src/WebComponent.js";
import { attachEffect } from "../../src/attach-effect.js"; import { attachEffect } from "../../src/attach-effect.js";
export class Counter extends WebComponent { export class Counter extends WebComponent {

View file

@ -1,5 +1,5 @@
// @ts-check // @ts-check
import WebComponent from "../../src/WebComponent.js"; import { WebComponent } from "../../src/WebComponent.js";
import { attachEffect } from "../../src/attach-effect.js"; import { attachEffect } from "../../src/attach-effect.js";
export class Decrease extends WebComponent { export class Decrease extends WebComponent {

View file

@ -1,4 +1,4 @@
import WebComponent from "../../src/WebComponent.js"; import { WebComponent } from "../../src/WebComponent.js";
export class BooleanPropTest extends WebComponent { export class BooleanPropTest extends WebComponent {
static properties = ["is-inline", "anotherone"]; static properties = ["is-inline", "anotherone"];

View file

@ -1,5 +1,5 @@
// @ts-check // @ts-check
import WebComponent from "../../src/WebComponent.js"; import { WebComponent } from "../../src/WebComponent.js";
export class Counter extends WebComponent { export class Counter extends WebComponent {
static properties = ["count"]; static properties = ["count"];

View file

@ -1,5 +1,5 @@
// @ts-check // @ts-check
import WebComponent from "../../src/WebComponent.js"; import { WebComponent } from "../../src/WebComponent.js";
export class HelloWorld extends WebComponent { export class HelloWorld extends WebComponent {
static properties = ["count", "emotion"]; static properties = ["count", "emotion"];

View file

@ -1,5 +1,5 @@
// @ts-check // @ts-check
import WebComponent from "../../src/WebComponent.js"; import { WebComponent } from "../../src/WebComponent.js";
class SimpleText extends WebComponent { class SimpleText extends WebComponent {
clickCallback() { clickCallback() {

View file

@ -10,7 +10,7 @@
} }
</style> </style>
<script type="module"> <script type="module">
import WebComponent from "https://unpkg.com/web-component-base@1.13.3/WebComponent.min.js"; import { WebComponent } from "https://unpkg.com/web-component-base@1.13.3/WebComponent.min.js";
/** /**
* @see https://ayco.io/n/web-component-base * @see https://ayco.io/n/web-component-base

View file

@ -1,5 +1,5 @@
// @ts-check // @ts-check
import WebComponent from "../../src/WebComponent.js"; import { WebComponent } from "../../src/WebComponent.js";
export class Counter extends WebComponent { export class Counter extends WebComponent {
static properties = ["count"]; static properties = ["count"];

View file

@ -1,4 +1,4 @@
import WebComponent from "../../src/WebComponent.js"; import { WebComponent } from "../../src/WebComponent.js";
export class HelloWorld extends WebComponent { export class HelloWorld extends WebComponent {
static properties = ["name"]; static properties = ["name"];

View file

@ -1,14 +1,18 @@
import WebComponent from "../../src/WebComponent.js"; import { WebComponent } from "../../src/WebComponent.js";
export class ObjectText extends WebComponent { export class ObjectText extends WebComponent {
static properties = ["object"]; static properties = ["object"];
onInit() { onInit() {
this.props.object = { this.props.object = {
hello: 'world' hello: 'world',
age: 2
}; };
} }
onChanges() {
console.log('>>> object', this.props.object)
}
get template() { get template() {
return `<textarea>${this.props.object}</textarea>`; return `<textarea>${JSON.stringify(this.props.object)}</textarea>`;
} }
} }

View file

@ -1,5 +1,5 @@
// @ts-check // @ts-check
import WebComponent from "../../src/WebComponent.js"; import { WebComponent } from "../../src/WebComponent.js";
export class Toggle extends WebComponent { export class Toggle extends WebComponent {
static properties = ["toggle"]; static properties = ["toggle"];

View file

@ -18,7 +18,7 @@
<div> <div>
Counter: <my-counter></my-counter> Counter: <my-counter></my-counter>
</div> </div>
<!-- <div> <div>
Toggle: <my-toggle></my-toggle> Toggle: <my-toggle></my-toggle>
</div> </div>
<div> <div>
@ -26,6 +26,6 @@
</div> </div>
<div> <div>
Object: <my-object /> Object: <my-object />
</div> --> </div>
</body> </body>
</html> </html>

View file

@ -1,6 +1,6 @@
{ {
"name": "web-component-base", "name": "web-component-base",
"version": "2.0.0-beta", "version": "2.0.0-beta.1",
"description": "A zero-dependency, ~600 Bytes (minified & gzipped), JS base class for creating reactive custom elements easily", "description": "A zero-dependency, ~600 Bytes (minified & gzipped), JS base class for creating reactive custom elements easily",
"type": "module", "type": "module",
"exports": { "exports": {
@ -12,14 +12,15 @@
"types": "./WebComponent.d.ts", "types": "./WebComponent.d.ts",
"import": "./WebComponent.js" "import": "./WebComponent.js"
}, },
"./attach-effect": {
"types": "./attach-effect.d.ts",
"import": "./attach-effect.js"
},
"./WebComponent.min.js": { "./WebComponent.min.js": {
"types": "./WebComponent.d.ts", "types": "./WebComponent.d.ts",
"import": "./WebComponent.min.js" "import": "./WebComponent.min.js"
}, },
"./attach-effect": { "./package.json": "./package.json"
"types": "./attach-effect.d.ts",
"import": "./attach-effect.js"
}
}, },
"scripts": { "scripts": {
"start": "npx simple-server .", "start": "npx simple-server .",

View file

@ -3,7 +3,7 @@
<head> <head>
<title>WC Base Test</title> <title>WC Base Test</title>
<script type="module"> <script type="module">
import WebComponent from "./src/WebComponent.js"; import { WebComponent } from "./src/WebComponent.js";
class HelloWorld extends WebComponent { class HelloWorld extends WebComponent {
static properties = ["my-name"]; static properties = ["my-name"];

View file

@ -57,7 +57,7 @@
<p>The result is a reactive UI on property changes: <my-counter></my-counter></p> <p>The result is a reactive UI on property changes: <my-counter></my-counter></p>
<code-block language="js"> <code-block language="js">
<pre> <pre>
import WebComponent from &quot;https://unpkg.com/web-component-base@1.13.0/WebComponent.min.js&quot;; import { WebComponent } from &quot;https://unpkg.com/web-component-base@1.13.0/WebComponent.min.js&quot;;
export class Counter extends WebComponent { export class Counter extends WebComponent {
static properties = [&quot;count&quot;]; static properties = [&quot;count&quot;];

View file

@ -93,7 +93,7 @@ export class WebComponent extends HTMLElement {
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];
this.#handleUpdateProp(camelCaps, this[property]); this.#handleUpdateProp(camelCaps, this[property]);
@ -102,10 +102,9 @@ export class WebComponent extends HTMLElement {
} }
} }
#handleUpdateProp(key, value) { #handleUpdateProp(key, stringifiedValue) {
const restored = this.#restoreType(value, this.#typeMap[key]); const restored = this.#deserialize(stringifiedValue, this.#typeMap[key]);
if (restored !== this.props[key]) this.props[key] = restored;
if (restored !== this.props[key]) this.props[key] = value;
} }
#getCamelCaps(kebab) { #getCamelCaps(kebab) {
@ -113,19 +112,6 @@ export class WebComponent extends HTMLElement {
} }
#typeMap = {}; #typeMap = {};
#restoreType = (value, type) => {
switch (type) {
case "string":
return value;
case "number":
case "boolean":
return JSON.parse(value);
default:
return value;
}
};
#effectsMap = {}; #effectsMap = {};
#handler(setter, meta) { #handler(setter, meta) {
@ -151,19 +137,19 @@ export class WebComponent extends HTMLElement {
effectsMap[prop] = []; effectsMap[prop] = [];
} }
effectsMap[prop].push(value.callback); effectsMap[prop].push(value.callback);
console.log('>>> ', Object.getPrototypeOf(obj[prop]).prop)
} else if (oldValue !== value) { } else if (oldValue !== value) {
obj[prop] = value; obj[prop] = value;
effectsMap[prop]?.forEach((f) => f(value)); effectsMap[prop]?.forEach((f) => f(value));
const kebab = getKebab(prop); const kebab = getKebab(prop);
setter(kebab, value);
setter(kebab, meta.#serialize(value));
} }
return true; return true;
}, },
get(obj, prop) { get(obj, prop) {
// TODO: handle non-objects // TODO: handle non-objects
if(obj[prop] !== null && obj[prop] !== undefined) { if (obj[prop] !== null && obj[prop] !== undefined) {
Object.getPrototypeOf(obj[prop]).proxy = meta.#props; Object.getPrototypeOf(obj[prop]).proxy = meta.#props;
Object.getPrototypeOf(obj[prop]).prop = prop; Object.getPrototypeOf(obj[prop]).prop = prop;
} }
@ -172,6 +158,29 @@ export class WebComponent extends HTMLElement {
}; };
} }
#deserialize(value, type){
switch (type) {
case 'number':
case 'boolean':
case 'object':
case 'undefined':
return JSON.parse(value);
default:
return value;
}
};
#serialize(value) {
switch(typeof value) {
case 'number':
case 'boolean':
case 'object':
case 'undefined':
return JSON.stringify(value);
default: return value;
}
}
#initializeProps() { #initializeProps() {
if (!this.#props) { if (!this.#props) {
this.#props = new Proxy( this.#props = new Proxy(
@ -181,5 +190,3 @@ export class WebComponent extends HTMLElement {
} }
} }
} }
export default WebComponent;

View file

@ -1,2 +1,2 @@
export {attachEffect} from './attach-effect.js'; export { attachEffect } from "./attach-effect.js";
export {default as WebComponent} from './WebComponent.js'; export { WebComponent } from "./WebComponent.js";