@itwin/presentation-hierarchies-react 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/LICENSE.md +9 -0
  3. package/README.md +303 -0
  4. package/lib/cjs/presentation-hierarchies-react/TreeNode.d.ts +75 -0
  5. package/lib/cjs/presentation-hierarchies-react/TreeNode.d.ts.map +1 -0
  6. package/lib/cjs/presentation-hierarchies-react/TreeNode.js +16 -0
  7. package/lib/cjs/presentation-hierarchies-react/TreeNode.js.map +1 -0
  8. package/lib/cjs/presentation-hierarchies-react/UnifiedSelectionContext.d.ts +18 -0
  9. package/lib/cjs/presentation-hierarchies-react/UnifiedSelectionContext.d.ts.map +1 -0
  10. package/lib/cjs/presentation-hierarchies-react/UnifiedSelectionContext.js +28 -0
  11. package/lib/cjs/presentation-hierarchies-react/UnifiedSelectionContext.js.map +1 -0
  12. package/lib/cjs/presentation-hierarchies-react/UseSelectionHandler.d.ts +33 -0
  13. package/lib/cjs/presentation-hierarchies-react/UseSelectionHandler.d.ts.map +1 -0
  14. package/lib/cjs/presentation-hierarchies-react/UseSelectionHandler.js +102 -0
  15. package/lib/cjs/presentation-hierarchies-react/UseSelectionHandler.js.map +1 -0
  16. package/lib/cjs/presentation-hierarchies-react/UseTree.d.ts +85 -0
  17. package/lib/cjs/presentation-hierarchies-react/UseTree.d.ts.map +1 -0
  18. package/lib/cjs/presentation-hierarchies-react/UseTree.js +214 -0
  19. package/lib/cjs/presentation-hierarchies-react/UseTree.js.map +1 -0
  20. package/lib/cjs/presentation-hierarchies-react/internal/TreeActions.d.ts +27 -0
  21. package/lib/cjs/presentation-hierarchies-react/internal/TreeActions.d.ts.map +1 -0
  22. package/lib/cjs/presentation-hierarchies-react/internal/TreeActions.js +236 -0
  23. package/lib/cjs/presentation-hierarchies-react/internal/TreeActions.js.map +1 -0
  24. package/lib/cjs/presentation-hierarchies-react/internal/TreeLoader.d.ts +33 -0
  25. package/lib/cjs/presentation-hierarchies-react/internal/TreeLoader.d.ts.map +1 -0
  26. package/lib/cjs/presentation-hierarchies-react/internal/TreeLoader.js +71 -0
  27. package/lib/cjs/presentation-hierarchies-react/internal/TreeLoader.js.map +1 -0
  28. package/lib/cjs/presentation-hierarchies-react/internal/TreeModel.d.ts +70 -0
  29. package/lib/cjs/presentation-hierarchies-react/internal/TreeModel.d.ts.map +1 -0
  30. package/lib/cjs/presentation-hierarchies-react/internal/TreeModel.js +154 -0
  31. package/lib/cjs/presentation-hierarchies-react/internal/TreeModel.js.map +1 -0
  32. package/lib/cjs/presentation-hierarchies-react/internal/UseUnifiedSelection.d.ts +16 -0
  33. package/lib/cjs/presentation-hierarchies-react/internal/UseUnifiedSelection.d.ts.map +1 -0
  34. package/lib/cjs/presentation-hierarchies-react/internal/UseUnifiedSelection.js +96 -0
  35. package/lib/cjs/presentation-hierarchies-react/internal/UseUnifiedSelection.js.map +1 -0
  36. package/lib/cjs/presentation-hierarchies-react/internal/Utils.d.ts +8 -0
  37. package/lib/cjs/presentation-hierarchies-react/internal/Utils.d.ts.map +1 -0
  38. package/lib/cjs/presentation-hierarchies-react/internal/Utils.js +45 -0
  39. package/lib/cjs/presentation-hierarchies-react/internal/Utils.js.map +1 -0
  40. package/lib/cjs/presentation-hierarchies-react/itwinui/LocalizationContext.d.ts +57 -0
  41. package/lib/cjs/presentation-hierarchies-react/itwinui/LocalizationContext.d.ts.map +1 -0
  42. package/lib/cjs/presentation-hierarchies-react/itwinui/LocalizationContext.js +35 -0
  43. package/lib/cjs/presentation-hierarchies-react/itwinui/LocalizationContext.js.map +1 -0
  44. package/lib/cjs/presentation-hierarchies-react/itwinui/TreeNodeRenderer.css +17 -0
  45. package/lib/cjs/presentation-hierarchies-react/itwinui/TreeNodeRenderer.d.ts +27 -0
  46. package/lib/cjs/presentation-hierarchies-react/itwinui/TreeNodeRenderer.d.ts.map +1 -0
  47. package/lib/cjs/presentation-hierarchies-react/itwinui/TreeNodeRenderer.js +101 -0
  48. package/lib/cjs/presentation-hierarchies-react/itwinui/TreeNodeRenderer.js.map +1 -0
  49. package/lib/cjs/presentation-hierarchies-react/itwinui/TreeRenderer.d.ts +55 -0
  50. package/lib/cjs/presentation-hierarchies-react/itwinui/TreeRenderer.d.ts.map +1 -0
  51. package/lib/cjs/presentation-hierarchies-react/itwinui/TreeRenderer.js +83 -0
  52. package/lib/cjs/presentation-hierarchies-react/itwinui/TreeRenderer.js.map +1 -0
  53. package/lib/cjs/presentation-hierarchies-react.d.ts +10 -0
  54. package/lib/cjs/presentation-hierarchies-react.d.ts.map +1 -0
  55. package/lib/cjs/presentation-hierarchies-react.js +27 -0
  56. package/lib/cjs/presentation-hierarchies-react.js.map +1 -0
  57. package/lib/esm/presentation-hierarchies-react/TreeNode.d.ts +75 -0
  58. package/lib/esm/presentation-hierarchies-react/TreeNode.d.ts.map +1 -0
  59. package/lib/esm/presentation-hierarchies-react/TreeNode.js +12 -0
  60. package/lib/esm/presentation-hierarchies-react/TreeNode.js.map +1 -0
  61. package/lib/esm/presentation-hierarchies-react/UnifiedSelectionContext.d.ts +18 -0
  62. package/lib/esm/presentation-hierarchies-react/UnifiedSelectionContext.d.ts.map +1 -0
  63. package/lib/esm/presentation-hierarchies-react/UnifiedSelectionContext.js +23 -0
  64. package/lib/esm/presentation-hierarchies-react/UnifiedSelectionContext.js.map +1 -0
  65. package/lib/esm/presentation-hierarchies-react/UseSelectionHandler.d.ts +33 -0
  66. package/lib/esm/presentation-hierarchies-react/UseSelectionHandler.d.ts.map +1 -0
  67. package/lib/esm/presentation-hierarchies-react/UseSelectionHandler.js +98 -0
  68. package/lib/esm/presentation-hierarchies-react/UseSelectionHandler.js.map +1 -0
  69. package/lib/esm/presentation-hierarchies-react/UseTree.d.ts +85 -0
  70. package/lib/esm/presentation-hierarchies-react/UseTree.d.ts.map +1 -0
  71. package/lib/esm/presentation-hierarchies-react/UseTree.js +209 -0
  72. package/lib/esm/presentation-hierarchies-react/UseTree.js.map +1 -0
  73. package/lib/esm/presentation-hierarchies-react/internal/TreeActions.d.ts +27 -0
  74. package/lib/esm/presentation-hierarchies-react/internal/TreeActions.d.ts.map +1 -0
  75. package/lib/esm/presentation-hierarchies-react/internal/TreeActions.js +232 -0
  76. package/lib/esm/presentation-hierarchies-react/internal/TreeActions.js.map +1 -0
  77. package/lib/esm/presentation-hierarchies-react/internal/TreeLoader.d.ts +33 -0
  78. package/lib/esm/presentation-hierarchies-react/internal/TreeLoader.d.ts.map +1 -0
  79. package/lib/esm/presentation-hierarchies-react/internal/TreeLoader.js +67 -0
  80. package/lib/esm/presentation-hierarchies-react/internal/TreeLoader.js.map +1 -0
  81. package/lib/esm/presentation-hierarchies-react/internal/TreeModel.d.ts +70 -0
  82. package/lib/esm/presentation-hierarchies-react/internal/TreeModel.d.ts.map +1 -0
  83. package/lib/esm/presentation-hierarchies-react/internal/TreeModel.js +149 -0
  84. package/lib/esm/presentation-hierarchies-react/internal/TreeModel.js.map +1 -0
  85. package/lib/esm/presentation-hierarchies-react/internal/UseUnifiedSelection.d.ts +16 -0
  86. package/lib/esm/presentation-hierarchies-react/internal/UseUnifiedSelection.d.ts.map +1 -0
  87. package/lib/esm/presentation-hierarchies-react/internal/UseUnifiedSelection.js +92 -0
  88. package/lib/esm/presentation-hierarchies-react/internal/UseUnifiedSelection.js.map +1 -0
  89. package/lib/esm/presentation-hierarchies-react/internal/Utils.d.ts +8 -0
  90. package/lib/esm/presentation-hierarchies-react/internal/Utils.d.ts.map +1 -0
  91. package/lib/esm/presentation-hierarchies-react/internal/Utils.js +40 -0
  92. package/lib/esm/presentation-hierarchies-react/internal/Utils.js.map +1 -0
  93. package/lib/esm/presentation-hierarchies-react/itwinui/LocalizationContext.d.ts +57 -0
  94. package/lib/esm/presentation-hierarchies-react/itwinui/LocalizationContext.d.ts.map +1 -0
  95. package/lib/esm/presentation-hierarchies-react/itwinui/LocalizationContext.js +30 -0
  96. package/lib/esm/presentation-hierarchies-react/itwinui/LocalizationContext.js.map +1 -0
  97. package/lib/esm/presentation-hierarchies-react/itwinui/TreeNodeRenderer.css +17 -0
  98. package/lib/esm/presentation-hierarchies-react/itwinui/TreeNodeRenderer.d.ts +27 -0
  99. package/lib/esm/presentation-hierarchies-react/itwinui/TreeNodeRenderer.d.ts.map +1 -0
  100. package/lib/esm/presentation-hierarchies-react/itwinui/TreeNodeRenderer.js +94 -0
  101. package/lib/esm/presentation-hierarchies-react/itwinui/TreeNodeRenderer.js.map +1 -0
  102. package/lib/esm/presentation-hierarchies-react/itwinui/TreeRenderer.d.ts +55 -0
  103. package/lib/esm/presentation-hierarchies-react/itwinui/TreeRenderer.d.ts.map +1 -0
  104. package/lib/esm/presentation-hierarchies-react/itwinui/TreeRenderer.js +78 -0
  105. package/lib/esm/presentation-hierarchies-react/itwinui/TreeRenderer.js.map +1 -0
  106. package/lib/esm/presentation-hierarchies-react.d.ts +10 -0
  107. package/lib/esm/presentation-hierarchies-react.d.ts.map +1 -0
  108. package/lib/esm/presentation-hierarchies-react.js +13 -0
  109. package/lib/esm/presentation-hierarchies-react.js.map +1 -0
  110. package/package.json +103 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TreeNode.js","sourceRoot":"","sources":["../../../src/presentation-hierarchies-react/TreeNode.ts"],"names":[],"mappings":"AAAA;;;gGAGgG;AA4EhG;;;GAGG;AACH,MAAM,UAAU,2BAA2B,CAAC,IAA0B;IACpE,OAAO,UAAU,IAAI,IAAI,CAAC;AAC5B,CAAC","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n * See LICENSE.md in the project root for license terms and full copyright notice.\n *--------------------------------------------------------------------------------------------*/\n\nimport { HierarchyNode } from \"@itwin/presentation-hierarchies\";\n\n/**\n * A type that defines an actual expandable node in a UI tree component, built with `useTree` hook.\n * @beta\n */\nexport interface PresentationHierarchyNode {\n id: string;\n label: string;\n children: true | Array<PresentationTreeNode>;\n isExpanded: boolean;\n isLoading: boolean;\n isFilterable: boolean;\n isFiltered: boolean;\n /** UI-agnostic source of this node object. */\n nodeData: HierarchyNode;\n /** Additional data that may be assigned to this node. */\n extendedData?: { [key: string]: any };\n}\n\n/**\n * A type of `PresentationInfoNode` that is returned as the single child of a filtered parent node,\n * when none of the child nodes match the filter.\n *\n * @beta\n */\nexport interface PresentationNoFilterMatchesInfoNode {\n id: string;\n parentNodeId: string | undefined;\n type: \"NoFilterMatches\";\n}\n\n/**\n * A type of `PresentationInfoNode` that is returned as the single child of a parent node, when the\n * number of child nodes exceeds the limit set on the tree nodes loader. The limit is also included\n * on this node as `resultSetSizeLimit` attribute.\n *\n * @beta\n */\nexport interface PresentationResultSetTooLargeInfoNode {\n id: string;\n parentNodeId: string | undefined;\n type: \"ResultSetTooLarge\";\n resultSetSizeLimit: number;\n}\n\n/**\n * A type of `PresentationInfoNode` that contains a user-friendly message to be displayed in the UI.\n * Generally, this is the only child of a parent node, created in cases like an error loading children. The\n * renderer may offer users to re-load the children or the whole component in such cases.\n *\n * @beta\n */\nexport interface PresentationGenericInfoNode {\n id: string;\n parentNodeId: string | undefined;\n type: \"Unknown\";\n message: string;\n}\n\n/**\n * A type that defines a non-expandable, non-selectable informational node in a UI tree component, built\n * with `useTree` hook.\n *\n * @beta\n */\nexport type PresentationInfoNode = PresentationGenericInfoNode | PresentationResultSetTooLargeInfoNode | PresentationNoFilterMatchesInfoNode;\n\n/**\n * A type that defines a node in a UI tree component, built with `useTree` hook.\n * @beta\n */\nexport type PresentationTreeNode = PresentationHierarchyNode | PresentationInfoNode;\n\n/**\n * An utility function to check if a node is a `PresentationHierarchyNode`.\n * @beta\n */\nexport function isPresentationHierarchyNode(node: PresentationTreeNode): node is PresentationHierarchyNode {\n return \"children\" in node;\n}\n"]}
