const liveData = {}
const dom = new Proxy(liveData, {
get(o, key) {
if (o[key]) {
return o[key]
} else {
const fn = node.bind(null, key)
return fn
}
}
});
const tags = {}
const isTag = tag => {
if (tags[tag] != null) {
// already calculated
return tags[tag]
}
const result = !/Unknown/.test(document.createElement(tag) + '')
tags[tag] = result
return result
}
const click = new WeakMap()
function pointerUp(e) {
const curr = e.target;
if (!curr) return
const action = click.get(curr)
if (action) action(e)
// bubble to parent
if (curr?.parentNode?.tagName != 'BODY') {
pointerUp({ target: e.target.parentNode })
}
}
document.addEventListener('pointerup', e => {
pointerUp(e)
})
function attrs(el, props) {
const keys = Reflect.ownKeys(props)
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const val = props[key]
if (typeof val != 'function') {
el.setAttribute(key, val)
} else if (key === 'click') {
click.set(el, val)
}
}
}
const textarea = document.createElement('textarea')
function node(type, ...args) {
let el;
const namedEl = isTag(type);
if (namedEl) {
el = document.createElement(type)
} else {
el = document.createElement('div')
el.className = type
}
const leng = args.length
for (let i = 0; i < leng; i++) {
const arg = args[i]
if ((i === 1 || leng === 1)
&& typeof arg === 'string') {
if (arg.includes('&')) {
textarea.innerHTML = arg
el.innerText = textarea.innerHTML
} else {
el.innerText = arg
}
} else if (i === 0 && typeof arg === 'string') {
el.classList.add(arg)
} else {
if (typeof arg === 'object') {
if (arg.el) {
el.appendChild(arg.el)
} else {
attrs(el, arg)
}
}
}
}
document.body.appendChild(el)
return { el }
}
const { header, h1, h2, style, div, button } = dom
style(`
body, html {
font-family: sans-serif;
}
.edit-me {
margin: 1em;
outline: 1px solid red;
padding: .5em;
}
`)
header(
h1('Dom Thoughts'),
h2('sub-header', 'Can\'t help playing with this',
{ style: 'font-style: italic;' }
)
)
div('main',
button('hello', 'Hello', { click: () => alert('hello') }),
div('edit-me', 'Edit Me', { contentEditable: true })
)