@thi.ng/rdom
Version:
Lightweight, reactive, VDOM-less UI/DOM components with async lifecycle and @thi.ng/hiccup compatible
80 lines (79 loc) • 2.7 kB
JavaScript
import { isArray } from "@thi.ng/checks/is-array";
import { isAsyncIterable } from "@thi.ng/checks/is-async-iterable";
import { isFunction } from "@thi.ng/checks/is-function";
import { isPlainObject } from "@thi.ng/checks/is-plain-object";
import { isSubscribable } from "@thi.ng/rstream/checks";
import { $async, $asyncA } from "./async.js";
import { isComponent, isElement } from "./checks.js";
import { $el, $remove, $tree } from "./dom.js";
import { $SubA, $sub } from "./sub.js";
import { $wrapEl, $wrapText } from "./wrap.js";
const $compile = (tree) => isArray(tree) ? isFunction(tree[0]) ? $compile(tree[0].apply(null, tree.slice(1))) : __isComplexComponent(tree) ? __complexComponent(tree) : __basicComponent(tree) : isComponent(tree) ? tree : isSubscribable(tree) ? $sub(tree, "span") : isAsyncIterable(tree) ? $async(tree, "span") : isFunction(tree) ? $compile(tree()) : tree instanceof Element ? $wrapEl(tree) : $wrapText("span", null, tree);
const __walk = (f, x, path = []) => {
if (isPlainObject(x)) {
for (const k in x) {
__walk(f, x[k], [...path, k]);
}
}
f(x, path);
};
const __isComplexComponent = (x) => {
if (isPlainObject(x)) {
for (const k in x) {
if (__isComplexComponent(x[k])) return true;
}
} else if (isArray(x)) {
for (let i = 0, n = x.length; i < n; i++) {
if (__isComplexComponent(x[i])) return true;
}
}
return isSubscribable(x) || isAsyncIterable(x) || isComponent(x) || isFunction(x) || isElement(x);
};
const __complexComponent = (tree) => ({
async mount(parent, index = -1) {
this.subs = [];
const attribs = { ...tree[1] };
__walk((x, path) => {
if (isSubscribable(x)) {
this.subs.push(x.subscribe(new $SubA(this, path)));
} else if (isAsyncIterable(x)) {
$asyncA(x, this, path);
if (path.length === 1) delete attribs[path[0]];
}
}, attribs);
this.children = [];
this.el = $el(tree[0], attribs, null, parent, index);
for (let i = 2; i < tree.length; i++) {
const child = $compile(tree[i]);
child.mount(this.el, i - 2);
this.children.push(child);
}
return this.el;
},
async unmount() {
if (this.children) {
for (let c of this.children) {
await c.unmount();
}
}
this.subs?.forEach((s) => s.unsubscribe());
this.el && $remove(this.el);
this.el = this.children = this.subs = void 0;
},
update() {
}
});
const __basicComponent = (tree) => ({
async mount(parent, index = -1) {
return this.el = await $tree(tree, parent, index);
},
async unmount() {
this.el && $remove(this.el);
this.el = void 0;
},
update() {
}
});
export {
$compile
};