// Tiny DOM helpers: h("div.card", {onclick}, child, "text"). type Child = Node | string | number | null | undefined | false; type Attrs = Record; export function h(spec: K | `${K}.${string}` | `${K}#${string}`, attrs?: Attrs | Child, ...children: Child[]): HTMLElementTagNameMap[K] { const [tagAndId, ...classes] = spec.split("."); const [tag, id] = tagAndId.split("#"); const el = document.createElement(tag) as HTMLElementTagNameMap[K]; if (id) el.id = id; if (classes.length) el.className = classes.join(" "); if (attrs && typeof attrs === "object" && !(attrs instanceof Node)) { for (const [k, v] of Object.entries(attrs)) { if (v === undefined || v === null || v === false) continue; if (k.startsWith("on") && typeof v === "function") el.addEventListener(k.slice(2), v as EventListener); else if (k === "class") el.className += (el.className ? " " : "") + v; else if (k === "style") el.setAttribute("style", String(v)); else if (k in el && typeof v !== "string") (el as unknown as Record)[k] = v; else el.setAttribute(k, v === true ? "" : String(v)); } } else if (attrs !== undefined) { children.unshift(attrs as Child); } append(el, ...children); return el; } export function append(el: Element, ...children: Child[]): void { for (const c of children) { if (c === null || c === undefined || c === false) continue; el.appendChild(c instanceof Node ? c : document.createTextNode(String(c))); } } export function clear(el: Element): void { while (el.firstChild) el.removeChild(el.firstChild); } export function replace(el: Element, ...children: Child[]): void { clear(el); append(el, ...children); }