Skip to content

Commit 259740a

Browse files
noi5eKaram Qaoud
authored and
Karam Qaoud
committed
Collapse and Expand DevTools Tree Nodes (facebook#2679)
1 parent 2ae8653 commit 259740a

File tree

7 files changed

+109
-33
lines changed

7 files changed

+109
-33
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.chevron-button {
2+
background: #222;
3+
border: none;
4+
color: #fff;
5+
cursor: pointer;
6+
margin: 0;
7+
padding: 0;
8+
text-decoration: none;
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
*/
8+
import './index.css';
9+
10+
import * as React from 'react';
11+
12+
function Chevron({
13+
handleClick,
14+
isExpanded,
15+
}: {
16+
handleClick: React.MouseEventHandler;
17+
isExpanded: boolean;
18+
}): JSX.Element {
19+
return (
20+
<button className="chevron-button" onClick={handleClick}>
21+
{isExpanded ? <>&#x25BC;</> : <>&#9654;</>}
22+
</button>
23+
);
24+
}
25+
26+
export default Chevron;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
.indentation {
2+
background: #222;
3+
border: none;
4+
color: #222;
5+
margin: 0;
6+
padding: 0;
7+
text-decoration: none;
8+
user-select: none;
9+
}
10+
11+
.tree-node {
12+
padding-left: 1em;
13+
width: 100%;
14+
}
15+
16+
.tree-node-wrapper {
17+
width: 100%;
18+
}

packages/lexical-devtools/src/panel/components/TreeNode/index.tsx

+35-16
Original file line numberDiff line numberDiff line change
@@ -5,33 +5,52 @@
55
* LICENSE file in the root directory of this source tree.
66
*
77
*/
8+
import './index.css';
9+
810
import {DevToolsNode} from 'packages/lexical-devtools/types';
911
import * as React from 'react';
12+
import {useState} from 'react';
13+
14+
import Chevron from '../Chevron';
1015

1116
function TreeNode({
12-
lexicalKey,
1317
__text,
1418
__type,
1519
children,
16-
}: {
17-
children: Array<DevToolsNode>;
18-
lexicalKey: string;
19-
__text?: string;
20-
__type: string;
21-
}): JSX.Element {
20+
depth,
21+
lexicalKey,
22+
}: DevToolsNode): JSX.Element {
23+
const [isExpanded, setIsExpanded] = useState(true);
24+
25+
const handleChevronClick = () => {
26+
setIsExpanded(!isExpanded);
27+
};
28+
29+
const nodeString = ` (${lexicalKey}) ${__type} ${
30+
__text ? '"' + __text + '"' : ''
31+
}`;
32+
const childNodes =
33+
children.length > 0 ? (
34+
<>
35+
{children.map((child) => (
36+
<TreeNode {...child} />
37+
))}
38+
</>
39+
) : (
40+
''
41+
);
42+
2243
return (
23-
<li key={lexicalKey}>
24-
({lexicalKey}) {__type} {__text ? '"' + __text + '"' : ''}
44+
<div className="tree-node" key={lexicalKey}>
2545
{children.length > 0 ? (
26-
<ul>
27-
{children.map((child) => (
28-
<TreeNode {...child} />
29-
))}
30-
</ul>
46+
<Chevron handleClick={handleChevronClick} isExpanded={isExpanded} />
3147
) : (
32-
''
48+
<button className="indentation">&#9654;</button>
3349
)}
34-
</li>
50+
{nodeString}
51+
{<br />}
52+
{isExpanded ? childNodes : ''}
53+
</div>
3554
);
3655
}
3756

packages/lexical-devtools/src/panel/components/TreeView/index.css

+2-6
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,10 @@
44
color: #fff;
55
margin: 0;
66
padding: 1em;
7-
font-size: 1em;
7+
font-size: 1.2em;
88
overflow: auto;
99
text-align: left;
1010
-moz-osx-font-smoothing: grayscale;
1111
font-weight: 400;
12-
}
13-
14-
.tree-view-output ul li {
15-
font-family: monospace;
16-
padding-left: 0.5em;
12+
--indentation-size: 1em;
1713
}

packages/lexical-devtools/src/panel/components/TreeView/index.tsx

+17-10
Original file line numberDiff line numberDiff line change
@@ -19,29 +19,36 @@ function TreeView({
1919
viewClassName: string;
2020
nodeMap: DevToolsTree;
2121
}): JSX.Element {
22-
const depthFirstSearch = (node: DevToolsNode): DevToolsNode => {
22+
// takes flat JSON structure, nests child comments inside parents
23+
const depthFirstSearch = (
24+
map: DevToolsTree = nodeMap,
25+
nodeKey = 'root',
26+
depth = 0,
27+
): DevToolsNode => {
28+
const node = map[nodeKey];
2329
const children: Array<DevToolsNode> = [];
2430

2531
if (Object.prototype.hasOwnProperty.call(node, '__children')) {
2632
node.__children.forEach((childKey: string) => {
27-
const child = nodeMap[childKey];
28-
children.push(depthFirstSearch(child));
33+
children.push(depthFirstSearch(map, childKey, depth + 1));
2934
});
3035
}
3136

32-
return {...node, __type: node.__type, children, lexicalKey: node.__key};
37+
return {
38+
...node,
39+
__type: node.__type,
40+
children,
41+
depth,
42+
lexicalKey: node.__key,
43+
};
3344
};
3445

3546
const generateTree = (map: DevToolsTree): JSX.Element => {
36-
const root = depthFirstSearch(map.root);
47+
const root = depthFirstSearch(nodeMap, 'root', 0);
3748
return <TreeNode {...root} />;
3849
};
3950

40-
return (
41-
<div className={viewClassName}>
42-
<ul>{generateTree(nodeMap)}</ul>
43-
</div>
44-
);
51+
return <div className={viewClassName}>{generateTree(nodeMap)}</div>;
4552
}
4653

4754
export default TreeView;

packages/lexical-devtools/types.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ export interface DevToolsTree {
1212
export interface DevToolsNode {
1313
// eslint-disable-next-line @typescript-eslint/no-explicit-any
1414
[x: string]: any;
15-
children: Array<DevToolsNode>;
1615
__text?: string;
1716
__type: string;
17+
children: Array<DevToolsNode>;
18+
depth: number;
1819
lexicalKey: string;
1920
}

0 commit comments

Comments
 (0)