@@ -0,0 +1,18 @@
1
+ import { PropsWithChildren } from "react";
2
+ import { SelectionStorage } from "@itwin/unified-selection";
3
+ interface Props {
4
+ storage: SelectionStorage;
5
+ }
6
+ /**
7
+ * A React context provider that makes given selection storage available to all child components. This
8
+ * is a requirement for `useUnifiedSelectionTree` to work with unified selection.
9
+ *
10
+ * See `README.md` for a usage example.
11
+ *
12
+ * @beta
13
+ */
14
+ export declare function UnifiedSelectionProvider({ storage, children }: PropsWithChildren<Props>): import("react/jsx-runtime").JSX.Element;
15
+ /** @internal */
16
+ export declare function useUnifiedSelectionContext(): SelectionStorage | undefined;
17
+ export {};
18
+ //# sourceMappingURL=UnifiedSelectionContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UnifiedSelectionContext.d.ts","sourceRoot":"","sources":["../../../src/presentation-hierarchies-react/UnifiedSelectionContext.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAiB,iBAAiB,EAAc,MAAM,OAAO,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAI5D,UAAU,KAAK;IACb,OAAO,EAAE,gBAAgB,CAAC;CAC3B;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,iBAAiB,CAAC,KAAK,CAAC,2CAEvF;AAED,gBAAgB;AAChB,wBAAgB,0BAA0B,iCAEzC"}
@@ -0,0 +1,23 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /*---------------------------------------------------------------------------------------------
3
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
4
+ * See LICENSE.md in the project root for license terms and full copyright notice.
5
+ *--------------------------------------------------------------------------------------------*/
6
+ import { createContext, useContext } from "react";
7
+ const unifiedSelectionContext = createContext(undefined);
8
+ /**
9
+ * A React context provider that makes given selection storage available to all child components. This
10
+ * is a requirement for `useUnifiedSelectionTree` to work with unified selection.
11
+ *
12
+ * See `README.md` for a usage example.
13
+ *
14
+ * @beta
15
+ */
16
+ export function UnifiedSelectionProvider({ storage, children }) {
17
+ return _jsx(unifiedSelectionContext.Provider, { value: storage, children: children });
18
+ }
19
+ /** @internal */
20
+ export function useUnifiedSelectionContext() {
21
+ return useContext(unifiedSelectionContext);
22
+ }
23
+ //# sourceMappingURL=UnifiedSelectionContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UnifiedSelectionContext.js","sourceRoot":"","sources":["../../../src/presentation-hierarchies-react/UnifiedSelectionContext.tsx"],"names":[],"mappings":";AAAA;;;gGAGgG;AAEhG,OAAO,EAAE,aAAa,EAAqB,UAAU,EAAE,MAAM,OAAO,CAAC;AAGrE,MAAM,uBAAuB,GAAG,aAAa,CAA+B,SAAS,CAAC,CAAC;AAMvF;;;;;;;GAOG;AACH,MAAM,UAAU,wBAAwB,CAAC,EAAE,OAAO,EAAE,QAAQ,EAA4B;IACtF,OAAO,KAAC,uBAAuB,CAAC,QAAQ,IAAC,KAAK,EAAE,OAAO,YAAG,QAAQ,GAAoC,CAAC;AACzG,CAAC;AAED,gBAAgB;AAChB,MAAM,UAAU,0BAA0B;IACxC,OAAO,UAAU,CAAC,uBAAuB,CAAC,CAAC;AAC7C,CAAC","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n * See LICENSE.md in the project root for license terms and full copyright notice.\n *--------------------------------------------------------------------------------------------*/\n\nimport { createContext, PropsWithChildren, useContext } from \"react\";\nimport { SelectionStorage } from \"@itwin/unified-selection\";\n\nconst unifiedSelectionContext = createContext<SelectionStorage | undefined>(undefined);\n\ninterface Props {\n storage: SelectionStorage;\n}\n\n/**\n * A React context provider that makes given selection storage available to all child components. This\n * is a requirement for `useUnifiedSelectionTree` to work with unified selection.\n *\n * See `README.md` for a usage example.\n *\n * @beta\n */\nexport function UnifiedSelectionProvider({ storage, children }: PropsWithChildren<Props>) {\n return <unifiedSelectionContext.Provider value={storage}>{children}</unifiedSelectionContext.Provider>;\n}\n\n/** @internal */\nexport function useUnifiedSelectionContext() {\n return useContext(unifiedSelectionContext);\n}\n"]}
@@ -0,0 +1,33 @@
1
+ /// <reference types="react" />
2
+ import { useTree } from "./UseTree";
3
+ /**
4
+ * A union of different supported selection modes in a tree component:
5
+ * - `none` - no selection is allowed,
6
+ * - `single` - only one node can be selected at a time,
7
+ * - `extended` - multiple nodes can be selected using shift and ctrl keys,
8
+ * - `multiple` - multiple nodes can be selected without using shift or ctrl keys.
9
+ *
10
+ * @internal
11
+ */
12
+ export type SelectionMode = "none" | "single" | "extended" | "multiple";
13
+ /** @internal */
14
+ export type SelectionChangeType = "add" | "replace" | "remove";
15
+ /** Props for `useSelectionHandler` hook. */
16
+ type UseSelectionHandlerProps = Pick<ReturnType<typeof useTree>, "rootNodes" | "selectNodes"> & {
17
+ /** Selection mode that the component is working in. */
18
+ selectionMode: SelectionMode;
19
+ };
20
+ /** Result of `useSelectionHandler` hook. */
21
+ interface UseSelectionHandlerResult {
22
+ /** Should be called by node renderer when a node component is clicked. */
23
+ onNodeClick: (nodeId: string, isSelected: boolean, event: React.MouseEvent<HTMLElement, MouseEvent>) => void;
24
+ /** Should be called by node renderer when a keyboard event happens on a node. */
25
+ onNodeKeyDown: (nodeId: string, isSelected: boolean, event: React.KeyboardEvent<HTMLElement>) => void;
26
+ }
27
+ /**
28
+ * A react hook that helps implement different selection modes in a tree component created using `useTree` hook.
29
+ * @beta
30
+ */
31
+ export declare function useSelectionHandler(props: UseSelectionHandlerProps): UseSelectionHandlerResult;
32
+ export {};
33
+ //# sourceMappingURL=UseSelectionHandler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UseSelectionHandler.d.ts","sourceRoot":"","sources":["../../../src/presentation-hierarchies-react/UseSelectionHandler.ts"],"names":[],"mappings":";AAOA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC;;;;;;;;GAQG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,GAAG,UAAU,CAAC;AAExE,gBAAgB;AAChB,MAAM,MAAM,mBAAmB,GAAG,KAAK,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE/D,4CAA4C;AAC5C,KAAK,wBAAwB,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,OAAO,CAAC,EAAE,WAAW,GAAG,aAAa,CAAC,GAAG;IAC9F,uDAAuD;IACvD,aAAa,EAAE,aAAa,CAAC;CAC9B,CAAC;AAEF,4CAA4C;AAC5C,UAAU,yBAAyB;IACjC,0EAA0E;IAC1E,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,WAAW,EAAE,UAAU,CAAC,KAAK,IAAI,CAAC;IAC7G,iFAAiF;IACjF,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,aAAa,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;CACvG;AAOD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,wBAAwB,GAAG,yBAAyB,CAwD9F"}
@@ -0,0 +1,98 @@
1
+ /*---------------------------------------------------------------------------------------------
2
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
3
+ * See LICENSE.md in the project root for license terms and full copyright notice.
4
+ *--------------------------------------------------------------------------------------------*/
5
+ import { useEffect, useRef } from "react";
6
+ import { isPresentationHierarchyNode } from "./TreeNode";
7
+ /**
8
+ * A react hook that helps implement different selection modes in a tree component created using `useTree` hook.
9
+ * @beta
10
+ */
11
+ export function useSelectionHandler(props) {
12
+ const { rootNodes, selectionMode, selectNodes } = props;
13
+ const previousSelectionRef = useRef(undefined);
14
+ const state = useRef({
15
+ flatNodeList: [],
16
+ nodeIdToIndexMap: new Map(),
17
+ });
18
+ useEffect(() => {
19
+ if (!rootNodes) {
20
+ return;
21
+ }
22
+ state.current = computeFlatNodeList(rootNodes);
23
+ }, [rootNodes]);
24
+ const getNodeRange = (firstId, secondId) => {
25
+ const getIndex = (nodeId) => {
26
+ return nodeId ? state.current.nodeIdToIndexMap.get(nodeId) : 0;
27
+ };
28
+ const firstIndex = getIndex(firstId);
29
+ const secondIndex = getIndex(secondId);
30
+ if (firstIndex === undefined || secondIndex === undefined) {
31
+ return [];
32
+ }
33
+ const startingIndex = Math.min(firstIndex, secondIndex);
34
+ const endIndex = Math.max(firstIndex, secondIndex);
35
+ return state.current.flatNodeList.slice(startingIndex, endIndex + 1);
36
+ };
37
+ const onNodeSelect = (nodeId, isSelected, shiftDown, ctrlDown) => {
38
+ const selection = getSelectionAction(selectionMode, isSelected, shiftDown, ctrlDown);
39
+ if (selection.type === "disabled") {
40
+ return;
41
+ }
42
+ const nodes = selection.select === "range" ? getNodeRange(previousSelectionRef.current, nodeId) : [nodeId];
43
+ if (!nodes.length) {
44
+ return;
45
+ }
46
+ selection.select !== "range" && (previousSelectionRef.current = nodeId);
47
+ selectNodes(nodes, selection.type);
48
+ };
49
+ const onNodeClick = (nodeId, isSelected, event) => {
50
+ return onNodeSelect(nodeId, isSelected, event.shiftKey, event.ctrlKey);
51
+ };
52
+ const onNodeKeyDown = (nodeId, isSelected, event) => {
53
+ if (event.key === " " || event.key === "Spacebar" || event.key === "Enter") {
54
+ return onNodeSelect(nodeId, isSelected, event.shiftKey, event.ctrlKey);
55
+ }
56
+ };
57
+ return { onNodeClick, onNodeKeyDown };
58
+ }
59
+ function getSelectionAction(selectionMode, isSelected, shiftDown, ctrlDown) {
60
+ switch (selectionMode) {
61
+ case "none":
62
+ return { select: "node", type: "disabled" };
63
+ case "single":
64
+ return { select: "node", type: isSelected ? "replace" : "remove" };
65
+ case "multiple":
66
+ return { select: "node", type: isSelected ? "add" : "remove" };
67
+ case "extended":
68
+ return getExtendedSelectionAction(isSelected, shiftDown, ctrlDown);
69
+ }
70
+ }
71
+ function getExtendedSelectionAction(isSelected, shiftDown, ctrlDown) {
72
+ if (shiftDown) {
73
+ return { select: "range", type: "replace" };
74
+ }
75
+ if (!isSelected) {
76
+ return { select: "node", type: "remove" };
77
+ }
78
+ return { select: "node", type: ctrlDown ? "add" : "replace" };
79
+ }
80
+ function computeFlatNodeList(rootNodes) {
81
+ const flatNodeList = [];
82
+ const nodeIdToIndexMap = new Map();
83
+ const flattenNodeRecursively = (nodes) => {
84
+ nodes.forEach((node) => {
85
+ if (!isPresentationHierarchyNode(node)) {
86
+ return;
87
+ }
88
+ nodeIdToIndexMap.set(node.id, flatNodeList.length);
89
+ flatNodeList.push(node.id);
90
+ if (node.isExpanded && typeof node.children !== "boolean") {
91
+ flattenNodeRecursively(node.children);
92
+ }
93
+ });
94
+ };
95
+ flattenNodeRecursively(rootNodes);
96
+ return { flatNodeList, nodeIdToIndexMap };
97
+ }
98
+ //# sourceMappingURL=UseSelectionHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UseSelectionHandler.js","sourceRoot":"","sources":["../../../src/presentation-hierarchies-react/UseSelectionHandler.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n * See LICENSE.md in the project root for license terms and full copyright notice.\n *--------------------------------------------------------------------------------------------*/\n\nimport { useEffect, useRef } from \"react\";\nimport { isPresentationHierarchyNode, PresentationTreeNode } from \"./TreeNode\";\nimport { useTree } from \"./UseTree\";\n\n/**\n * A union of different supported selection modes in a tree component:\n * - `none` - no selection is allowed,\n * - `single` - only one node can be selected at a time,\n * - `extended` - multiple nodes can be selected using shift and ctrl keys,\n * - `multiple` - multiple nodes can be selected without using shift or ctrl keys.\n *\n * @internal\n */\nexport type SelectionMode = \"none\" | \"single\" | \"extended\" | \"multiple\";\n\n/** @internal */\nexport type SelectionChangeType = \"add\" | \"replace\" | \"remove\";\n\n/** Props for `useSelectionHandler` hook. */\ntype UseSelectionHandlerProps = Pick<ReturnType<typeof useTree>, \"rootNodes\" | \"selectNodes\"> & {\n /** Selection mode that the component is working in. */\n selectionMode: SelectionMode;\n};\n\n/** Result of `useSelectionHandler` hook. */\ninterface UseSelectionHandlerResult {\n /** Should be called by node renderer when a node component is clicked. */\n onNodeClick: (nodeId: string, isSelected: boolean, event: React.MouseEvent<HTMLElement, MouseEvent>) => void;\n /** Should be called by node renderer when a keyboard event happens on a node. */\n onNodeKeyDown: (nodeId: string, isSelected: boolean, event: React.KeyboardEvent<HTMLElement>) => void;\n}\n\ninterface FlatTreeState {\n flatNodeList: Array<string>;\n nodeIdToIndexMap: Map<string, number>;\n}\n\n/**\n * A react hook that helps implement different selection modes in a tree component created using `useTree` hook.\n * @beta\n */\nexport function useSelectionHandler(props: UseSelectionHandlerProps): UseSelectionHandlerResult {\n const { rootNodes, selectionMode, selectNodes } = props;\n const previousSelectionRef = useRef<string | undefined>(undefined);\n const state = useRef<FlatTreeState>({\n flatNodeList: [],\n nodeIdToIndexMap: new Map(),\n });\n\n useEffect(() => {\n if (!rootNodes) {\n return;\n }\n state.current = computeFlatNodeList(rootNodes);\n }, [rootNodes]);\n\n const getNodeRange = (firstId?: string, secondId?: string) => {\n const getIndex = (nodeId?: string) => {\n return nodeId ? state.current.nodeIdToIndexMap.get(nodeId) : 0;\n };\n const firstIndex = getIndex(firstId);\n const secondIndex = getIndex(secondId);\n if (firstIndex === undefined || secondIndex === undefined) {\n return [];\n }\n\n const startingIndex = Math.min(firstIndex, secondIndex);\n const endIndex = Math.max(firstIndex, secondIndex);\n return state.current.flatNodeList.slice(startingIndex, endIndex + 1);\n };\n\n const onNodeSelect = (nodeId: string, isSelected: boolean, shiftDown: boolean, ctrlDown: boolean) => {\n const selection = getSelectionAction(selectionMode, isSelected, shiftDown, ctrlDown);\n if (selection.type === \"disabled\") {\n return;\n }\n\n const nodes = selection.select === \"range\" ? getNodeRange(previousSelectionRef.current, nodeId) : [nodeId];\n if (!nodes.length) {\n return;\n }\n\n selection.select !== \"range\" && (previousSelectionRef.current = nodeId);\n selectNodes(nodes, selection.type);\n };\n\n const onNodeClick = (nodeId: string, isSelected: boolean, event: React.MouseEvent<HTMLElement, MouseEvent>) => {\n return onNodeSelect(nodeId, isSelected, event.shiftKey, event.ctrlKey);\n };\n\n const onNodeKeyDown = (nodeId: string, isSelected: boolean, event: React.KeyboardEvent<HTMLElement>) => {\n if (event.key === \" \" || event.key === \"Spacebar\" || event.key === \"Enter\") {\n return onNodeSelect(nodeId, isSelected, event.shiftKey, event.ctrlKey);\n }\n };\n\n return { onNodeClick, onNodeKeyDown };\n}\n\ninterface SelectionAction {\n select: \"node\" | \"range\";\n type: SelectionChangeType | \"disabled\";\n}\n\nfunction getSelectionAction(selectionMode: SelectionMode, isSelected: boolean, shiftDown: boolean, ctrlDown: boolean): SelectionAction {\n switch (selectionMode) {\n case \"none\":\n return { select: \"node\", type: \"disabled\" };\n case \"single\":\n return { select: \"node\", type: isSelected ? \"replace\" : \"remove\" };\n case \"multiple\":\n return { select: \"node\", type: isSelected ? \"add\" : \"remove\" };\n case \"extended\":\n return getExtendedSelectionAction(isSelected, shiftDown, ctrlDown);\n }\n}\n\nfunction getExtendedSelectionAction(isSelected: boolean, shiftDown: boolean, ctrlDown: boolean): SelectionAction {\n if (shiftDown) {\n return { select: \"range\", type: \"replace\" };\n }\n if (!isSelected) {\n return { select: \"node\", type: \"remove\" };\n }\n\n return { select: \"node\", type: ctrlDown ? \"add\" : \"replace\" };\n}\n\nfunction computeFlatNodeList(rootNodes: Array<PresentationTreeNode>): FlatTreeState {\n const flatNodeList: Array<string> = [];\n const nodeIdToIndexMap: Map<string, number> = new Map();\n\n const flattenNodeRecursively = (nodes: Array<PresentationTreeNode>) => {\n nodes.forEach((node) => {\n if (!isPresentationHierarchyNode(node)) {\n return;\n }\n nodeIdToIndexMap.set(node.id, flatNodeList.length);\n flatNodeList.push(node.id);\n if (node.isExpanded && typeof node.children !== \"boolean\") {\n flattenNodeRecursively(node.children);\n }\n });\n };\n\n flattenNodeRecursively(rootNodes);\n return { flatNodeList, nodeIdToIndexMap };\n}\n"]}
@@ -0,0 +1,85 @@
1
+ import { createHierarchyProvider, GenericInstanceFilter, HierarchyDefinition, HierarchyNode, HierarchyNodeIdentifiersPath, LimitingECSqlQueryExecutor } from "@itwin/presentation-hierarchies";
2
+ import { ECClassHierarchyInspector, ECSchemaProvider, InstanceKey, IPrimitiveValueFormatter } from "@itwin/presentation-shared";
3
+ import { UseUnifiedTreeSelectionProps } from "./internal/UseUnifiedSelection";
4
+ import { PresentationTreeNode } from "./TreeNode";
5
+ import { SelectionChangeType } from "./UseSelectionHandler";
6
+ /**
7
+ * A data structure that contains information about a single hierarchy level.
8
+ * @beta
9
+ */
10
+ export interface HierarchyLevelDetails {
11
+ /** The parent node whose hierarchy level's information is contained in this data structure */
12
+ hierarchyNode: HierarchyNode | undefined;
13
+ /** A function to get instance keys of the hierarchy level. */
14
+ getInstanceKeysIterator: (props?: {
15
+ instanceFilter?: GenericInstanceFilter;
16
+ hierarchyLevelSizeLimit?: number | "unbounded";
17
+ }) => AsyncIterableIterator<InstanceKey>;
18
+ /** Get the limit of how many nodes can be loaded in this hierarchy level. */
19
+ sizeLimit?: number | "unbounded";
20
+ /** Set the limit of how many nodes can be loaded in this hierarchy level. */
21
+ setSizeLimit: (value: undefined | number | "unbounded") => void;
22
+ /** Get the active instance filter applied to this hierarchy level. */
23
+ instanceFilter?: GenericInstanceFilter;
24
+ /** Set the instance filter to apply to this hierarchy level */
25
+ setInstanceFilter: (filter: GenericInstanceFilter | undefined) => void;
26
+ }
27
+ /**
28
+ * A React hook that creates state for a tree component.
29
+ *
30
+ * The hook uses `@itwin/presentation-hierarchies` package to load the hierarchy data and returns a
31
+ * component-agnostic result which may be used to render the hierarchy using any UI framework.
32
+ *
33
+ * See `README.md` for an example
34
+ *
35
+ * @see `useUnifiedSelectionTree`
36
+ * @beta
37
+ */
38
+ export declare function useTree(props: UseTreeProps): UseTreeResult;
39
+ /**
40
+ * A React hook that creates state for a tree component, that is integrated with unified selection
41
+ * through context provided by `UnifiedSelectionProvider`.
42
+ *
43
+ * The hook uses `@itwin/presentation-hierarchies` package to load the hierarchy data and returns a
44
+ * component-agnostic result which may be used to render the hierarchy using any UI framework.
45
+ *
46
+ * See `README.md` for an example
47
+ *
48
+ * @see `useTree`
49
+ * @see `UnifiedSelectionProvider`
50
+ * @beta
51
+ */
52
+ export declare function useUnifiedSelectionTree({ imodelKey, sourceName, ...props }: UseTreeProps & Omit<UseUnifiedTreeSelectionProps, "getNode">): UseTreeResult;
53
+ type IModelAccess = ECSchemaProvider & LimitingECSqlQueryExecutor & ECClassHierarchyInspector;
54
+ interface GetFilteredPathsProps {
55
+ imodelAccess: IModelAccess;
56
+ }
57
+ interface UseTreeProps {
58
+ imodelAccess: ECSchemaProvider & LimitingECSqlQueryExecutor & ECClassHierarchyInspector;
59
+ getHierarchyDefinition: (props: {
60
+ imodelAccess: IModelAccess;
61
+ }) => HierarchyDefinition;
62
+ getFilteredPaths?: (props: GetFilteredPathsProps) => Promise<HierarchyNodeIdentifiersPath[] | undefined>;
63
+ localizedStrings?: Parameters<typeof createHierarchyProvider>[0]["localizedStrings"];
64
+ }
65
+ interface UseTreeResult {
66
+ /**
67
+ * Array containing root tree nodes. It is `undefined` on initial render until any nodes are loaded.
68
+ */
69
+ rootNodes: PresentationTreeNode[] | undefined;
70
+ /**
71
+ * Specifies whether tree is loading or not. It is set to `true` when initial tree load is in progress
72
+ * or tree is reloading.
73
+ */
74
+ isLoading: boolean;
75
+ reloadTree: (options?: {
76
+ discardState?: boolean;
77
+ }) => void;
78
+ expandNode: (nodeId: string, isExpanded: boolean) => void;
79
+ selectNodes: (nodeIds: Array<string>, changeType: SelectionChangeType) => void;
80
+ isNodeSelected: (nodeId: string) => boolean;
81
+ getHierarchyLevelDetails: (nodeId: string | undefined) => HierarchyLevelDetails | undefined;
82
+ setFormatter: (formatter: IPrimitiveValueFormatter | undefined) => void;
83
+ }
84
+ export {};
85
+ //# sourceMappingURL=UseTree.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UseTree.d.ts","sourceRoot":"","sources":["../../../src/presentation-hierarchies-react/UseTree.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,209 @@
1
+ /*---------------------------------------------------------------------------------------------
2
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
3
+ * See LICENSE.md in the project root for license terms and full copyright notice.
4
+ *--------------------------------------------------------------------------------------------*/
5
+ import { useCallback, useEffect, useRef, useState } from "react";
6
+ import { createHierarchyProvider, HierarchyNode, } from "@itwin/presentation-hierarchies";
7
+ import { TreeActions } from "./internal/TreeActions";
8
+ import { isTreeModelHierarchyNode, isTreeModelInfoNode, TreeModel } from "./internal/TreeModel";
9
+ import { useUnifiedTreeSelection } from "./internal/UseUnifiedSelection";
10
+ /**
11
+ * A React hook that creates state for a tree component.
12
+ *
13
+ * The hook uses `@itwin/presentation-hierarchies` package to load the hierarchy data and returns a
14
+ * component-agnostic result which may be used to render the hierarchy using any UI framework.
15
+ *
16
+ * See `README.md` for an example
17
+ *
18
+ * @see `useUnifiedSelectionTree`
19
+ * @beta
20
+ */
21
+ export function useTree(props) {
22
+ const { getNode: _, ...rest } = useTreeInternal(props);
23
+ return rest;
24
+ }
25
+ /**
26
+ * A React hook that creates state for a tree component, that is integrated with unified selection
27
+ * through context provided by `UnifiedSelectionProvider`.
28
+ *
29
+ * The hook uses `@itwin/presentation-hierarchies` package to load the hierarchy data and returns a
30
+ * component-agnostic result which may be used to render the hierarchy using any UI framework.
31
+ *
32
+ * See `README.md` for an example
33
+ *
34
+ * @see `useTree`
35
+ * @see `UnifiedSelectionProvider`
36
+ * @beta
37
+ */
38
+ export function useUnifiedSelectionTree({ imodelKey, sourceName, ...props }) {
39
+ const { getNode, ...rest } = useTreeInternal(props);
40
+ return { ...rest, ...useUnifiedTreeSelection({ imodelKey, sourceName, getNode }) };
41
+ }
42
+ function useTreeInternal({ imodelAccess, getHierarchyDefinition, getFilteredPaths, localizedStrings, }) {
43
+ const [state, setState] = useState({
44
+ model: { idToNode: new Map(), parentChildMap: new Map(), rootNode: { id: undefined, nodeData: undefined } },
45
+ rootNodes: undefined,
46
+ });
47
+ const [hierarchySource, setHierarchySource] = useState({ isFiltering: false });
48
+ const [actions] = useState(() => new TreeActions((model) => {
49
+ const rootNodes = model.parentChildMap.get(undefined) !== undefined ? generateTreeStructure(undefined, model) : undefined;
50
+ setState({
51
+ model,
52
+ rootNodes,
53
+ });
54
+ }));
55
+ const currentFormatter = useRef();
56
+ useEffect(() => {
57
+ const updateHierarchyProvider = (provider) => {
58
+ actions.setHierarchyProvider(provider);
59
+ actions.reloadTree(undefined);
60
+ setHierarchySource({ hierarchyProvider: provider, isFiltering: false });
61
+ };
62
+ const createProvider = (paths) => {
63
+ return createHierarchyProvider({
64
+ imodelAccess,
65
+ hierarchyDefinition: getHierarchyDefinition({ imodelAccess }),
66
+ localizedStrings,
67
+ formatter: currentFormatter.current,
68
+ filtering: paths !== undefined
69
+ ? {
70
+ paths,
71
+ }
72
+ : undefined,
73
+ });
74
+ };
75
+ const loadHierarchyProvider = async () => {
76
+ if (!getFilteredPaths) {
77
+ return createProvider(undefined);
78
+ }
79
+ setHierarchySource((prev) => ({ ...prev, isFiltering: true }));
80
+ try {
81
+ const filteredPaths = await getFilteredPaths({ imodelAccess });
82
+ return createProvider(filteredPaths);
83
+ }
84
+ catch {
85
+ return createProvider(undefined);
86
+ }
87
+ };
88
+ let disposed = false;
89
+ void (async () => {
90
+ const provider = await loadHierarchyProvider();
91
+ if (disposed) {
92
+ return;
93
+ }
94
+ updateHierarchyProvider(provider);
95
+ })();
96
+ return () => {
97
+ disposed = true;
98
+ actions.dispose();
99
+ };
100
+ }, [actions, imodelAccess, localizedStrings, getHierarchyDefinition, getFilteredPaths]);
101
+ const getNode = useRef((nodeId) => {
102
+ return actions.getNode(nodeId);
103
+ }).current;
104
+ const expandNode = useRef((nodeId, isExpanded) => {
105
+ actions.expandNode(nodeId, isExpanded);
106
+ }).current;
107
+ const reloadTree = useRef((options) => {
108
+ actions.reloadTree(options);
109
+ }).current;
110
+ const selectNodes = useRef((nodeIds, changeType) => {
111
+ actions.selectNodes(nodeIds, changeType);
112
+ }).current;
113
+ const isNodeSelected = useCallback((nodeId) => TreeModel.isNodeSelected(state.model, nodeId), [state]);
114
+ const setFormatter = useCallback((formatter) => {
115
+ currentFormatter.current = formatter;
116
+ // istanbul ignore if
117
+ if (!hierarchySource.hierarchyProvider) {
118
+ return;
119
+ }
120
+ hierarchySource.hierarchyProvider.setFormatter(formatter);
121
+ actions.reloadTree();
122
+ }, [hierarchySource.hierarchyProvider, actions]);
123
+ const getHierarchyLevelDetails = useCallback((nodeId) => {
124
+ const node = actions.getNode(nodeId);
125
+ const hierarchyProvider = hierarchySource.hierarchyProvider;
126
+ if (!hierarchyProvider || !node || isTreeModelInfoNode(node)) {
127
+ return undefined;
128
+ }
129
+ const hierarchyNode = node.nodeData;
130
+ if (hierarchyNode && HierarchyNode.isGroupingNode(hierarchyNode)) {
131
+ return undefined;
132
+ }
133
+ return {
134
+ hierarchyNode,
135
+ getInstanceKeysIterator: (props) => hierarchyProvider.getNodeInstanceKeys({
136
+ parentNode: hierarchyNode,
137
+ instanceFilter: props?.instanceFilter,
138
+ hierarchyLevelSizeLimit: props?.hierarchyLevelSizeLimit,
139
+ }),
140
+ instanceFilter: node.instanceFilter,
141
+ setInstanceFilter: (filter) => actions.setInstanceFilter(nodeId, filter),
142
+ sizeLimit: node.hierarchyLimit,
143
+ setSizeLimit: (value) => actions.setHierarchyLimit(nodeId, value),
144
+ };
145
+ }, [actions, hierarchySource.hierarchyProvider]);
146
+ return {
147
+ rootNodes: state.rootNodes,
148
+ isLoading: !!state.model.rootNode.isLoading || hierarchySource.isFiltering,
149
+ expandNode,
150
+ reloadTree,
151
+ selectNodes,
152
+ isNodeSelected,
153
+ getNode,
154
+ getHierarchyLevelDetails,
155
+ setFormatter,
156
+ };
157
+ }
158
+ function generateTreeStructure(parentNodeId, model) {
159
+ const currentChildren = model.parentChildMap.get(parentNodeId);
160
+ if (!currentChildren) {
161
+ return undefined;
162
+ }
163
+ return currentChildren
164
+ .map((childId) => model.idToNode.get(childId))
165
+ .filter((node) => !!node)
166
+ .map((node) => {
167
+ if (isTreeModelHierarchyNode(node)) {
168
+ const children = generateTreeStructure(node.id, model);
169
+ return {
170
+ ...toPresentationHierarchyNodeBase(node),
171
+ children: children ? children : node.children === true ? true : [],
172
+ };
173
+ }
174
+ if (node.type === "ResultSetTooLarge") {
175
+ return {
176
+ id: node.id,
177
+ parentNodeId,
178
+ type: node.type,
179
+ resultSetSizeLimit: node.resultSetSizeLimit,
180
+ };
181
+ }
182
+ if (node.type === "NoFilterMatches") {
183
+ return {
184
+ id: node.id,
185
+ parentNodeId,
186
+ type: node.type,
187
+ };
188
+ }
189
+ return {
190
+ id: node.id,
191
+ parentNodeId,
192
+ type: node.type,
193
+ message: node.message,
194
+ };
195
+ });
196
+ }
197
+ function toPresentationHierarchyNodeBase(node) {
198
+ return {
199
+ id: node.id,
200
+ label: node.label,
201
+ nodeData: node.nodeData,
202
+ isLoading: !!node.isLoading,
203
+ isExpanded: !!node.isExpanded,
204
+ isFilterable: !HierarchyNode.isGroupingNode(node.nodeData) && !!node.nodeData.supportsFiltering && node.children,
205
+ isFiltered: !!node.instanceFilter,
206
+ extendedData: node.nodeData.extendedData,
207
+ };
208
+ }
209
+ //# sourceMappingURL=UseTree.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UseTree.js","sourceRoot":"","sources":["../../../src/presentation-hierarchies-react/UseTree.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n * See LICENSE.md in the project root for license terms and full copyright notice.\n *--------------------------------------------------------------------------------------------*/\n\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport {\n createHierarchyProvider,\n GenericInstanceFilter,\n HierarchyDefinition,\n HierarchyNode,\n HierarchyNodeIdentifiersPath,\n HierarchyProvider,\n LimitingECSqlQueryExecutor,\n} from \"@itwin/presentation-hierarchies\";\nimport { ECClassHierarchyInspector, ECSchemaProvider, InstanceKey, IPrimitiveValueFormatter } from \"@itwin/presentation-shared\";\nimport { TreeActions } from \"./internal/TreeActions\";\nimport { isTreeModelHierarchyNode, isTreeModelInfoNode, TreeModel, TreeModelHierarchyNode, TreeModelNode, TreeModelRootNode } from \"./internal/TreeModel\";\nimport { useUnifiedTreeSelection, UseUnifiedTreeSelectionProps } from \"./internal/UseUnifiedSelection\";\nimport { PresentationHierarchyNode, PresentationTreeNode } from \"./TreeNode\";\nimport { SelectionChangeType } from \"./UseSelectionHandler\";\n\n/**\n * A data structure that contains information about a single hierarchy level.\n * @beta\n */\nexport interface HierarchyLevelDetails {\n /** The parent node whose hierarchy level's information is contained in this data structure */\n hierarchyNode: HierarchyNode | undefined;\n\n /** A function to get instance keys of the hierarchy level. */\n getInstanceKeysIterator: (props?: {\n instanceFilter?: GenericInstanceFilter;\n hierarchyLevelSizeLimit?: number | \"unbounded\";\n }) => AsyncIterableIterator<InstanceKey>;\n\n /** Get the limit of how many nodes can be loaded in this hierarchy level. */\n sizeLimit?: number | \"unbounded\";\n /** Set the limit of how many nodes can be loaded in this hierarchy level. */\n setSizeLimit: (value: undefined | number | \"unbounded\") => void;\n\n /** Get the active instance filter applied to this hierarchy level. */\n instanceFilter?: GenericInstanceFilter;\n /** Set the instance filter to apply to this hierarchy level */\n setInstanceFilter: (filter: GenericInstanceFilter | undefined) => void;\n}\n\n/**\n * A React hook that creates state for a tree component.\n *\n * The hook uses `@itwin/presentation-hierarchies` package to load the hierarchy data and returns a\n * component-agnostic result which may be used to render the hierarchy using any UI framework.\n *\n * See `README.md` for an example\n *\n * @see `useUnifiedSelectionTree`\n * @beta\n */\nexport function useTree(props: UseTreeProps): UseTreeResult {\n const { getNode: _, ...rest } = useTreeInternal(props);\n return rest;\n}\n\n/**\n * A React hook that creates state for a tree component, that is integrated with unified selection\n * through context provided by `UnifiedSelectionProvider`.\n *\n * The hook uses `@itwin/presentation-hierarchies` package to load the hierarchy data and returns a\n * component-agnostic result which may be used to render the hierarchy using any UI framework.\n *\n * See `README.md` for an example\n *\n * @see `useTree`\n * @see `UnifiedSelectionProvider`\n * @beta\n */\nexport function useUnifiedSelectionTree({ imodelKey, sourceName, ...props }: UseTreeProps & Omit<UseUnifiedTreeSelectionProps, \"getNode\">): UseTreeResult {\n const { getNode, ...rest } = useTreeInternal(props);\n return { ...rest, ...useUnifiedTreeSelection({ imodelKey, sourceName, getNode }) };\n}\n\ntype IModelAccess = ECSchemaProvider & LimitingECSqlQueryExecutor & ECClassHierarchyInspector;\n\ninterface GetFilteredPathsProps {\n imodelAccess: IModelAccess;\n}\n\ninterface UseTreeProps {\n imodelAccess: ECSchemaProvider & LimitingECSqlQueryExecutor & ECClassHierarchyInspector;\n getHierarchyDefinition: (props: { imodelAccess: IModelAccess }) => HierarchyDefinition;\n getFilteredPaths?: (props: GetFilteredPathsProps) => Promise<HierarchyNodeIdentifiersPath[] | undefined>;\n localizedStrings?: Parameters<typeof createHierarchyProvider>[0][\"localizedStrings\"];\n}\n\ninterface UseTreeResult {\n /**\n * Array containing root tree nodes. It is `undefined` on initial render until any nodes are loaded.\n */\n rootNodes: PresentationTreeNode[] | undefined;\n /**\n * Specifies whether tree is loading or not. It is set to `true` when initial tree load is in progress\n * or tree is reloading.\n */\n isLoading: boolean;\n reloadTree: (options?: { discardState?: boolean }) => void;\n expandNode: (nodeId: string, isExpanded: boolean) => void;\n selectNodes: (nodeIds: Array<string>, changeType: SelectionChangeType) => void;\n isNodeSelected: (nodeId: string) => boolean;\n getHierarchyLevelDetails: (nodeId: string | undefined) => HierarchyLevelDetails | undefined;\n setFormatter: (formatter: IPrimitiveValueFormatter | undefined) => void;\n}\n\ninterface TreeState {\n model: TreeModel;\n rootNodes: Array<PresentationTreeNode> | undefined;\n}\n\nfunction useTreeInternal({\n imodelAccess,\n getHierarchyDefinition,\n getFilteredPaths,\n localizedStrings,\n}: UseTreeProps): UseTreeResult & { getNode: (nodeId: string) => TreeModelRootNode | TreeModelNode | undefined } {\n const [state, setState] = useState<TreeState>({\n model: { idToNode: new Map(), parentChildMap: new Map(), rootNode: { id: undefined, nodeData: undefined } },\n rootNodes: undefined,\n });\n const [hierarchySource, setHierarchySource] = useState<{ hierarchyProvider?: HierarchyProvider; isFiltering: boolean }>({ isFiltering: false });\n const [actions] = useState<TreeActions>(\n () =>\n new TreeActions((model) => {\n const rootNodes = model.parentChildMap.get(undefined) !== undefined ? generateTreeStructure(undefined, model) : undefined;\n setState({\n model,\n rootNodes,\n });\n }),\n );\n const currentFormatter = useRef<IPrimitiveValueFormatter>();\n\n useEffect(() => {\n const updateHierarchyProvider = (provider: HierarchyProvider) => {\n actions.setHierarchyProvider(provider);\n actions.reloadTree(undefined);\n setHierarchySource({ hierarchyProvider: provider, isFiltering: false });\n };\n\n const createProvider = (paths: HierarchyNodeIdentifiersPath[] | undefined) => {\n return createHierarchyProvider({\n imodelAccess,\n hierarchyDefinition: getHierarchyDefinition({ imodelAccess }),\n localizedStrings,\n formatter: currentFormatter.current,\n filtering:\n paths !== undefined\n ? {\n paths,\n }\n : undefined,\n });\n };\n\n const loadHierarchyProvider = async () => {\n if (!getFilteredPaths) {\n return createProvider(undefined);\n }\n\n setHierarchySource((prev) => ({ ...prev, isFiltering: true }));\n try {\n const filteredPaths = await getFilteredPaths({ imodelAccess });\n return createProvider(filteredPaths);\n } catch {\n return createProvider(undefined);\n }\n };\n\n let disposed = false;\n void (async () => {\n const provider = await loadHierarchyProvider();\n if (disposed) {\n return;\n }\n updateHierarchyProvider(provider);\n })();\n\n return () => {\n disposed = true;\n actions.dispose();\n };\n }, [actions, imodelAccess, localizedStrings, getHierarchyDefinition, getFilteredPaths]);\n\n const getNode = useRef((nodeId: string) => {\n return actions.getNode(nodeId);\n }).current;\n\n const expandNode = useRef((nodeId: string, isExpanded: boolean) => {\n actions.expandNode(nodeId, isExpanded);\n }).current;\n\n const reloadTree = useRef((options?: { discardState?: boolean }) => {\n actions.reloadTree(options);\n }).current;\n\n const selectNodes = useRef((nodeIds: Array<string>, changeType: SelectionChangeType) => {\n actions.selectNodes(nodeIds, changeType);\n }).current;\n\n const isNodeSelected = useCallback((nodeId: string) => TreeModel.isNodeSelected(state.model, nodeId), [state]);\n\n const setFormatter = useCallback(\n (formatter: IPrimitiveValueFormatter | undefined) => {\n currentFormatter.current = formatter;\n // istanbul ignore if\n if (!hierarchySource.hierarchyProvider) {\n return;\n }\n\n hierarchySource.hierarchyProvider.setFormatter(formatter);\n actions.reloadTree();\n },\n [hierarchySource.hierarchyProvider, actions],\n );\n\n const getHierarchyLevelDetails = useCallback<UseTreeResult[\"getHierarchyLevelDetails\"]>(\n (nodeId) => {\n const node = actions.getNode(nodeId);\n const hierarchyProvider = hierarchySource.hierarchyProvider;\n if (!hierarchyProvider || !node || isTreeModelInfoNode(node)) {\n return undefined;\n }\n const hierarchyNode = node.nodeData;\n if (hierarchyNode && HierarchyNode.isGroupingNode(hierarchyNode)) {\n return undefined;\n }\n\n return {\n hierarchyNode,\n getInstanceKeysIterator: (props) =>\n hierarchyProvider.getNodeInstanceKeys({\n parentNode: hierarchyNode,\n instanceFilter: props?.instanceFilter,\n hierarchyLevelSizeLimit: props?.hierarchyLevelSizeLimit,\n }),\n instanceFilter: node.instanceFilter,\n setInstanceFilter: (filter) => actions.setInstanceFilter(nodeId, filter),\n sizeLimit: node.hierarchyLimit,\n setSizeLimit: (value) => actions.setHierarchyLimit(nodeId, value),\n };\n },\n [actions, hierarchySource.hierarchyProvider],\n );\n\n return {\n rootNodes: state.rootNodes,\n isLoading: !!state.model.rootNode.isLoading || hierarchySource.isFiltering,\n expandNode,\n reloadTree,\n selectNodes,\n isNodeSelected,\n getNode,\n getHierarchyLevelDetails,\n setFormatter,\n };\n}\n\nfunction generateTreeStructure(parentNodeId: string | undefined, model: TreeModel): Array<PresentationTreeNode> | undefined {\n const currentChildren = model.parentChildMap.get(parentNodeId);\n if (!currentChildren) {\n return undefined;\n }\n\n return currentChildren\n .map((childId) => model.idToNode.get(childId))\n .filter((node): node is TreeModelNode => !!node)\n .map<PresentationTreeNode>((node) => {\n if (isTreeModelHierarchyNode(node)) {\n const children = generateTreeStructure(node.id, model);\n return {\n ...toPresentationHierarchyNodeBase(node),\n children: children ? children : node.children === true ? true : [],\n };\n }\n\n if (node.type === \"ResultSetTooLarge\") {\n return {\n id: node.id,\n parentNodeId,\n type: node.type,\n resultSetSizeLimit: node.resultSetSizeLimit,\n };\n }\n\n if (node.type === \"NoFilterMatches\") {\n return {\n id: node.id,\n parentNodeId,\n type: node.type,\n };\n }\n\n return {\n id: node.id,\n parentNodeId,\n type: node.type,\n message: node.message,\n };\n });\n}\n\nfunction toPresentationHierarchyNodeBase(node: TreeModelHierarchyNode): Omit<PresentationHierarchyNode, \"children\"> {\n return {\n id: node.id,\n label: node.label,\n nodeData: node.nodeData,\n isLoading: !!node.isLoading,\n isExpanded: !!node.isExpanded,\n isFilterable: !HierarchyNode.isGroupingNode(node.nodeData) && !!node.nodeData.supportsFiltering && node.children,\n isFiltered: !!node.instanceFilter,\n extendedData: node.nodeData.extendedData,\n };\n}\n"]}
@@ -0,0 +1,27 @@
1
+ import { GenericInstanceFilter, HierarchyProvider } from "@itwin/presentation-hierarchies";
2
+ import { SelectionChangeType } from "../UseSelectionHandler";
3
+ import { TreeModel, TreeModelNode, TreeModelRootNode } from "./TreeModel";
4
+ /** @internal */
5
+ export declare class TreeActions {
6
+ private _onModelChanged;
7
+ private _loader;
8
+ private _currentModel;
9
+ private _disposed;
10
+ constructor(_onModelChanged: (model: TreeModel) => void, seed?: TreeModel);
11
+ private updateTreeModel;
12
+ private handleLoadedHierarchy;
13
+ private onLoadingComplete;
14
+ private loadNodes;
15
+ private reloadSubTree;
16
+ dispose(): void;
17
+ setHierarchyProvider(provider?: HierarchyProvider): void;
18
+ getNode(nodeId: string | undefined): TreeModelNode | TreeModelRootNode | undefined;
19
+ selectNodes(nodeIds: Array<string>, changeType: SelectionChangeType): void;
20
+ expandNode(nodeId: string, isExpanded: boolean): void;
21
+ setHierarchyLimit(nodeId: string | undefined, limit?: number | "unbounded"): void;
22
+ setInstanceFilter(nodeId: string | undefined, filter?: GenericInstanceFilter): void;
23
+ reloadTree(options?: {
24
+ discardState?: boolean;
25
+ }): void;
26
+ }
27
+ //# sourceMappingURL=TreeActions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TreeActions.d.ts","sourceRoot":"","sources":["../../../../src/presentation-hierarchies-react/internal/TreeActions.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,qBAAqB,EAAiB,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAC1G,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAE7D,OAAO,EAAiD,SAAS,EAA0B,aAAa,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAKjJ,gBAAgB;AAChB,qBAAa,WAAW;IAMpB,OAAO,CAAC,eAAe;IALzB,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,aAAa,CAAY;IACjC,OAAO,CAAC,SAAS,CAAuB;gBAG9B,eAAe,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,EACnD,IAAI,CAAC,EAAE,SAAS;IAUlB,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,qBAAqB;IAM7B,OAAO,CAAC,iBAAiB;IAMzB,OAAO,CAAC,SAAS;IAyBjB,OAAO,CAAC,aAAa;IA8Cd,OAAO;IAIP,oBAAoB,CAAC,QAAQ,CAAC,EAAE,iBAAiB;IAIjD,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,aAAa,GAAG,iBAAiB,GAAG,SAAS;IAIlF,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,mBAAmB;IAMnE,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO;IAa9C,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,WAAW;IAc1E,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,CAAC,EAAE,qBAAqB;IAc5E,UAAU,CAAC,OAAO,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,OAAO,CAAA;KAAE;CAQvD"}