Last active
July 10, 2019 19:31
-
-
Save patrickml/d41482238f354b26e63a8e0359f85465 to your computer and use it in GitHub Desktop.
Reactive Web Component Demo Library 200bytes (gz) -- https://jsfiddle.net/patrickml/6h9uz4g3/2/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const ProxyStore = (values={}, options={}) => new Proxy( | |
{ | |
__registry: {}, | |
subscribe: function(key, fn) { | |
this.__registry[key] = [...(this.__registry[key] || []), fn]; | |
}, | |
unsubscribe: function(key, fn) { | |
this.__registry[key] = this.__registry[key].filter(fn); | |
}, | |
...values, | |
}, | |
{ | |
get: function(target, name, receiver) { | |
return Reflect.get(target, name, receiver); | |
}, | |
set: function(target, name, value, receiver) { | |
Reflect.set(target, name, value, receiver); | |
target.__registry[name].forEach(fn => fn()); | |
return true; | |
}, | |
...options, | |
} | |
); | |
const store = ProxyStore({ users: [] }); | |
const NodeOf = (type) => ( | |
class Node extends type { | |
constructor() { super(); } | |
componentDidRender() {} | |
componentDidMount() {} | |
componentDidUnmount() {} | |
connectedCallback() { | |
this.componentDidMount(); | |
this.renderNode(); | |
} | |
disconnectedCallback() { | |
this.componentDidUnmount(); | |
} | |
renderNode() { | |
let html = this.render(); | |
if (Array.isArray(html)) { | |
html = html.join(''); | |
} | |
if (this._shadow) this._shadow.innerHTML = html; | |
else this.innerHTML = html; | |
this.componentDidRender(); | |
} | |
} | |
) | |
const Node = NodeOf(HTMLElement); | |
class ProxyNode extends Node { | |
set data(data) { | |
this._data = data; | |
this.renderNode(); | |
} | |
get data() { | |
return this._data; | |
} | |
} | |
class ProxyProvider extends HTMLElement { | |
get subscribe() { return this.hasAttribute('subscribe'); } | |
get storeKey() { return this.getAttribute('store'); } | |
get data() { return store[this.storeKey]; } | |
set data(value) { return store[this.storeKey] = value; } | |
_subscribe() { | |
store.subscribe(this.storeKey, this.propagateChanges.bind(this)); | |
} | |
_unsubscribe() { | |
store.unsubscribe(this.storeKey, this.propagateChanges.bind(this)); | |
} | |
connectedCallback() { | |
if(this.subscribe) this._subscribe(); | |
this.propagateChanges(); | |
} | |
disconnectedCallback() { | |
if(this.subscribe) this._unsubscribe(); | |
} | |
append(item) { | |
this.data = [...this.data, item] | |
} | |
merge(item) { | |
this.data = {...this.data, item} | |
} | |
set(item) { | |
this.data = item | |
} | |
propagateChanges() { | |
for (var child of this.children) { | |
child.data = this.data; | |
child[this.storeKey] = { | |
append: this.append.bind(this), | |
merge: this.merge.bind(this), | |
set: this.set.bind(this), | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class ListItem extends Node { | |
get text() { return this.getAttribute('text'); } | |
render() { | |
return `<li>${this.text}</li>`; | |
} | |
} | |
class List extends ProxyNode { | |
render() { | |
if (!this.data) { | |
return ''; | |
} | |
return this.data.map((user) => ( | |
`<list-item text="${user.name} is age ${user.age}"></list-item>` | |
)); | |
} | |
} | |
class AddUserButton extends NodeOf(HTMLButtonElement) { | |
createUser() { | |
this.users.append({ | |
name: `Random User`, | |
age: Math.round(Math.random() * 100), | |
}); | |
} | |
componentDidMount() { | |
this.addEventListener('click', this.createUser.bind(this)); | |
} | |
render() { | |
return `Add User`; | |
} | |
} | |
customElements.define('list-item', ListItem); | |
customElements.define('add-user-button', AddUserButton, { extends: 'button' }); | |
customElements.define('user-list', List); | |
customElements.define('proxy-provider', ProxyProvider); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<body> | |
<h1>Testing</h1> | |
<proxy-provider store="users"> | |
<button is="add-user-button"></button> | |
</proxy-provider> | |
<proxy-provider store="users" subscribe> | |
<user-list></user-list> | |
</proxy-provider> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment