1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Expanding parent nodes when scrolling along child ones

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>
This commit is contained in:
Alex Andreev 2021-03-09 11:26:02 +03:00
parent d0e25e90b0
commit 09a009049f
4 changed files with 67 additions and 15 deletions

View File

@ -306,6 +306,7 @@
"concurrently": "^5.2.0",
"css-element-queries": "^1.2.3",
"css-loader": "^3.5.3",
"deepdash-es": "^5.3.5",
"dompurify": "^2.0.11",
"electron": "^9.4.0",
"electron-builder": "^22.7.0",

View File

@ -29,6 +29,7 @@ export function ScrollSpy(props: Props) {
sections.forEach(section => {
const id = section.getAttribute("id");
const parentId = section.parentElement.id;
const name = section.querySelector("h1, h2, h3, h4, h5, h6").textContent;
const selected = id === activeElementId;
@ -38,6 +39,7 @@ export function ScrollSpy(props: Props) {
children.push({
id,
parentId,
name,
selected,
children: getNavigation(section)
@ -56,6 +58,9 @@ export function ScrollSpy(props: Props) {
const observeSections = () => {
const options: IntersectionObserverInit = {
threshold: [0],
// Shrinking root area from the bottom
// Allows to fire observer event only if target scrolled up to top of the page)
// https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#creating_an_intersection_observer
rootMargin: "0px 0px -85%",
};

View File

@ -1,14 +1,15 @@
import "./tree-view.scss";
import React from "react";
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 flattenDeep from "lodash/flattenDeep";
import findDeep from "deepdash-es/findDeep";
export interface NavigationTree {
id: string;
parentId: string;
name: string;
selected?: boolean;
children?: NavigationTree[];
@ -18,14 +19,49 @@ interface Props {
data: NavigationTree[]
}
const scrollToItem = (id: string) => {
const element = document.getElementById(id);
element?.scrollIntoView();
};
const getSelectedNode = (data: NavigationTree[]) => {
return findDeep(data, (value, key) => key === "selected" && value === true)?.parent;
};
export function RecursiveTreeView({ data }: Props) {
const [expanded, setExpanded] = React.useState<string[]>([]);
const prevData = useRef<NavigationTree[]>(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 => (
<TreeItem
key={node.id}
nodeId={node.id}
label={node.name}
onLabelClick={() => scrollToItem(node.id)}
onLabelClick={(event) => onLabelClick(event, node.id)}
className={cssNames({selected: node.selected})}
>
{Array.isArray(node.children) ? node.children.map((node) => renderTree([node])) : null}
@ -33,17 +69,14 @@ export function RecursiveTreeView({ data }: Props) {
));
};
const scrollToItem = (id: string) => {
const element = document.getElementById(id);
element?.scrollIntoView();
};
const getAllNodeIds = (nodes: NavigationTree[]): string[] => {
return flattenDeep(nodes.map(node => {
return [node.id, ...node.children.map(item => getAllNodeIds([item]))];
}));
};
useEffect(() => {
if (!prevData.current.length) {
expandTopLevelNodes();
} else {
expandParentNode();
}
prevData.current = data;
}, [data]);
if (!data.length) {
return null;
@ -52,7 +85,8 @@ export function RecursiveTreeView({ data }: Props) {
return (
<TreeView
className="TreeView"
defaultExpanded={getAllNodeIds(data)}
expanded={expanded}
onNodeToggle={handleToggle}
defaultCollapseIcon={<Icon material="expand_more"/>}
defaultExpandIcon={<Icon material="chevron_right" />}
>

View File

@ -4381,6 +4381,13 @@ deep-is@^0.1.3, deep-is@~0.1.3:
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
deepdash-es@^5.3.5:
version "5.3.5"
resolved "https://registry.yarnpkg.com/deepdash-es/-/deepdash-es-5.3.5.tgz#1217365f6508bb47f1f90def6b4f1c4b5f4ff6eb"
integrity sha512-bezxT+LqAu1Ly8I2LAEFle3fdEAc/bHld9cMAbgYzY+69+P9qTkGtNvC2ZQJEP4C1C2Fx9gVn/TCoQlAivWPDA==
dependencies:
lodash-es "^4.17.15"
deepmerge@^4.2.2:
version "4.2.2"
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
@ -8637,6 +8644,11 @@ lockfile@^1.0.4:
dependencies:
signal-exit "^3.0.2"
lodash-es@^4.17.15:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
lodash._baseuniq@~4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8"