/** * Tiny DOM helpers — enough structure to avoid a framework without the * ergonomics falling apart. * * el('div', { class: 'card', onclick: fn }, 'text', childNode) */ export function el(tag, props = {}, ...children) { const node = document.createElement(tag); for (const [key, value] of Object.entries(props || {})) { if (value == null || value === false) continue; if (key === 'class') node.className = value; else if (key === 'dataset') Object.assign(node.dataset, value); else if (key === 'html') node.innerHTML = value; else if (key.startsWith('on') && typeof value === 'function') { node.addEventListener(key.slice(2).toLowerCase(), value); } else if (key in node) { try { node[key] = value; } catch { node.setAttribute(key, value); } } else { node.setAttribute(key, value); } } append(node, children); return node; } export function append(node, children) { for (const child of children.flat(Infinity)) { if (child == null || child === false) continue; node.append(child.nodeType ? child : document.createTextNode(String(child))); } } export function clear(node) { node.replaceChildren(); return node; } /** Run a cleanup fn when the view node is torn down by the router. */ export function onTeardown(viewNode, fn) { viewNode.addEventListener('view:teardown', fn, { once: true }); }