import { useMemo, useState } from 'preact/hooks' export type TreeViewGroupRenderer = (props: { name: string, open: boolean, onClick: () => void }) => JSX.Element export type TreeViewLeafRenderer = (props: { entry: E }) => JSX.Element interface Props { entries: E[], split: (entry: E) => string[], group: TreeViewGroupRenderer, leaf: TreeViewLeafRenderer, level?: number, } export function TreeView({ entries, split, group: Group, leaf: Leaf, level = 0 }: Props) { const roots = useMemo(() => { const groups: Record = {} for (const entry of entries) { const path = split(entry) if (path[level + 1] !== undefined) { ;(groups[path[level]] ??= []).push(entry) } } return groups }, [entries, split, level]) const leaves = useMemo(() => { return entries.filter(e => split(e).length === level + 1) }, [entries, split, level]) const [hidden, setHidden] = useState(new Set()) const toggle = (root: string) => { if (hidden.has(root)) { hidden.delete(root) } else { hidden.add(root) } setHidden(new Set(hidden)) } return
{Object.entries(roots).map(([r, childs]) => <> toggle(r)} /> {!hidden.has(r) && entries={childs} split={split} group={Group} leaf={Leaf} level={level + 1} />} )} {leaves.map(e => )}
}