Skip to content

Commit

Permalink
(feat) simple renderDOM implementation
Browse files Browse the repository at this point in the history
Signed-off-by: Muthu Kumar <[email protected]>
  • Loading branch information
MKRhere committed Jun 23, 2021
1 parent 6101935 commit ac2ea83
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 2 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
browser-test/test.browser.js
14 changes: 14 additions & 0 deletions browser-test/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Hyperactive!</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>

<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script type="application/javascript" src="/test.browser.js"></script>
</body>
</html>
51 changes: 49 additions & 2 deletions src/render.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { Nodeish, HTMLNode } from "./Node.ts";
import { isFalsy, escapeHTML } from "./util.ts";
///<reference path="https://raw.githubusercontent.com/denoland/deno/main/cli/dts/lib.deno.ns.d.ts" />
///<reference path="https://raw.githubusercontent.com/microsoft/TypeScript/main/lib/lib.dom.d.ts" />

import { Node, Nodeish, HTMLNode } from "./Node.ts";
import { Falsy, isFalsy, escapeHTML, guessEnv } from "./util.ts";

export function renderHTML(node: Nodeish) {
if (isFalsy(node)) return "";
Expand All @@ -21,3 +24,47 @@ export function renderHTML(node: Nodeish) {

return stringified;
}

type NodeishtoDOM<N extends Nodeish> = N extends Falsy
? ""
: N extends string
? string
: N extends HTMLNode
? { innerHTML: string }
: HTMLElement;

const toDOM = function toDOM<N extends Nodeish>(node: N) {
if (isFalsy(node)) return "";
if (typeof node === "string") return escapeHTML(node);
if (node instanceof HTMLNode) return { innerHTML: node.htmlString };

const el = document.createElement(node.tag);

for (const attr in node.attrs) {
el.setAttribute(attr, node.attrs[attr]);
}

for (const child of node.children) {
const childNode = toDOM(child);
if (typeof childNode !== "string" && "innerHTML" in childNode)
el.insertAdjacentHTML("beforeend", childNode.innerHTML);
else el.append(childNode);
}

return el;
} as <N extends Nodeish>(node: N) => NodeishtoDOM<N>;

export function renderDOM<
HyNode extends Node | string,
RootNode extends HTMLElement,
>(rootNode: RootNode, hyNode: HyNode) {
const env = guessEnv();
if (env !== "browser")
throw new Error(
`renderDOM is meant to be used in the browser.` +
` Found: '${env || "unknown"}'`,
);

const domNode = toDOM(hyNode);
return rootNode.append(domNode);
}
9 changes: 9 additions & 0 deletions src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,12 @@ export type Falsy = false | "" | 0 | 0n | undefined | null;
export const Falsy = new Set([false, "", 0, 0n, undefined, null]);
// deno-lint-ignore no-explicit-any
export const isFalsy = (n: any): n is Falsy => Falsy.has(n);

export const guessEnv = () => {
if (typeof window === "undefined") {
// @ts-ignore process is a node global API
if (typeof process === "undefined") return "node";
else return undefined;
} else if (typeof window.Deno !== "undefined") return "deno";
else return "browser";
};
11 changes: 11 additions & 0 deletions test.browser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
///<reference path="https://raw.githubusercontent.com/denoland/deno/main/cli/dts/lib.deno.ns.d.ts" />
///<reference path="https://raw.githubusercontent.com/microsoft/TypeScript/main/lib/lib.dom.d.ts" />

import { elements, renderDOM } from "./mod.ts";

const { div, p } = elements;

renderDOM(
document.getElementById("root")!,
div({ class: "container" }, p("Hello world")),
);

0 comments on commit ac2ea83

Please sign in to comment.