/** @jsx dom */
/*
Article:

https://dev.to/merri/building-a-jsx-dom-library-part-1-3ga6

Code is split to two parts:

1. Library
2. Application
*/

// --- Library ---

const propsStore = new WeakMap()

function updateProps(element) {
    const props = propsStore.get(element)
    Object.entries(props).forEach(([key, value]) => {
        if (typeof value === 'function') {
            if (key.slice(0, 2) === 'on') {
                if (element[key] !== value) {
                    console.log('Set event listener', element, key, value)
                    element[key] = value
                }
                return
            }
            value = value.call(element, props)
        }
        if (element[key] !== value) {
            console.log('Set DOM property', element, key, value)
            element[key] = value
        }
    })
}

function render(element) {
    if (!propsStore.has(element)) return
    updateProps(element)
    for (let child of element.childNodes) {
        render(child)
    }
}

function dom(component, props, ...children) {
    props = { ...props }
    const isFn = typeof component === 'function'
    const element = isFn ? component(props) : document.createElement(component)
    if (!isFn) propsStore.set(element, props)
    updateProps(element)
    return children.reduce(function(el, child) {
        if (child instanceof Node) el.appendChild(child)
        else el.appendChild(document.createTextNode(String(child)))
        return el
    }, element)
}

// --- Application ---

function Component(props) {
    function changeColor() {
        props.dark = !props.dark
        render(ref)
    }

    const ref = (
        <div style={() => `background-color: ${props.dark ? 'red' : 'wheat'}; padding: 5px;`}>
            <h1 style={() => `color: ${props.dark ? 'white' : '#333'};`}>
                Hello world!
            </h1>
            <button onclick={changeColor}>Change color</button>
        </div>
    )

    return ref
}

const App = <Component dark={false} />

document.body.appendChild(App)
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.