UNPKG

react-arborist

Version:
210 lines (171 loc) 4.17 kB
import React from "react"; import { TreeApi } from "./tree-api"; import { IdObj } from "../types/utils"; import { ROOT_ID } from "../data/create-root"; type Params<T> = { id: string; data: T; level: number; children: NodeApi<T>[] | null; parent: NodeApi<T> | null; isDraggable: boolean; rowIndex: number | null; tree: TreeApi<T>; }; export class NodeApi<T = any> { tree: TreeApi<T>; id: string; data: T; level: number; children: NodeApi<T>[] | null; parent: NodeApi<T> | null; isDraggable: boolean; rowIndex: number | null; constructor(params: Params<T>) { this.tree = params.tree; this.id = params.id; this.data = params.data; this.level = params.level; this.children = params.children; this.parent = params.parent; this.isDraggable = params.isDraggable; this.rowIndex = params.rowIndex; } get isRoot() { return this.id === ROOT_ID; } get isLeaf() { return !Array.isArray(this.children); } get isInternal() { return !this.isLeaf; } get isOpen() { return this.isLeaf ? false : this.tree.isOpen(this.id); } get isClosed() { return this.isLeaf ? false : !this.tree.isOpen(this.id); } get isEditable() { return this.tree.isEditable(this.data); } get isEditing() { return this.tree.editingId === this.id; } get isSelected() { return this.tree.isSelected(this.id); } get isOnlySelection() { return this.isSelected && this.tree.hasOneSelection; } get isSelectedStart() { return this.isSelected && !this.prev?.isSelected; } get isSelectedEnd() { return this.isSelected && !this.next?.isSelected; } get isFocused() { return this.tree.isFocused(this.id); } get isDragging() { return this.tree.isDragging(this.id); } get willReceiveDrop() { return this.tree.willReceiveDrop(this.id); } get state() { return { isClosed: this.isClosed, isDragging: this.isDragging, isEditing: this.isEditing, isFocused: this.isFocused, isInternal: this.isInternal, isLeaf: this.isLeaf, isOpen: this.isOpen, isSelected: this.isSelected, isSelectedEnd: this.isSelectedEnd, isSelectedStart: this.isSelectedStart, willReceiveDrop: this.willReceiveDrop, }; } get childIndex() { if (this.parent && this.parent.children) { return this.parent.children.findIndex((child) => child.id === this.id); } else { return -1; } } get next(): NodeApi<T> | null { if (this.rowIndex === null) return null; return this.tree.at(this.rowIndex + 1); } get prev(): NodeApi<T> | null { if (this.rowIndex === null) return null; return this.tree.at(this.rowIndex - 1); } get nextSibling(): NodeApi<T> | null { const i = this.childIndex; return this.parent?.children![i + 1] ?? null; } isAncestorOf(node: NodeApi<T> | null) { if (!node) return false; let ancestor: NodeApi<T> | null = node; while (ancestor) { if (ancestor.id === this.id) return true; ancestor = ancestor.parent; } return false; } select() { this.tree.select(this); } deselect() { this.tree.deselect(this); } selectMulti() { this.tree.selectMulti(this); } selectContiguous() { this.tree.selectContiguous(this); } activate() { this.tree.activate(this); } focus() { this.tree.focus(this); } toggle() { this.tree.toggle(this); } open() { this.tree.open(this); } openParents() { this.tree.openParents(this); } close() { this.tree.close(this); } submit(value: string) { this.tree.submit(this, value); } reset() { this.tree.reset(); } clone() { return new NodeApi<T>({ ...this }); } edit() { return this.tree.edit(this); } handleClick = (e: React.MouseEvent) => { if (e.metaKey && !this.tree.props.disableMultiSelection) { this.isSelected ? this.deselect() : this.selectMulti(); } else if (e.shiftKey && !this.tree.props.disableMultiSelection) { this.selectContiguous(); } else { this.select(); this.activate(); } }; }