Toggle all children when holding the shift/option key

This commit is contained in:
Eric Allam
2022-03-18 11:34:25 +00:00
parent de1efa8149
commit 48d8c9894c
2 changed files with 79 additions and 8 deletions
+3 -3
View File
@@ -81,7 +81,7 @@ export function JsonTreeView() {
<TreeViewNode
virtualNode={virtualNode}
key={virtualNode.node.id}
onToggle={() => tree.toggleNode(virtualNode.node.id)}
onToggle={(node, e) => tree.toggleNode(node.id, e)}
selectedNodeId={selectedNodeId}
/>
))}
@@ -97,7 +97,7 @@ function TreeViewNode({
}: {
virtualNode: VirtualNode<JsonTreeViewNode>;
selectedNodeId?: string;
onToggle?: (node: JsonTreeViewNode) => void;
onToggle?: (node: JsonTreeViewNode, e: MouseEvent) => void;
}) {
const { tree } = useJsonTreeViewContext();
@@ -145,7 +145,7 @@ function TreeViewNode({
onClick={(e) => {
if (onToggle) {
e.preventDefault();
onToggle(node);
onToggle(node, e.nativeEvent);
}
}}
>
+74 -3
View File
@@ -34,7 +34,7 @@ export type UseVirtualTreeInstance<T> = {
nodes: VirtualNode<T>[];
focusedNodeId: string | null;
totalSize: number;
toggleNode: (id: string) => void;
toggleNode: (id: string, source?: KeyboardEvent | MouseEvent) => void;
focusNode: (id: string) => void;
focusFirst: () => void;
scrollToNode: (id: string) => void;
@@ -60,6 +60,7 @@ type TreeState<T extends { id: string; children?: T[] }> = {
type ToggleNodeAction = {
type: "TOGGLE_NODE";
id: string;
source?: KeyboardEvent | MouseEvent;
};
type FocusNodeAction = {
@@ -138,6 +139,56 @@ function collapseNode<T extends { id: string; children?: T[] }>(
focusedNodeId: id,
};
}
function toggleAllChildren<T extends { id: string; children?: T[] }>(
state: TreeState<T>,
id: string
): TreeState<T> {
const item = state.items.find(({ id: nodeId }) => nodeId === id);
if (!item) {
return state;
}
if (!item.node.children || item.node.children.length === 0) {
return state;
}
const allCollapsed = item.node.children.every(
(child) => state.collapsedState[child.id]
);
if (allCollapsed) {
const collapsedState = item.node.children.reduce(
(acc, child) => ({
...acc,
[child.id]: false,
}),
state.collapsedState
);
return {
...state,
collapsedState,
items: createNodeItems(state.nodes, 0, collapsedState),
focusedNodeId: id,
};
}
const collapsedState = item.node.children.reduce(
(acc, child) => ({
...acc,
[child.id]: true,
}),
state.collapsedState
);
return {
...state,
collapsedState,
items: createNodeItems(state.nodes, 0, collapsedState),
focusedNodeId: id,
};
}
export function useVirtualTree<T extends { id: string; children?: T[] }, R>(
options: UseVirtualTreeOptions<T, R>
@@ -150,10 +201,17 @@ export function useVirtualTree<T extends { id: string; children?: T[] }, R>(
if (isCollapsed) {
return expandNode<T>(state, action.id);
} else {
if (
action.source &&
(action.source.shiftKey || action.source.altKey)
) {
return toggleAllChildren<T>(state, action.id);
} else {
return collapseNode<T>(state, action.id);
}
}
}
case "FOCUS_NODE": {
return {
...state,
@@ -229,6 +287,12 @@ export function useVirtualTree<T extends { id: string; children?: T[] }, R>(
if (action.isCollapsed) {
return expandNode<T>(state, action.id);
}
if (
action.source &&
(action.source.shiftKey || action.source.altKey)
) {
return toggleAllChildren<T>(state, action.id);
}
const nodeIndex = state.items.findIndex(
(item) => item.id === action.id
@@ -251,8 +315,15 @@ export function useVirtualTree<T extends { id: string; children?: T[] }, R>(
}
case "MOVE_LEFT": {
if (action.hasChildren && !action.isCollapsed) {
if (
action.source &&
(action.source.shiftKey || action.source.altKey)
) {
return toggleAllChildren<T>(state, action.id);
} else {
return collapseNode<T>(state, action.id);
}
}
if (!action.hasChildren || action.isCollapsed) {
// Try to go to the parent node
@@ -392,8 +463,8 @@ export function useVirtualTree<T extends { id: string; children?: T[] }, R>(
});
const toggleNode = useCallback(
(id: string) => {
dispatch({ type: "TOGGLE_NODE", id });
(id: string, source?: KeyboardEvent | MouseEvent) => {
dispatch({ type: "TOGGLE_NODE", id, source });
},
[dispatch]
);