@itwin/presentation-hierarchies-react
Version:
React components based on `@itwin/presentation-hierarchies`
128 lines • 5.83 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
import { useEffect, useState } from "react";
import { assert } from "@itwin/core-bentley";
import { HierarchyNode } from "@itwin/presentation-hierarchies";
import { Selectables } from "@itwin/unified-selection";
import { useUnifiedSelectionStorage } from "../UnifiedSelectionContext.js";
import { isTreeModelHierarchyNode } from "./TreeModel.js";
/** @internal */
export function useUnifiedTreeSelection({ sourceName, selectionStorage, getTreeModelNode, createSelectableForGenericNode, }) {
const [options, setOptions] = useState(() => ({
isNodeSelected: /* c8 ignore next */ () => false,
selectNodes: /* c8 ignore next */ () => { },
}));
const deprecatedSelectionStorage = useUnifiedSelectionStorage();
selectionStorage ??= deprecatedSelectionStorage;
createSelectableForGenericNode ??= defaultCreateSelectableForGenericNode;
useEffect(() => {
if (!selectionStorage) {
// TODO: make selectionStorage prop required
setOptions({
isNodeSelected: () => false,
selectNodes: () => { },
});
return;
}
setOptions(createOptions(sourceName, selectionStorage, createSelectableForGenericNode, getTreeModelNode));
return selectionStorage.selectionChangeEvent.addListener((args) => {
if (args.level > 0) {
return;
}
setOptions(createOptions(sourceName, selectionStorage, createSelectableForGenericNode, getTreeModelNode));
});
}, [selectionStorage, createSelectableForGenericNode, getTreeModelNode, sourceName]);
return options;
}
const defaultCreateSelectableForGenericNode = (node, treeModelNodeId) => ({
identifier: treeModelNodeId,
data: node,
async *loadInstanceKeys() { },
});
function createOptions(source, storage, createSelectableForGenericNode, getNode) {
return {
isNodeSelected: (nodeId) => {
const node = getNode(nodeId);
if (!node || !isTreeModelHierarchyNode(node)) {
return false;
}
return Object.entries(groupNodeSelectablesByIModelKey(node, createSelectableForGenericNode)).some(([imodelKey, nodeSelectables]) => {
const storageSelectables = storage.getSelection({ imodelKey, level: 0 });
return Selectables.hasAny(storageSelectables, nodeSelectables);
});
},
selectNodes: (nodeIds, changeType) => {
const imodelSelectables = {};
for (const nodeId of nodeIds) {
const node = getNode(nodeId);
if (!node || !isTreeModelHierarchyNode(node)) {
return;
}
Object.entries(groupNodeSelectablesByIModelKey(node, createSelectableForGenericNode)).forEach(([imodelKey, nodeSelectables]) => {
let selectablesList = imodelSelectables[imodelKey];
if (!selectablesList) {
selectablesList = [];
imodelSelectables[imodelKey] = selectablesList;
}
nodeSelectables.forEach((selectable) => selectablesList.push(selectable));
});
}
Object.entries(imodelSelectables).forEach(([imodelKey, selectables]) => {
const actionProps = { imodelKey, source, selectables, level: 0 };
switch (changeType) {
case "add":
storage.addToSelection(actionProps);
return;
case "remove":
storage.removeFromSelection(actionProps);
return;
case "replace":
storage.replaceSelection(actionProps);
return;
}
});
},
};
}
function groupNodeSelectablesByIModelKey(modelNode, createSelectableForGenericNode) {
const hierarchyNode = modelNode.nodeData;
if (HierarchyNode.isInstancesNode(hierarchyNode)) {
return groupIModelInstanceKeys(hierarchyNode.key.instanceKeys);
}
if (HierarchyNode.isGroupingNode(hierarchyNode)) {
return Object.entries(groupIModelInstanceKeys(hierarchyNode.groupedInstanceKeys)).reduce((imodelSelectables, [imodelKey, instanceKeys]) => ({
...imodelSelectables,
[imodelKey]: [
{
identifier: modelNode.id,
data: hierarchyNode,
async *loadInstanceKeys() {
for (const key of instanceKeys) {
yield key;
}
},
},
],
}), {});
}
assert(HierarchyNode.isGeneric(hierarchyNode));
return {
// note: generic nodes aren't associated with an imodel
[""]: [createSelectableForGenericNode(hierarchyNode, modelNode.id)],
};
}
function groupIModelInstanceKeys(instanceKeys) {
return instanceKeys.reduce((imodelSelectables, key) => {
const imodelKey = key.imodelKey ?? "";
let selectablesList = imodelSelectables[imodelKey];
if (!selectablesList) {
selectablesList = [];
imodelSelectables[imodelKey] = selectablesList;
}
selectablesList.push(key);
return imodelSelectables;
}, {});
}
//# sourceMappingURL=UseUnifiedSelection.js.map