UNPKG

@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
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 };