Re-work toHierarchy utility

Refactor `toHiearchy` to be more generic, performant

- Use callback to "pick" generic parent ID property instead of requiring that `pid` be hardcoded`
- Account for edge cases of an invalid parent ID
- Use Map to store node children for lookups
- Use one pass instead of removing empty nodes at the very end
- DX: use generics to type `toHierarchy`
- Make `toHierarchy` even more generic (reusable with `RecursiveList`)

Co-Authored-By: Bram <bramhavers@gmail.com>
This commit is contained in:
Eric Liu 2024-12-07 13:54:06 -08:00
commit 5f1e8de1e1
29 changed files with 414 additions and 273 deletions

View file

@ -15,7 +15,7 @@ type $RestProps = SvelteHTMLElements["ul"];
type $Props = {
/**
* Provide a nested array of nodes to render
* Provide an array of nodes to render
* @default []
*/
nodes?: Array<TreeNode>;
@ -94,11 +94,6 @@ export default class TreeView extends SvelteComponentTyped<
*/
collapseAll: () => void;
/**
* Create a nested array from a flat array
*/
toHierarchy: (flatArray: TreeNode[] & { pid?: any }[]) => TreeNode[];
/**
* Programmatically expand a subset of nodes.
* Expands all nodes if no argument is provided

View file

@ -1,2 +1 @@
export { default as TreeView } from "./TreeView.svelte";
export { toHierarchy } from "./treeview";

View file

@ -1,9 +0,0 @@
import { type TreeNode } from "./TreeView.svelte";
/**
* Create a nested array from a flat array
*/
export function toHierarchy(
flatArray: TreeNode[] & { pid?: any }[],
): TreeNode[];
export default toHierarchy;

2
types/index.d.ts vendored
View file

@ -143,7 +143,6 @@ export { default as TooltipFooter } from "./Tooltip/TooltipFooter.svelte";
export { default as TooltipDefinition } from "./TooltipDefinition/TooltipDefinition.svelte";
export { default as TooltipIcon } from "./TooltipIcon/TooltipIcon.svelte";
export { default as TreeView } from "./TreeView/TreeView.svelte";
export { default as toHierarchy } from "./TreeView/treeview";
export { default as Truncate } from "./Truncate/Truncate.svelte";
export { default as truncate } from "./Truncate/truncate";
export { default as Header } from "./UIShell/Header.svelte";
@ -167,3 +166,4 @@ export { default as SkipToContent } from "./UIShell/SkipToContent.svelte";
export { default as HeaderGlobalAction } from "./UIShell/HeaderGlobalAction.svelte";
export { default as HeaderSearch } from "./UIShell/HeaderSearch.svelte";
export { default as UnorderedList } from "./UnorderedList/UnorderedList.svelte";
export { default as toHierarchy } from "./utils/toHierarchy";

21
types/utils/toHierarchy.d.ts vendored Normal file
View file

@ -0,0 +1,21 @@
type NodeLike = {
id: string | number;
nodes?: NodeLike[];
[key: string]: any;
};
/** Create a hierarchical tree from a flat array. */
export function toHierarchy<
T extends NodeLike,
K extends keyof Omit<T, "id" | "nodes">,
>(
flatArray: T[] | readonly T[],
/**
* Function that returns the parent ID for a given node.
* @example
* toHierarchy(flatArray, (node) => node.parentId);
*/
getParentId: (node: T) => T[K] | null,
): (T & { nodes?: (T & { nodes?: T[] })[] })[];
export default toHierarchy;