UNPKG

@thi.ng/rdom

Version:

Lightweight, reactive, VDOM-less UI/DOM components with async lifecycle and @thi.ng/hiccup compatible

114 lines (113 loc) 3.18 kB
import { $compile } from "./compile.js"; import { Component } from "./component.js"; import { __nextID } from "./idgen.js"; import { $subWithID } from "./sub.js"; const $klist = (src, tag, attribs, childCtor, keyFn) => $subWithID( src, new KList(tag, attribs, childCtor, keyFn), __nextID("klist", src) ); class KList extends Component { constructor(tag, attribs, ctor, keyFn = (_, i) => i) { super(); this.tag = tag; this.attribs = attribs; this.ctor = ctor; this.keyFn = keyFn; } items = []; cache; async mount(parent, index, state) { this.items = []; this.cache = /* @__PURE__ */ new Map(); this.el = this.$el(this.tag, this.attribs, null, parent, index); this.update(state); return this.el; } async unmount() { this.items.forEach((c) => c.v.unmount()); this.$remove(); this.el = void 0; this.items = void 0; this.cache = void 0; } async update(curr) { if (!curr) return; const { keyFn, items, ctor, cache, el: parent } = this; const currItems = []; const currCache = /* @__PURE__ */ new Map(); const offsets = /* @__PURE__ */ new Map(); const deltas = /* @__PURE__ */ new Map(); let numPrev = items.length; let numCurr = curr.length; let i; for (i = numPrev; i-- > 0; ) { offsets.set(items[i].k, i); } for (i = numCurr; i-- > 0; ) { const val = curr[i]; const key = keyFn(val, i); let item = cache.get(key); item ? item.v.update(val) : item = { k: key, v: $compile(ctor(val)) }; currCache.set(key, currItems[i] = item); const off = offsets.get(key); off != void 0 && deltas.set(key, Math.abs(i - off)); } const willMove = /* @__PURE__ */ new Set(); const didMove = /* @__PURE__ */ new Set(); let next; const insert = async (item) => { if (cache.has(item.k)) { this.$moveTo(parent, item.v.el, next); next = item.v.el; } else { cache.set(item.k, item); next = await item.v.mount(parent, next); } numCurr--; }; while (numPrev && numCurr) { const prevItem = items[numPrev - 1]; const prevKey = prevItem.k; const currItem = currItems[numCurr - 1]; const currKey = currItem.k; if (currItem === prevItem) { next = currItem.v.el; numPrev--; numCurr--; } else if (!currCache.has(prevKey)) { await prevItem.v.unmount(); cache.delete(prevKey); numPrev--; } else if (!cache.has(currKey) || willMove.has(currKey)) { await insert(currItem); } else if (didMove.has(prevKey)) { numPrev--; } else if (deltas.get(currKey) > deltas.get(prevKey)) { await insert(currItem); didMove.add(currKey); } else { willMove.add(prevKey); numPrev--; } } while (numPrev--) { const item = items[numPrev]; if (!currCache.has(item.k)) { await item.v.unmount(); cache.delete(item.k); } } while (numCurr) { await insert(currItems[numCurr - 1]); } this.items = currItems; } } export { $klist, KList };