UNPKG

@itwin/presentation-hierarchies-react

Version:

React components based on `@itwin/presentation-hierarchies`

101 lines 4.34 kB
"use strict"; /*--------------------------------------------------------------------------------------------- * 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