@1771technologies/lytenyte-pro
Version:
Blazingly fast headless React data grid with 100s of features.
60 lines (59 loc) • 2.24 kB
JavaScript
import { useMemo } from "react";
import { isObject } from "../utils/is-object.js";
const defaultIdFn = (path) => path.join("-->");
const rowValueFnDefault = (x) => {
if (!isObject(x))
return null;
const entries = Object.entries(x).filter((v) => !isObject(v[1]));
return Object.fromEntries(entries);
};
const rowChildrenFnDefault = (x) => {
if (!isObject(x))
return [];
return Object.entries(x).filter((x) => isObject(x[1]));
};
export function useTree({ data, filter, idFn = defaultIdFn, rowValueFn = rowValueFnDefault, rowChildrenFn = rowChildrenFnDefault, rowRootFn = Object.entries, }) {
const rowTree = useMemo(() => {
const root = {
kind: "root",
children: new Map(),
rowIdToNode: new Map(),
data,
};
const groupKeys = (parent, path, row, parentObj) => {
const value = rowValueFn(row, parentObj, path.at(-1));
const entries = rowChildrenFn(row, parentObj, path.at(-1));
if (filter && !filter(value))
return;
const expandable = entries.some((x) => isObject(x[1]));
const node = {
kind: "parent",
children: new Map(),
parent,
path,
data: row,
key: path.at(-1),
row: {
kind: "branch",
depth: path.length - 1,
expandable,
expanded: false,
key: path.at(-1),
last: !expandable,
id: idFn(path, value),
data: value,
parentId: parent.kind === "root" ? null : parent.row.id,
},
};
parent.children.set(path.at(-1), node);
root.rowIdToNode.set(node.row.id, node);
entries.forEach((x) => groupKeys(node, [...path, x[0]], x[1], row));
};
const rootRows = rowRootFn(data);
for (const [path, row] of rootRows) {
groupKeys(root, [path], row, data);
}
return root;
}, [data, filter, idFn, rowChildrenFn, rowRootFn, rowValueFn]);
return rowTree;
}