/** * Copyright (c) 2021 OpenLens Authors * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ import "./tree-view.scss"; import React, { useEffect, useRef } from "react"; import { Icon } from "../icon"; import TreeView from "@material-ui/lab/TreeView"; import TreeItem from "@material-ui/lab/TreeItem"; import { cssNames } from "../../utils"; import _ from "lodash"; import getDeepDash from "deepdash"; const deepDash = getDeepDash(_); export interface NavigationTree { id: string; parentId: string; name: string; selected?: boolean; children?: NavigationTree[]; } interface Props { data: NavigationTree[] } function scrollToItem(id: string) { document.getElementById(id)?.scrollIntoView(); } function getSelectedNode(data: NavigationTree[]) { return deepDash.findDeep(data, (value, key) => key === "selected" && value === true)?.parent; } export function RecursiveTreeView({ data }: Props) { const [expanded, setExpanded] = React.useState([]); const prevData = useRef(data); const handleToggle = (event: React.ChangeEvent<{}>, nodeIds: string[]) => { setExpanded(nodeIds); }; const expandTopLevelNodes = () => { setExpanded(data.map(node => node.id)); }; const expandParentNode = () => { const node = getSelectedNode(data) as any as NavigationTree; const id = node?.parentId; if (id && !expanded.includes(id)) { setExpanded([...expanded, id]); } }; const onLabelClick = (event: React.MouseEvent, nodeId: string) => { event.preventDefault(); scrollToItem(nodeId); }; const renderTree = (nodes: NavigationTree[]) => { return nodes.map(node => ( onLabelClick(event, node.id)} className={cssNames({ selected: node.selected })} title={node.name} > {Array.isArray(node.children) ? node.children.map((node) => renderTree([node])) : null} )); }; useEffect(() => { if (!prevData.current.length) { expandTopLevelNodes(); } else { expandParentNode(); } prevData.current = data; }, [data]); if (!data.length) { return null; } return ( } defaultExpandIcon={} > {renderTree(data)} ); }