Only render a single context menu for the entire tree

Summary: There is no reason to have a context menu rendered by react for each item in the tree, its pretty wastefull. It also means less props drilled to the tree node

Reviewed By: lblasa

Differential Revision: D41872778

fbshipit-source-id: b13491a310c03334d7f3056207f5de23d20c3e61
This commit is contained in:
Luke De Feo
2022-12-12 07:28:37 -08:00
committed by Facebook GitHub Bot
parent 040240ec34
commit ed35623bef

View File

@@ -83,31 +83,35 @@ export function Tree2({
<HighlightProvider <HighlightProvider
text={searchTerm} text={searchTerm}
highlightColor={theme.searchHighlightBackground.yellow}> highlightColor={theme.searchHighlightBackground.yellow}>
<div <ContextMenu
onMouseLeave={() => { focusedNode={focusedNode}
if (isContextMenuOpen === false) { hoveredNode={hoveredNode}
instance.uiState.hoveredNodes.set([]); nodes={nodes}
} onContextMenuOpen={instance.uiActions.onContextMenuOpen}
}}> onFocusNode={instance.uiActions.onFocusNode}>
{treeNodes.map((treeNode, index) => ( <div
<MemoTreeItemContainer onMouseLeave={() => {
innerRef={refs[index]} if (isContextMenuOpen === false) {
key={treeNode.id} instance.uiState.hoveredNodes.set([]);
treeNode={treeNode} }
selectedNode={selectedNode} }}>
hoveredNode={hoveredNode} {treeNodes.map((treeNode, index) => (
focusedNode={focusedNode} <MemoTreeItemContainer
isUsingKBToScroll={isUsingKBToScroll} innerRef={refs[index]}
isContextMenuOpen={isContextMenuOpen} key={treeNode.id}
onSelectNode={onSelectNode} treeNode={treeNode}
onExpandNode={instance.uiActions.onExpandNode} selectedNode={selectedNode}
onCollapseNode={instance.uiActions.onCollapseNode} hoveredNode={hoveredNode}
onContextMenuOpen={instance.uiActions.onContextMenuOpen} isUsingKBToScroll={isUsingKBToScroll}
onFocusNode={instance.uiActions.onFocusNode} isContextMenuOpen={isContextMenuOpen}
onHoverNode={instance.uiActions.onHoverNode} onSelectNode={onSelectNode}
/> onExpandNode={instance.uiActions.onExpandNode}
))} onCollapseNode={instance.uiActions.onCollapseNode}
</div> onHoverNode={instance.uiActions.onHoverNode}
/>
))}
</div>
</ContextMenu>
</HighlightProvider> </HighlightProvider>
); );
} }
@@ -138,11 +142,8 @@ function TreeItemContainer({
treeNode, treeNode,
selectedNode, selectedNode,
hoveredNode, hoveredNode,
focusedNode,
isUsingKBToScroll, isUsingKBToScroll,
isContextMenuOpen, isContextMenuOpen,
onFocusNode,
onContextMenuOpen,
onSelectNode, onSelectNode,
onExpandNode, onExpandNode,
onCollapseNode, onCollapseNode,
@@ -152,55 +153,42 @@ function TreeItemContainer({
treeNode: TreeNode; treeNode: TreeNode;
selectedNode?: Id; selectedNode?: Id;
hoveredNode?: Id; hoveredNode?: Id;
focusedNode?: Id;
isUsingKBToScroll: RefObject<boolean>; isUsingKBToScroll: RefObject<boolean>;
isContextMenuOpen: boolean; isContextMenuOpen: boolean;
onFocusNode: (id?: Id) => void;
onContextMenuOpen: (open: boolean) => void;
onSelectNode: (node?: Id) => void; onSelectNode: (node?: Id) => void;
onExpandNode: (node: Id) => void; onExpandNode: (node: Id) => void;
onCollapseNode: (node: Id) => void; onCollapseNode: (node: Id) => void;
onHoverNode: (node: Id) => void; onHoverNode: (node: Id) => void;
}) { }) {
return ( return (
<ContextMenu <TreeItem
onContextMenuOpen={onContextMenuOpen} ref={innerRef}
onFocusNode={onFocusNode} isSelected={treeNode.id === selectedNode}
focusedNode={focusedNode} isHovered={hoveredNode === treeNode.id}
hoveredNode={hoveredNode} onMouseEnter={() => {
node={treeNode}> if (isUsingKBToScroll.current === false && isContextMenuOpen == false) {
<TreeItem onHoverNode(treeNode.id);
ref={innerRef} }
isSelected={treeNode.id === selectedNode} }}
isHovered={hoveredNode === treeNode.id} onClick={() => {
onMouseEnter={() => { onSelectNode(treeNode.id);
if ( }}
isUsingKBToScroll.current === false && item={treeNode}>
isContextMenuOpen == false <ExpandedIconOrSpace
) { expanded={treeNode.isExpanded}
onHoverNode(treeNode.id); showIcon={treeNode.children.length > 0}
onClick={() => {
if (treeNode.isExpanded) {
onCollapseNode(treeNode.id);
} else {
onExpandNode(treeNode.id);
} }
}} }}
onClick={() => { />
onSelectNode(treeNode.id); {nodeIcon(treeNode)}
}} <HighlightedText text={treeNode.name} />
item={treeNode}> <InlineAttributes attributes={treeNode.inlineAttributes} />
<ExpandedIconOrSpace </TreeItem>
expanded={treeNode.isExpanded}
showIcon={treeNode.children.length > 0}
onClick={() => {
if (treeNode.isExpanded) {
onCollapseNode(treeNode.id);
} else {
onExpandNode(treeNode.id);
}
}}
/>
{nodeIcon(treeNode)}
<HighlightedText text={treeNode.name} />
<InlineAttributes attributes={treeNode.inlineAttributes} />
</TreeItem>
</ContextMenu>
); );
} }
@@ -291,13 +279,13 @@ const DecorationImage = styled.img({
const renderDepthOffset = 4; const renderDepthOffset = 4;
const ContextMenu: React.FC<{ const ContextMenu: React.FC<{
node: TreeNode; nodes: Map<Id, UINode>;
hoveredNode?: Id; hoveredNode?: Id;
focusedNode?: Id; focusedNode?: Id;
onFocusNode: (id?: Id) => void; onFocusNode: (id?: Id) => void;
onContextMenuOpen: (open: boolean) => void; onContextMenuOpen: (open: boolean) => void;
}> = ({ }> = ({
node, nodes,
hoveredNode, hoveredNode,
children, children,
focusedNode, focusedNode,
@@ -311,12 +299,12 @@ const ContextMenu: React.FC<{
}} }}
overlay={() => ( overlay={() => (
<Menu> <Menu>
{focusedNode !== hoveredNode && ( {hoveredNode != null && focusedNode !== hoveredNode && (
<UIDebuggerMenuItem <UIDebuggerMenuItem
key="focus" key="focus"
text={`Focus ${node.name}`} text={`Focus ${nodes.get(hoveredNode)?.name}`}
onClick={() => { onClick={() => {
onFocusNode(node.id); onFocusNode(hoveredNode);
}} }}
/> />
)} )}