UNPKG

@deepdub/react-arborist

Version:
104 lines (87 loc) 2.85 kB
type SimpleData = { id: string; name: string; children?: SimpleData[] }; export class SimpleTree<T extends SimpleData> { root: SimpleNode<T>; constructor(data: T[]) { this.root = createRoot<T>(data); } get data() { return this.root.children?.map((node) => node.data) ?? []; } create(args: { parentId: string | null; index: number; data: T }) { const parent = args.parentId ? this.find(args.parentId) : this.root; if (!parent) return null; parent.addChild(args.data, args.index); } move(args: { id: string; parentId: string | null; index: number }) { const src = this.find(args.id); const parent = args.parentId ? this.find(args.parentId) : this.root; if (!src || !parent) return; parent.addChild(src.data, args.index); src.drop(); } update(args: { id: string; changes: Partial<T> }) { const node = this.find(args.id); if (node) node.update(args.changes); } drop(args: { id: string }) { const node = this.find(args.id); if (node) node.drop(); } find(id: string, node: SimpleNode<T> = this.root): SimpleNode<T> | null { if (!node) return null; if (node.id === id) return node as SimpleNode<T>; if (node.children) { for (let child of node.children) { const found = this.find(id, child); if (found) return found; } return null; } return null; } } function createRoot<T extends SimpleData>(data: T[]) { const root = new SimpleNode<T>({ id: "ROOT" } as T, null); root.children = data.map((d) => createNode(d as T, root)); return root; } function createNode<T extends SimpleData>(data: T, parent: SimpleNode<T>) { const node = new SimpleNode<T>(data, parent); if (data.children) node.children = data.children.map((d) => createNode<T>(d as T, node)); return node; } class SimpleNode<T extends SimpleData> { id: string; children?: SimpleNode<T>[]; constructor(public data: T, public parent: SimpleNode<T> | null) { this.id = data.id; } hasParent(): this is this & { parent: SimpleNode<T> } { return !!this.parent; } get childIndex(): number { return this.hasParent() ? this.parent.children!.indexOf(this) : -1; } addChild(data: T, index: number) { const node = createNode(data, this); this.children = this.children ?? []; this.children.splice(index, 0, node); this.data.children = this.data.children ?? []; this.data.children.splice(index, 0, data); } removeChild(index: number) { this.children?.splice(index, 1); this.data.children?.splice(index, 1); } update(changes: Partial<T>) { if (this.hasParent()) { const i = this.childIndex; this.parent.addChild({ ...this.data, ...changes }, i); this.drop(); } } drop() { if (this.hasParent()) this.parent.removeChild(this.childIndex); } }