Reactive Web Components 1kb - Library.js

by patrickml

HTML

<!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>

JavaScript

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,...