1/** Tiny DOM element builder. */2type Child = Node | string | null | undefined | false;3type Attrs = Record<string, unknown> | null;45export function h<K extends keyof HTMLElementTagNameMap>(6 tag: K,7 attrs?: Attrs,8 ...children: Array<Child | Child[]>9): HTMLElementTagNameMap[K] {10 const el = document.createElement(tag);11 if (attrs) {12 for (const [key, value] of Object.entries(attrs)) {13 if (value == null || value === false) continue;14 if (key === 'class') el.className = String(value);15 else if (key === 'dataset') Object.assign(el.dataset, value as Record<string, string>);16 else if (key.startsWith('on') && typeof value === 'function') {17 el.addEventListener(key.slice(2).toLowerCase(), value as EventListener);18 } else if (key in el) {19 // Some IDL attributes are getter-only (e.g. input.list); fall back20 // to the content attribute for those.21 try {22 (el as unknown as Record<string, unknown>)[key] = value;23 } catch {24 el.setAttribute(key, String(value));25 }26 } else {27 el.setAttribute(key, String(value));28 }29 }30 }31 for (const c of children.flat()) {32 if (c == null || c === false) continue;33 el.append(typeof c === 'string' ? document.createTextNode(c) : c);34 }35 return el;36}3738export function clear(el: HTMLElement): HTMLElement {39 el.textContent = '';40 return el;41}