@itwin/presentation-hierarchies-react
Version:
React components based on `@itwin/presentation-hierarchies`
101 lines • 4.34 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.useSelectionHandler = useSelectionHandler;
const react_1 = require("react");
const TreeNode_js_1 = require("./TreeNode.js");
/**
* A react hook that helps implement different selection modes in a tree component created using `useTree` hook.
* @public
*/
function useSelectionHandler(props) {
const { rootNodes, selectionMode, selectNodes } = props;
const previousSelectionRef = (0, react_1.useRef)(undefined);
const state = (0, react_1.useRef)({
flatNodeList: [],
nodeIdToIndexMap: new Map(),
});
(0, react_1.useEffect)(() => {
if (!rootNodes) {
return;
}
state.current = computeFlatNodeList(rootNodes);
}, [rootNodes]);
const getNodeRange = (firstId, secondId) => {
const getIndex = (nodeId) => {
return nodeId ? state.current.nodeIdToIndexMap.get(nodeId) : 0;
};
const firstIndex = getIndex(firstId);
const secondIndex = getIndex(secondId);
if (firstIndex === undefined || secondIndex === undefined) {
return [];
}
const startingIndex = Math.min(firstIndex, secondIndex);
const endIndex = Math.max(firstIndex, secondIndex);
return state.current.flatNodeList.slice(startingIndex, endIndex + 1);
};
const onNodeSelect = (0, react_1.useCallback)((nodeId, isSelected, shiftDown, ctrlDown) => {
const selection = getSelectionAction(selectionMode, isSelected, shiftDown, ctrlDown);
if (selection.type === "disabled") {
return;
}
const nodes = selection.select === "range" ? getNodeRange(previousSelectionRef.current, nodeId) : [nodeId];
if (!nodes.length) {
return;
}
selection.select !== "range" && (previousSelectionRef.current = nodeId);
selectNodes(nodes, selection.type);
}, [selectionMode, selectNodes]);
const onNodeClick = (0, react_1.useCallback)((node, isSelected, event) => {
return onNodeSelect(node.id, isSelected, event.shiftKey, event.ctrlKey);
}, [onNodeSelect]);
const onNodeKeyDown = (0, react_1.useCallback)((node, isSelected, event) => {
if (event.key === " " || event.key === "Spacebar" || event.key === "Enter") {
return onNodeSelect(node.id, isSelected, event.shiftKey, event.ctrlKey);
}
}, [onNodeSelect]);
return { onNodeClick, onNodeKeyDown };
}
function getSelectionAction(selectionMode, isSelected, shiftDown, ctrlDown) {
switch (selectionMode) {
case "none":
return { select: "node", type: "disabled" };
case "single":
return { select: "node", type: isSelected ? "replace" : "remove" };
case "multiple":
return { select: "node", type: isSelected ? "add" : "remove" };
case "extended":
return getExtendedSelectionAction(isSelected, shiftDown, ctrlDown);
}
}
function getExtendedSelectionAction(isSelected, shiftDown, ctrlDown) {
if (shiftDown) {
return { select: "range", type: "replace" };
}
if (ctrlDown) {
return { select: "node", type: isSelected ? "add" : "remove" };
}
return { select: "node", type: "replace" };
}
function computeFlatNodeList(rootNodes) {
const flatNodeList = [];
const nodeIdToIndexMap = new Map();
const flattenNodeRecursively = (nodes) => {
nodes.forEach((node) => {
if (!(0, TreeNode_js_1.isPresentationHierarchyNode)(node)) {
return;
}
nodeIdToIndexMap.set(node.id, flatNodeList.length);
flatNodeList.push(node.id);
if (node.isExpanded && typeof node.children !== "boolean") {
flattenNodeRecursively(node.children);
}
});
};
flattenNodeRecursively(rootNodes);
return { flatNodeList, nodeIdToIndexMap };
}
//# sourceMappingURL=UseSelectionHandler.js.map
;