1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import { h as h2 } from "https://esm.town/v/tmcw/h";
export function h(tagName: string, attrsPlus?: any, ...children: any[]) {
if (!attrsPlus) attrsPlus = {};
if (attrsPlus.isEl || typeof attrsPlus === "string")
return h2(tagName, {}, attrsPlus, ...children);
if (tagName.includes("."))
return h2(
tagName.split(".")[0],
{ ...attrsPlus, class: tagName.split(".").slice(1).join(" ") },
...children
);
// This version supports our special attrs like .class and $style
// Also supports making style/attrs null or undefined to skip them. For ease of definition
const camelToKebab = (a: string) =>
a
.split("")
.map((x) => (x === x.toUpperCase() ? "-" + x.toLowerCase() : x))
.join("");
const text2Html = (text: string) =>
text
.replace(/&/g, "&")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;");
let innerHtml = children
.map((x) => (typeof x === "string" ? x : x.html))
.join("");
const attrsToEmit = Object.entries(attrsPlus).reduce((acc: any, [k, v]) => {
if (k.startsWith("on") && typeof v === "function") return acc; // Skip events
if (v === null || v === undefined) return acc; // Skip null/undefined
if (typeof v === "function") v = v(); // Allow dynamic stuff (continue to rest of function)
if (k === "innerHTML") innerHtml = String(v);
else if (k === "innerText") innerHtml = text2Html(String(v));
else if (k[0] === "." && v)
acc.class = ((acc.class || "") + " " + k.slice(1)).trim();
else if (k[0] === "$" && v !== null && v !== undefined)
acc.style =
`${camelToKebab(k.slice(1))}: ${v}` +
(acc.style ? "; " + acc.style : "");
// TODO should preserve order instead of backwards
else acc[k] = v;
return acc;
}, {});
const needsEnding =
!"base br col hr img input link meta param command keygen source"
.split(" ")
.includes(tagName);
const attrsHtml = Object.entries(attrsToEmit)
.map(([k, v]) => `${k}=${JSON.stringify(v)}`)
.join(" ");
return {
isEl: true,
html: [
"<",
tagName,
attrsHtml ? " " + attrsHtml : "",
">",
innerHtml,
needsEnding ? `</${tagName}>` : "",
].join(""),
};
}