import { getDocument, isString } from "@daybrush/utils"; import { diff } from "@egjs/list-differ"; import { Provider } from "./base/Provider"; import { findDOMNode } from "./externalUtils"; import { createProvider } from "./renderProviders"; import { CompatElement } from "./types"; import { fillKeys, findContainerNode, removeNode } from "./utils"; export class ContainerProvider extends Provider { public typ = "container"; constructor(base: Element, depth = 0) { super("container", depth, "container", 0, null); this.b = base; } public r() { return true; } public un() { return; } } export class TextProvider extends Provider { public typ = "text"; public r(hooks: Function[]) { const self = this; const isMount = !self.b; if (isMount) { const containerNode = findContainerNode(self.c); const b = self._hyd?.splice(0, 1)[0]; self.b = b || getDocument(containerNode).createTextNode(self.t.replace("text_", "")); } hooks.push(() => { if (isMount) { self.md(); } else { self.ud(); } }); return true; } public un() { removeNode(this.b); } } export function diffProviders( containerProvider: Provider, providers: Provider[], children: Array, ) { const childrenKeys = children.map(p => isString(p) ? null : p.key); const keys1 = fillKeys(providers.map(p => p.k)); const keys2 = fillKeys(childrenKeys); const result = diff(keys1, keys2, key => key); result.removed.forEach(index => { providers.splice(index, 1)[0].un(); }); result.ordered.forEach(([from, to]) => { const childrenProvider = providers.splice(from, 1)[0]; providers.splice(to, 0, childrenProvider); const el = findDOMNode(childrenProvider.b); const next = findDOMNode(providers[to + 1] && providers[to + 1].b); if (el) { el.parentNode!.insertBefore(el, next); } }); result.added.forEach(index => { providers.splice(index, 0, createProvider(children[index], childrenKeys[index], index, containerProvider)); }); const changed = result.maintained.filter(([_, to]) => { const el = children[to]; const childProvider = providers[to]; const type = isString(el) ? `text_${el}` : el.type; if (type !== childProvider.t) { childProvider.un(); providers.splice(to, 1, createProvider(el, childrenKeys[to], to, containerProvider)); return true; } childProvider.i = to; return false; }); return [ ...result.added, ...changed.map(([_, to]) => to), ]; }