@itwin/presentation-hierarchies-react 2.0.0-alpha.5 → 2.0.0-alpha.51

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 (121) hide show
  1. package/CHANGELOG.md +902 -7
  2. package/README.md +28 -70
  3. package/lib/esm/presentation-hierarchies-react/Renderers.d.ts +85 -0
  4. package/lib/esm/presentation-hierarchies-react/Renderers.d.ts.map +1 -0
  5. package/lib/esm/presentation-hierarchies-react/Renderers.js +6 -0
  6. package/lib/esm/presentation-hierarchies-react/Renderers.js.map +1 -0
  7. package/lib/esm/presentation-hierarchies-react/TreeNode.d.ts +28 -29
  8. package/lib/esm/presentation-hierarchies-react/TreeNode.d.ts.map +1 -1
  9. package/lib/esm/presentation-hierarchies-react/TreeNode.js +1 -7
  10. package/lib/esm/presentation-hierarchies-react/TreeNode.js.map +1 -1
  11. package/lib/esm/presentation-hierarchies-react/UseIModelTree.d.ts +7 -5
  12. package/lib/esm/presentation-hierarchies-react/UseIModelTree.d.ts.map +1 -1
  13. package/lib/esm/presentation-hierarchies-react/UseIModelTree.js +6 -6
  14. package/lib/esm/presentation-hierarchies-react/UseIModelTree.js.map +1 -1
  15. package/lib/esm/presentation-hierarchies-react/UseNodeHighlighting.d.ts +24 -0
  16. package/lib/esm/presentation-hierarchies-react/UseNodeHighlighting.d.ts.map +1 -0
  17. package/lib/esm/presentation-hierarchies-react/UseNodeHighlighting.js +53 -0
  18. package/lib/esm/presentation-hierarchies-react/UseNodeHighlighting.js.map +1 -0
  19. package/lib/esm/presentation-hierarchies-react/UseSelectionHandler.d.ts +12 -10
  20. package/lib/esm/presentation-hierarchies-react/UseSelectionHandler.d.ts.map +1 -1
  21. package/lib/esm/presentation-hierarchies-react/UseSelectionHandler.js +7 -22
  22. package/lib/esm/presentation-hierarchies-react/UseSelectionHandler.js.map +1 -1
  23. package/lib/esm/presentation-hierarchies-react/UseTree.d.ts +33 -71
  24. package/lib/esm/presentation-hierarchies-react/UseTree.d.ts.map +1 -1
  25. package/lib/esm/presentation-hierarchies-react/UseTree.js +63 -64
  26. package/lib/esm/presentation-hierarchies-react/UseTree.js.map +1 -1
  27. package/lib/esm/presentation-hierarchies-react/Utils.d.ts +8 -0
  28. package/lib/esm/presentation-hierarchies-react/Utils.d.ts.map +1 -0
  29. package/lib/esm/presentation-hierarchies-react/Utils.js +39 -0
  30. package/lib/esm/presentation-hierarchies-react/Utils.js.map +1 -0
  31. package/lib/esm/presentation-hierarchies-react/internal/TreeActions.d.ts +2 -2
  32. package/lib/esm/presentation-hierarchies-react/internal/TreeActions.d.ts.map +1 -1
  33. package/lib/esm/presentation-hierarchies-react/internal/TreeActions.js +31 -16
  34. package/lib/esm/presentation-hierarchies-react/internal/TreeActions.js.map +1 -1
  35. package/lib/esm/presentation-hierarchies-react/internal/TreeLoader.d.ts +24 -6
  36. package/lib/esm/presentation-hierarchies-react/internal/TreeLoader.d.ts.map +1 -1
  37. package/lib/esm/presentation-hierarchies-react/internal/TreeLoader.js +29 -33
  38. package/lib/esm/presentation-hierarchies-react/internal/TreeLoader.js.map +1 -1
  39. package/lib/esm/presentation-hierarchies-react/internal/TreeModel.d.ts +6 -29
  40. package/lib/esm/presentation-hierarchies-react/internal/TreeModel.d.ts.map +1 -1
  41. package/lib/esm/presentation-hierarchies-react/internal/TreeModel.js +31 -27
  42. package/lib/esm/presentation-hierarchies-react/internal/TreeModel.js.map +1 -1
  43. package/lib/esm/presentation-hierarchies-react/internal/UseUnifiedSelection.d.ts +23 -9
  44. package/lib/esm/presentation-hierarchies-react/internal/UseUnifiedSelection.d.ts.map +1 -1
  45. package/lib/esm/presentation-hierarchies-react/internal/UseUnifiedSelection.js +16 -29
  46. package/lib/esm/presentation-hierarchies-react/internal/UseUnifiedSelection.js.map +1 -1
  47. package/lib/esm/presentation-hierarchies-react/internal/Utils.d.ts.map +1 -1
  48. package/lib/esm/presentation-hierarchies-react/internal/Utils.js.map +1 -1
  49. package/lib/esm/presentation-hierarchies-react/stratakit/ErrorItemRenderer.d.ts +27 -0
  50. package/lib/esm/presentation-hierarchies-react/stratakit/ErrorItemRenderer.d.ts.map +1 -0
  51. package/lib/esm/presentation-hierarchies-react/stratakit/ErrorItemRenderer.js +74 -0
  52. package/lib/esm/presentation-hierarchies-react/stratakit/ErrorItemRenderer.js.map +1 -0
  53. package/lib/esm/presentation-hierarchies-react/stratakit/FlatTreeNode.d.ts +48 -0
  54. package/lib/esm/presentation-hierarchies-react/stratakit/FlatTreeNode.d.ts.map +1 -0
  55. package/lib/esm/presentation-hierarchies-react/stratakit/FlatTreeNode.js +73 -0
  56. package/lib/esm/presentation-hierarchies-react/stratakit/FlatTreeNode.js.map +1 -0
  57. package/lib/esm/presentation-hierarchies-react/stratakit/LocalizationContext.d.ts +133 -0
  58. package/lib/esm/presentation-hierarchies-react/stratakit/LocalizationContext.d.ts.map +1 -0
  59. package/lib/esm/presentation-hierarchies-react/{itwinui → stratakit}/LocalizationContext.js +17 -5
  60. package/lib/esm/presentation-hierarchies-react/stratakit/LocalizationContext.js.map +1 -0
  61. package/lib/esm/presentation-hierarchies-react/stratakit/RootErrorRenderer.d.ts +16 -0
  62. package/lib/esm/presentation-hierarchies-react/stratakit/RootErrorRenderer.d.ts.map +1 -0
  63. package/lib/esm/presentation-hierarchies-react/stratakit/RootErrorRenderer.js +42 -0
  64. package/lib/esm/presentation-hierarchies-react/stratakit/RootErrorRenderer.js.map +1 -0
  65. package/lib/esm/presentation-hierarchies-react/stratakit/TreeAction.d.ts +45 -0
  66. package/lib/esm/presentation-hierarchies-react/stratakit/TreeAction.d.ts.map +1 -0
  67. package/lib/esm/presentation-hierarchies-react/stratakit/TreeAction.js +36 -0
  68. package/lib/esm/presentation-hierarchies-react/stratakit/TreeAction.js.map +1 -0
  69. package/lib/esm/presentation-hierarchies-react/stratakit/TreeErrorRenderer.d.ts +30 -0
  70. package/lib/esm/presentation-hierarchies-react/stratakit/TreeErrorRenderer.d.ts.map +1 -0
  71. package/lib/esm/presentation-hierarchies-react/stratakit/TreeErrorRenderer.js +30 -0
  72. package/lib/esm/presentation-hierarchies-react/stratakit/TreeErrorRenderer.js.map +1 -0
  73. package/lib/esm/presentation-hierarchies-react/stratakit/TreeNodeFilterAction.d.ts +20 -0
  74. package/lib/esm/presentation-hierarchies-react/stratakit/TreeNodeFilterAction.d.ts.map +1 -0
  75. package/lib/esm/presentation-hierarchies-react/stratakit/TreeNodeFilterAction.js +29 -0
  76. package/lib/esm/presentation-hierarchies-react/stratakit/TreeNodeFilterAction.js.map +1 -0
  77. package/lib/esm/presentation-hierarchies-react/stratakit/TreeNodeRenameAction.d.ts +57 -0
  78. package/lib/esm/presentation-hierarchies-react/stratakit/TreeNodeRenameAction.d.ts.map +1 -0
  79. package/lib/esm/presentation-hierarchies-react/stratakit/TreeNodeRenameAction.js +71 -0
  80. package/lib/esm/presentation-hierarchies-react/stratakit/TreeNodeRenameAction.js.map +1 -0
  81. package/lib/esm/presentation-hierarchies-react/stratakit/TreeNodeRenderer.css +25 -0
  82. package/lib/esm/presentation-hierarchies-react/stratakit/TreeNodeRenderer.d.ts +46 -0
  83. package/lib/esm/presentation-hierarchies-react/stratakit/TreeNodeRenderer.d.ts.map +1 -0
  84. package/lib/esm/presentation-hierarchies-react/stratakit/TreeNodeRenderer.js +132 -0
  85. package/lib/esm/presentation-hierarchies-react/stratakit/TreeNodeRenderer.js.map +1 -0
  86. package/lib/esm/presentation-hierarchies-react/stratakit/TreeRenderer.d.ts +75 -0
  87. package/lib/esm/presentation-hierarchies-react/stratakit/TreeRenderer.d.ts.map +1 -0
  88. package/lib/esm/presentation-hierarchies-react/stratakit/TreeRenderer.js +193 -0
  89. package/lib/esm/presentation-hierarchies-react/stratakit/TreeRenderer.js.map +1 -0
  90. package/lib/esm/presentation-hierarchies-react.d.ts +14 -10
  91. package/lib/esm/presentation-hierarchies-react.d.ts.map +1 -1
  92. package/lib/esm/presentation-hierarchies-react.js +11 -9
  93. package/lib/esm/presentation-hierarchies-react.js.map +1 -1
  94. package/package.json +55 -47
  95. package/lib/esm/presentation-hierarchies-react/UnifiedSelectionContext.d.ts +0 -15
  96. package/lib/esm/presentation-hierarchies-react/UnifiedSelectionContext.d.ts.map +0 -1
  97. package/lib/esm/presentation-hierarchies-react/UnifiedSelectionContext.js +0 -22
  98. package/lib/esm/presentation-hierarchies-react/UnifiedSelectionContext.js.map +0 -1
  99. package/lib/esm/presentation-hierarchies-react/itwinui/FlatTreeNode.d.ts +0 -21
  100. package/lib/esm/presentation-hierarchies-react/itwinui/FlatTreeNode.d.ts.map +0 -1
  101. package/lib/esm/presentation-hierarchies-react/itwinui/FlatTreeNode.js +0 -30
  102. package/lib/esm/presentation-hierarchies-react/itwinui/FlatTreeNode.js.map +0 -1
  103. package/lib/esm/presentation-hierarchies-react/itwinui/LocalizationContext.d.ts +0 -73
  104. package/lib/esm/presentation-hierarchies-react/itwinui/LocalizationContext.d.ts.map +0 -1
  105. package/lib/esm/presentation-hierarchies-react/itwinui/LocalizationContext.js.map +0 -1
  106. package/lib/esm/presentation-hierarchies-react/itwinui/TreeActionButton.d.ts +0 -25
  107. package/lib/esm/presentation-hierarchies-react/itwinui/TreeActionButton.d.ts.map +0 -1
  108. package/lib/esm/presentation-hierarchies-react/itwinui/TreeActionButton.js +0 -40
  109. package/lib/esm/presentation-hierarchies-react/itwinui/TreeActionButton.js.map +0 -1
  110. package/lib/esm/presentation-hierarchies-react/itwinui/TreeErrorRenderer.d.ts +0 -23
  111. package/lib/esm/presentation-hierarchies-react/itwinui/TreeErrorRenderer.d.ts.map +0 -1
  112. package/lib/esm/presentation-hierarchies-react/itwinui/TreeErrorRenderer.js +0 -72
  113. package/lib/esm/presentation-hierarchies-react/itwinui/TreeErrorRenderer.js.map +0 -1
  114. package/lib/esm/presentation-hierarchies-react/itwinui/TreeNodeRenderer.d.ts +0 -40
  115. package/lib/esm/presentation-hierarchies-react/itwinui/TreeNodeRenderer.d.ts.map +0 -1
  116. package/lib/esm/presentation-hierarchies-react/itwinui/TreeNodeRenderer.js +0 -80
  117. package/lib/esm/presentation-hierarchies-react/itwinui/TreeNodeRenderer.js.map +0 -1
  118. package/lib/esm/presentation-hierarchies-react/itwinui/TreeRenderer.d.ts +0 -30
  119. package/lib/esm/presentation-hierarchies-react/itwinui/TreeRenderer.d.ts.map +0 -1
  120. package/lib/esm/presentation-hierarchies-react/itwinui/TreeRenderer.js +0 -48
  121. package/lib/esm/presentation-hierarchies-react/itwinui/TreeRenderer.js.map +0 -1
@@ -0,0 +1,53 @@
1
+ import { jsx as _jsx, Fragment as _Fragment } 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 { useCallback } from "react";
7
+ import { HierarchyNode } from "@itwin/presentation-hierarchies";
8
+ /**
9
+ * A react hook that helps create highlighted node labels based on provided highlight.
10
+ * @alpha
11
+ */
12
+ export function useNodeHighlighting({ highlightText }) {
13
+ const getLabel = useCallback((node) => {
14
+ if (!highlightText || HierarchyNode.isGroupingNode(node.nodeData) || !node.nodeData.search?.isSearchTarget) {
15
+ return _jsx("span", { children: node.label });
16
+ }
17
+ const matchedIndexes = new Array();
18
+ const nodeLabel = node.label.toLocaleLowerCase();
19
+ const searchText = highlightText.toLocaleLowerCase();
20
+ let fromPosition = 0;
21
+ // Find all occurrences of the search text in the node label
22
+ while (true) {
23
+ const foundIndex = nodeLabel.indexOf(searchText, fromPosition);
24
+ if (foundIndex === -1) {
25
+ break;
26
+ }
27
+ matchedIndexes.push(foundIndex);
28
+ fromPosition = foundIndex + searchText.length;
29
+ }
30
+ if (matchedIndexes.length === 0) {
31
+ return _jsx("span", { children: node.label });
32
+ }
33
+ // Create the final label with highlighted parts
34
+ const finalLabel = new Array();
35
+ let lastAddedPosition = 0;
36
+ for (let i = 0; i < matchedIndexes.length; ++i) {
37
+ const matchedIndex = matchedIndexes[i];
38
+ if (matchedIndex > lastAddedPosition) {
39
+ finalLabel.push(_jsx("span", { children: node.label.substring(lastAddedPosition, matchedIndex) }, `normal-${i}`));
40
+ lastAddedPosition = matchedIndex;
41
+ }
42
+ const endingPlace = matchedIndex + highlightText.length;
43
+ finalLabel.push(_jsx("mark", { children: node.label.substring(lastAddedPosition, endingPlace) }, `marked-${i}`));
44
+ lastAddedPosition = endingPlace;
45
+ }
46
+ if (lastAddedPosition < node.label.length) {
47
+ finalLabel.push(_jsx("span", { children: node.label.substring(lastAddedPosition) }, `normal-${matchedIndexes.length + 1}`));
48
+ }
49
+ return _jsx(_Fragment, { children: finalLabel });
50
+ }, [highlightText]);
51
+ return { getLabel };
52
+ }
53
+ //# sourceMappingURL=UseNodeHighlighting.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UseNodeHighlighting.js","sourceRoot":"","sources":["../../../src/presentation-hierarchies-react/UseNodeHighlighting.tsx"],"names":[],"mappings":";AAAA;;;gGAGgG;AAEhG,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAqBhE;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,EAAE,aAAa,EAA4B;IAC7E,MAAM,QAAQ,GAAG,WAAW,CAC1B,CAAC,IAAc,EAAE,EAAE;QACjB,IAAI,CAAC,aAAa,IAAI,aAAa,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC;YAC3G,OAAO,yBAAO,IAAI,CAAC,KAAK,GAAQ,CAAC;QACnC,CAAC;QAED,MAAM,cAAc,GAAG,IAAI,KAAK,EAAU,CAAC;QAC3C,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,iBAAiB,EAAE,CAAC;QACjD,MAAM,UAAU,GAAG,aAAa,CAAC,iBAAiB,EAAE,CAAC;QACrD,IAAI,YAAY,GAAG,CAAC,CAAC;QACrB,4DAA4D;QAC5D,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,UAAU,GAAG,SAAS,CAAC,OAAO,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;YAC/D,IAAI,UAAU,KAAK,CAAC,CAAC,EAAE,CAAC;gBACtB,MAAM;YACR,CAAC;YACD,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAChC,YAAY,GAAG,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC;QAChD,CAAC;QAED,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAChC,OAAO,yBAAO,IAAI,CAAC,KAAK,GAAQ,CAAC;QACnC,CAAC;QAED,gDAAgD;QAChD,MAAM,UAAU,GAAG,IAAI,KAAK,EAAqB,CAAC;QAClD,IAAI,iBAAiB,GAAG,CAAC,CAAC;QAC1B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,cAAc,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC;YAC/C,MAAM,YAAY,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;YACvC,IAAI,YAAY,GAAG,iBAAiB,EAAE,CAAC;gBACrC,UAAU,CAAC,IAAI,CAAC,yBAA2B,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,iBAAiB,EAAE,YAAY,CAAC,IAArE,UAAU,CAAC,EAAE,CAAgE,CAAC,CAAC;gBAC1G,iBAAiB,GAAG,YAAY,CAAC;YACnC,CAAC;YACD,MAAM,WAAW,GAAG,YAAY,GAAG,aAAa,CAAC,MAAM,CAAC;YACxD,UAAU,CAAC,IAAI,CAAC,yBAA2B,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,iBAAiB,EAAE,WAAW,CAAC,IAApE,UAAU,CAAC,EAAE,CAA+D,CAAC,CAAC;YACzG,iBAAiB,GAAG,WAAW,CAAC;QAClC,CAAC;QACD,IAAI,iBAAiB,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;YAC1C,UAAU,CAAC,IAAI,CAAC,yBAAmD,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,iBAAiB,CAAC,IAA/E,UAAU,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAkD,CAAC,CAAC;QACtH,CAAC;QAED,OAAO,4BAAG,UAAU,GAAI,CAAC;IAC3B,CAAC,EACD,CAAC,aAAa,CAAC,CAChB,CAAC;IAEF,OAAO,EAAE,QAAQ,EAAE,CAAC;AACtB,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 { useCallback } from \"react\";\nimport { HierarchyNode } from \"@itwin/presentation-hierarchies\";\nimport { TreeNode } from \"./TreeNode.js\";\n\n/**\n * Props for `useNodeHighlighting` hook.\n * @alpha\n */\ninterface UseNodeHighlightingProps {\n /** Text that should be highlighted */\n highlightText?: string;\n}\n\n/**\n * Result of `useNodeHighlighting` hook.\n * @alpha\n */\ninterface UseNodeHighlightingResult {\n /** Function that creates highlighted node labels. */\n getLabel: (node: TreeNode) => React.ReactElement;\n}\n\n/**\n * A react hook that helps create highlighted node labels based on provided highlight.\n * @alpha\n */\nexport function useNodeHighlighting({ highlightText }: UseNodeHighlightingProps): UseNodeHighlightingResult {\n const getLabel = useCallback(\n (node: TreeNode) => {\n if (!highlightText || HierarchyNode.isGroupingNode(node.nodeData) || !node.nodeData.search?.isSearchTarget) {\n return <span>{node.label}</span>;\n }\n\n const matchedIndexes = new Array<number>();\n const nodeLabel = node.label.toLocaleLowerCase();\n const searchText = highlightText.toLocaleLowerCase();\n let fromPosition = 0;\n // Find all occurrences of the search text in the node label\n while (true) {\n const foundIndex = nodeLabel.indexOf(searchText, fromPosition);\n if (foundIndex === -1) {\n break;\n }\n matchedIndexes.push(foundIndex);\n fromPosition = foundIndex + searchText.length;\n }\n\n if (matchedIndexes.length === 0) {\n return <span>{node.label}</span>;\n }\n\n // Create the final label with highlighted parts\n const finalLabel = new Array<React.JSX.Element>();\n let lastAddedPosition = 0;\n for (let i = 0; i < matchedIndexes.length; ++i) {\n const matchedIndex = matchedIndexes[i];\n if (matchedIndex > lastAddedPosition) {\n finalLabel.push(<span key={`normal-${i}`}>{node.label.substring(lastAddedPosition, matchedIndex)}</span>);\n lastAddedPosition = matchedIndex;\n }\n const endingPlace = matchedIndex + highlightText.length;\n finalLabel.push(<mark key={`marked-${i}`}>{node.label.substring(lastAddedPosition, endingPlace)}</mark>);\n lastAddedPosition = endingPlace;\n }\n if (lastAddedPosition < node.label.length) {\n finalLabel.push(<span key={`normal-${matchedIndexes.length + 1}`}>{node.label.substring(lastAddedPosition)}</span>);\n }\n\n return <>{finalLabel}</>;\n },\n [highlightText],\n );\n\n return { getLabel };\n}\n"]}
@@ -1,5 +1,4 @@
1
- import { PresentationHierarchyNode } from "./TreeNode.js";
2
- import { useTree } from "./UseTree.js";
1
+ import { TreeRendererProps } from "./Renderers.js";
3
2
  /**
4
3
  * A union of different supported selection modes in a tree component:
5
4
  * - `none` - no selection is allowed,
@@ -21,25 +20,28 @@ export type SelectionMode = "none" | "single" | "extended" | "multiple";
21
20
  export type SelectionChangeType = "add" | "replace" | "remove";
22
21
  /**
23
22
  * Props for `useSelectionHandler` hook.
24
- * @public
23
+ * @alpha
25
24
  */
26
- type UseSelectionHandlerProps = Pick<ReturnType<typeof useTree>, "rootNodes" | "selectNodes"> & {
25
+ type UseSelectionHandlerProps = Pick<TreeRendererProps, "selectNodes" | "rootNodes"> & {
27
26
  /** Selection mode that the component is working in. */
28
27
  selectionMode: SelectionMode;
29
28
  };
30
29
  /**
31
30
  * Result of `useSelectionHandler` hook.
32
- * @public
31
+ * @internal
33
32
  */
34
33
  interface UseSelectionHandlerResult {
35
- /** Should be called by node renderer when a node component is clicked. */
36
- onNodeClick: (node: PresentationHierarchyNode, isSelected: boolean, event: React.MouseEvent<HTMLElement, MouseEvent>) => void;
37
- /** Should be called by node renderer when a keyboard event happens on a node. */
38
- onNodeKeyDown: (node: PresentationHierarchyNode, isSelected: boolean, event: React.KeyboardEvent<HTMLElement>) => void;
34
+ /** Updates nodes selection based on current node state and modifier keys used. */
35
+ handleNodeSelect: (props: {
36
+ nodeId: string;
37
+ isSelected: boolean;
38
+ shiftDown: boolean;
39
+ ctrlDown: boolean;
40
+ }) => void;
39
41
  }
40
42
  /**
41
43
  * A react hook that helps implement different selection modes in a tree component created using `useTree` hook.
42
- * @public
44
+ * @internal
43
45
  */
44
46
  export declare function useSelectionHandler(props: UseSelectionHandlerProps): UseSelectionHandlerResult;
45
47
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"UseSelectionHandler.d.ts","sourceRoot":"","sources":["../../../src/presentation-hierarchies-react/UseSelectionHandler.ts"],"names":[],"mappings":"AAMA,OAAO,EAA+B,yBAAyB,EAAwB,MAAM,eAAe,CAAC;AAC7G,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC;;;;;;;;GAQG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,GAAG,UAAU,CAAC;AAExE;;;;;;;GAOG;AACH,MAAM,MAAM,mBAAmB,GAAG,KAAK,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE/D;;;GAGG;AACH,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;;;GAGG;AACH,UAAU,yBAAyB;IACjC,0EAA0E;IAC1E,WAAW,EAAE,CAAC,IAAI,EAAE,yBAAyB,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,WAAW,EAAE,UAAU,CAAC,KAAK,IAAI,CAAC;IAC9H,iFAAiF;IACjF,aAAa,EAAE,CAAC,IAAI,EAAE,yBAAyB,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,aAAa,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;CACxH;AAOD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,wBAAwB,GAAG,yBAAyB,CAiE9F"}
1
+ {"version":3,"file":"UseSelectionHandler.d.ts","sourceRoot":"","sources":["../../../src/presentation-hierarchies-react/UseSelectionHandler.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAGnD;;;;;;;;GAQG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,GAAG,UAAU,CAAC;AAExE;;;;;;;GAOG;AACH,MAAM,MAAM,mBAAmB,GAAG,KAAK,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE/D;;;GAGG;AACH,KAAK,wBAAwB,GAAG,IAAI,CAAC,iBAAiB,EAAE,aAAa,GAAG,WAAW,CAAC,GAAG;IACrF,uDAAuD;IACvD,aAAa,EAAE,aAAa,CAAC;CAC9B,CAAC;AAEF;;;GAGG;AACH,UAAU,yBAAyB;IACjC,kFAAkF;IAClF,gBAAgB,EAAE,CAAC,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,OAAO,CAAC;QAAC,SAAS,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAC;CACnH;AAOD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,wBAAwB,GAAG,yBAAyB,CA8C9F"}
@@ -3,10 +3,9 @@
3
3
  * See LICENSE.md in the project root for license terms and full copyright notice.
4
4
  *--------------------------------------------------------------------------------------------*/
5
5
  import { useCallback, useEffect, useRef } from "react";
6
- import { isPresentationHierarchyNode } from "./TreeNode.js";
7
6
  /**
8
7
  * A react hook that helps implement different selection modes in a tree component created using `useTree` hook.
9
- * @public
8
+ * @internal
10
9
  */
11
10
  export function useSelectionHandler(props) {
12
11
  const { rootNodes, selectionMode, selectNodes } = props;
@@ -16,9 +15,6 @@ export function useSelectionHandler(props) {
16
15
  nodeIdToIndexMap: new Map(),
17
16
  });
18
17
  useEffect(() => {
19
- if (!rootNodes) {
20
- return;
21
- }
22
18
  state.current = computeFlatNodeList(rootNodes);
23
19
  }, [rootNodes]);
24
20
  const getNodeRange = (firstId, secondId) => {
@@ -34,7 +30,7 @@ export function useSelectionHandler(props) {
34
30
  const endIndex = Math.max(firstIndex, secondIndex);
35
31
  return state.current.flatNodeList.slice(startingIndex, endIndex + 1);
36
32
  };
37
- const onNodeSelect = useCallback((nodeId, isSelected, shiftDown, ctrlDown) => {
33
+ const handleNodeSelect = useCallback(({ nodeId, isSelected, shiftDown, ctrlDown }) => {
38
34
  const selection = getSelectionAction(selectionMode, isSelected, shiftDown, ctrlDown);
39
35
  if (selection.type === "disabled") {
40
36
  return;
@@ -46,24 +42,16 @@ export function useSelectionHandler(props) {
46
42
  selection.select !== "range" && (previousSelectionRef.current = nodeId);
47
43
  selectNodes(nodes, selection.type);
48
44
  }, [selectionMode, selectNodes]);
49
- const onNodeClick = useCallback((node, isSelected, event) => {
50
- return onNodeSelect(node.id, isSelected, event.shiftKey, event.ctrlKey);
51
- }, [onNodeSelect]);
52
- const onNodeKeyDown = useCallback((node, isSelected, event) => {
53
- if (event.key === " " || event.key === "Spacebar" || event.key === "Enter") {
54
- return onNodeSelect(node.id, isSelected, event.shiftKey, event.ctrlKey);
55
- }
56
- }, [onNodeSelect]);
57
- return { onNodeClick, onNodeKeyDown };
45
+ return { handleNodeSelect };
58
46
  }
59
47
  function getSelectionAction(selectionMode, isSelected, shiftDown, ctrlDown) {
60
48
  switch (selectionMode) {
61
49
  case "none":
62
50
  return { select: "node", type: "disabled" };
63
51
  case "single":
64
- return { select: "node", type: isSelected ? "replace" : "remove" };
52
+ return { select: "node", type: isSelected ? "remove" : "replace" };
65
53
  case "multiple":
66
- return { select: "node", type: isSelected ? "add" : "remove" };
54
+ return { select: "node", type: isSelected ? "remove" : "add" };
67
55
  case "extended":
68
56
  return getExtendedSelectionAction(isSelected, shiftDown, ctrlDown);
69
57
  }
@@ -73,18 +61,15 @@ function getExtendedSelectionAction(isSelected, shiftDown, ctrlDown) {
73
61
  return { select: "range", type: "replace" };
74
62
  }
75
63
  if (ctrlDown) {
76
- return { select: "node", type: isSelected ? "add" : "remove" };
64
+ return { select: "node", type: isSelected ? "remove" : "add" };
77
65
  }
78
- return { select: "node", type: isSelected ? "replace" : "disabled" };
66
+ return { select: "node", type: "replace" };
79
67
  }
80
68
  function computeFlatNodeList(rootNodes) {
81
69
  const flatNodeList = [];
82
70
  const nodeIdToIndexMap = new Map();
83
71
  const flattenNodeRecursively = (nodes) => {
84
72
  nodes.forEach((node) => {
85
- if (!isPresentationHierarchyNode(node)) {
86
- return;
87
- }
88
73
  nodeIdToIndexMap.set(node.id, flatNodeList.length);
89
74
  flatNodeList.push(node.id);
90
75
  if (node.isExpanded && typeof node.children !== "boolean") {
@@ -1 +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 { useCallback, useEffect, useRef } from \"react\";\nimport { isPresentationHierarchyNode, PresentationHierarchyNode, PresentationTreeNode } from \"./TreeNode.js\";\nimport { useTree } from \"./UseTree.js\";\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 * @public\n */\nexport type SelectionMode = \"none\" | \"single\" | \"extended\" | \"multiple\";\n\n/**\n * Type of selection change.\n * - `add` - a node was added to the selection,\n * - `replace` - a selected node was replaced with a different one,\n * - `remove` - a node was removed from the selection.\n *\n * @public\n */\nexport type SelectionChangeType = \"add\" | \"replace\" | \"remove\";\n\n/**\n * Props for `useSelectionHandler` hook.\n * @public\n */\ntype UseSelectionHandlerProps = Pick<ReturnType<typeof useTree>, \"rootNodes\" | \"selectNodes\"> & {\n /** Selection mode that the component is working in. */\n selectionMode: SelectionMode;\n};\n\n/**\n * Result of `useSelectionHandler` hook.\n * @public\n */\ninterface UseSelectionHandlerResult {\n /** Should be called by node renderer when a node component is clicked. */\n onNodeClick: (node: PresentationHierarchyNode, 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: (node: PresentationHierarchyNode, 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 * @public\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 = useCallback(\n (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 [selectionMode, selectNodes],\n );\n\n const onNodeClick = useCallback(\n (node: PresentationHierarchyNode, isSelected: boolean, event: React.MouseEvent<HTMLElement, MouseEvent>) => {\n return onNodeSelect(node.id, isSelected, event.shiftKey, event.ctrlKey);\n },\n [onNodeSelect],\n );\n\n const onNodeKeyDown = useCallback(\n (node: PresentationHierarchyNode, isSelected: boolean, event: React.KeyboardEvent<HTMLElement>) => {\n if (event.key === \" \" || event.key === \"Spacebar\" || event.key === \"Enter\") {\n return onNodeSelect(node.id, isSelected, event.shiftKey, event.ctrlKey);\n }\n },\n [onNodeSelect],\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 (ctrlDown) {\n return { select: \"node\", type: isSelected ? \"add\" : \"remove\" };\n }\n return { select: \"node\", type: isSelected ? \"replace\" : \"disabled\" };\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"]}
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 { useCallback, useEffect, useRef } from \"react\";\nimport { TreeRendererProps } from \"./Renderers.js\";\nimport { TreeNode } from \"./TreeNode.js\";\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 * @public\n */\nexport type SelectionMode = \"none\" | \"single\" | \"extended\" | \"multiple\";\n\n/**\n * Type of selection change.\n * - `add` - a node was added to the selection,\n * - `replace` - a selected node was replaced with a different one,\n * - `remove` - a node was removed from the selection.\n *\n * @public\n */\nexport type SelectionChangeType = \"add\" | \"replace\" | \"remove\";\n\n/**\n * Props for `useSelectionHandler` hook.\n * @alpha\n */\ntype UseSelectionHandlerProps = Pick<TreeRendererProps, \"selectNodes\" | \"rootNodes\"> & {\n /** Selection mode that the component is working in. */\n selectionMode: SelectionMode;\n};\n\n/**\n * Result of `useSelectionHandler` hook.\n * @internal\n */\ninterface UseSelectionHandlerResult {\n /** Updates nodes selection based on current node state and modifier keys used. */\n handleNodeSelect: (props: { nodeId: string; isSelected: boolean; shiftDown: boolean; ctrlDown: boolean }) => 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 * @internal\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 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 handleNodeSelect = useCallback<UseSelectionHandlerResult[\"handleNodeSelect\"]>(\n ({ nodeId, isSelected, shiftDown, ctrlDown }) => {\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 [selectionMode, selectNodes],\n );\n\n return { handleNodeSelect };\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 ? \"remove\" : \"replace\" };\n case \"multiple\":\n return { select: \"node\", type: isSelected ? \"remove\" : \"add\" };\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 (ctrlDown) {\n return { select: \"node\", type: isSelected ? \"remove\" : \"add\" };\n }\n return { select: \"node\", type: \"replace\" };\n}\n\nfunction computeFlatNodeList(rootNodes: Array<TreeNode>): FlatTreeState {\n const flatNodeList: Array<string> = [];\n const nodeIdToIndexMap: Map<string, number> = new Map();\n\n const flattenNodeRecursively = (nodes: Array<TreeNode>) => {\n nodes.forEach((node) => {\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"]}
@@ -1,29 +1,8 @@
1
- import { GenericInstanceFilter, HierarchyFilteringPath, HierarchyNode, HierarchyProvider } from "@itwin/presentation-hierarchies";
2
- import { InstanceKey, IPrimitiveValueFormatter } from "@itwin/presentation-shared";
1
+ import { GenericInstanceFilter, HierarchyProvider, HierarchySearchPath } from "@itwin/presentation-hierarchies";
2
+ import { IPrimitiveValueFormatter } from "@itwin/presentation-shared";
3
3
  import { UseUnifiedTreeSelectionProps } from "./internal/UseUnifiedSelection.js";
4
- import { PresentationHierarchyNode, PresentationTreeNode } from "./TreeNode.js";
5
- import { SelectionChangeType } from "./UseSelectionHandler.js";
6
- /**
7
- * A data structure that contains information about a single hierarchy level.
8
- * @public
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
- }
4
+ import { RootErrorRendererProps, TreeRendererProps } from "./Renderers.js";
5
+ import { TreeNode } from "./TreeNode.js";
27
6
  /**
28
7
  * A React hook that creates state for a tree component.
29
8
  *
@@ -52,13 +31,15 @@ export declare function useTree(props: UseTreeProps): UseTreeResult;
52
31
  * @see `UnifiedSelectionProvider`
53
32
  * @public
54
33
  */
55
- export declare function useUnifiedSelectionTree({ sourceName, selectionStorage, ...props }: UseTreeProps & UseUnifiedTreeSelectionProps): UseTreeResult;
34
+ export declare function useUnifiedSelectionTree({ sourceName, selectionStorage, createSelectableForGenericNode, ...props }: UseTreeProps & UseUnifiedTreeSelectionProps): UseTreeResult;
56
35
  /** @public */
57
36
  export interface UseTreeProps {
58
37
  /** Provides the hierarchy provider for the tree. */
59
38
  getHierarchyProvider: () => HierarchyProvider;
60
- /** Provides paths to filtered nodes. */
61
- getFilteredPaths?: () => Promise<HierarchyFilteringPath[] | undefined>;
39
+ /** Provides paths to search nodes. */
40
+ getSearchPaths?: ({ abortSignal }: {
41
+ abortSignal: AbortSignal;
42
+ }) => Promise<HierarchySearchPath[] | undefined>;
62
43
  /**
63
44
  * Callback that is called just after a certain action is finished.
64
45
  * Can be used for performance tracking.
@@ -77,56 +58,37 @@ export interface UseTreeProps {
77
58
  error: unknown;
78
59
  }) => void;
79
60
  }
80
- /**
81
- * Options for doing either full or a sub tree reload.
82
- * @public
83
- */
84
- interface ReloadTreeOptions {
85
- /** Specifies parent node under which sub tree should be reloaded. */
86
- parentNodeId: string | undefined;
87
- /**
88
- * Specifies how current tree state should be handled:
89
- * - `keep` - try to keep current tree state (expanded/collapsed nodes, instance filters, etc.).
90
- * - `discard` - do not try to keep current tree state. Tree model will be update after nodes are reloaded.
91
- * - `reset` - remove subtree from the model before reloading and reload nodes ignoring cache.
92
- *
93
- * Defaults to `"keep"`.
94
- */
95
- state?: "keep" | "discard" | "reset";
96
- }
97
61
  /** @public */
98
- export interface UseTreeResult {
99
- /**
100
- * Array containing root tree nodes. It is `undefined` on initial render until any nodes are loaded.
101
- */
102
- rootNodes: PresentationTreeNode[] | undefined;
62
+ export type UseTreeResult = {
103
63
  /**
104
- * Specifies whether tree is loading or not. It is set to `true` when initial tree load is in progress
64
+ * Specifies whether tree is reloading or not. It is set to `false` when initial tree load is in progress to check if
105
65
  * or tree is reloading.
106
66
  */
107
- isLoading: boolean;
108
- /**
109
- * A function that should be called to reload the tree.
110
- */
111
- reloadTree: (options?: ReloadTreeOptions) => void;
67
+ isReloading: boolean;
68
+ /** Get a tree node by id */
69
+ getNode: (nodeId: string) => TreeNode | undefined;
70
+ /** Sets a formatter for the primitive values that are displayed in the hierarchy. */
71
+ setFormatter: (formatter: IPrimitiveValueFormatter | undefined) => void;
72
+ } & RendererProps;
73
+ /**.
74
+ * @alpha
75
+ */
76
+ type RendererProps = {
112
77
  /**
113
- * A function that should be called to either expand or collapse the given node.
78
+ * An object containing information used to render root error handling UI.
79
+ * Use in combination with `RootErrorRenderer` or your custom implementation.
80
+ * Defined when root nodes fail to load.
114
81
  */
115
- expandNode: (nodeId: string, isExpanded: boolean) => void;
82
+ rootErrorRendererProps: RootErrorRendererProps;
83
+ } | {
84
+ /** Is undefined when rootNodes where successfully loaded or are in initial loading process */
85
+ rootErrorRendererProps: undefined;
116
86
  /**
117
- * A function that should be called to select nodes in the tree.
118
- * @param nodeIds Ids of the nodes that are selected.
119
- * @param changeType Type of change that occurred for the selection.
87
+ * An object containing information used to render tree.
88
+ * Use with `TreeRenderer` or your custom implementation.
89
+ * Is undefined on initial loading process.
120
90
  */
121
- selectNodes: (nodeIds: Array<string>, changeType: SelectionChangeType) => void;
122
- /** Determines whether a given node is selected. */
123
- isNodeSelected: (nodeId: string) => boolean;
124
- /** Get a tree node by id */
125
- getNode: (nodeId: string) => PresentationHierarchyNode | undefined;
126
- /** Returns hierarchy level details for a given node ID. */
127
- getHierarchyLevelDetails: (nodeId: string | undefined) => HierarchyLevelDetails | undefined;
128
- /** Sets a formatter for the primitive values that are displayed in the hierarchy. */
129
- setFormatter: (formatter: IPrimitiveValueFormatter | undefined) => void;
130
- }
91
+ treeRendererProps?: TreeRendererProps;
92
+ };
131
93
  export {};
132
94
  //# sourceMappingURL=UseTree.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"UseTree.d.ts","sourceRoot":"","sources":["../../../src/presentation-hierarchies-react/UseTree.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"UseTree.d.ts","sourceRoot":"","sources":["../../../src/presentation-hierarchies-react/UseTree.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,qBAAqB,EAAiB,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAC/H,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAGtE,OAAO,EAA2B,4BAA4B,EAAE,MAAM,mCAAmC,CAAC;AAE1G,OAAO,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAC3E,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAIzC;;;;;;;;;;;GAWG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,aAAa,CAG1D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,uBAAuB,CAAC,EACtC,UAAU,EACV,gBAAgB,EAChB,8BAA8B,EAC9B,GAAG,KAAK,EACT,EAAE,YAAY,GAAG,4BAA4B,GAAG,aAAa,CAa7D;AAED,cAAc;AACd,MAAM,WAAW,YAAY;IAC3B,oDAAoD;IACpD,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;IAC9C,sCAAsC;IACtC,cAAc,CAAC,EAAE,CAAC,EAAE,WAAW,EAAE,EAAE;QAAE,WAAW,EAAE,WAAW,CAAA;KAAE,KAAK,OAAO,CAAC,mBAAmB,EAAE,GAAG,SAAS,CAAC,CAAC;IAC/G;;;OAGG;IACH,qBAAqB,CAAC,EAAE,CAAC,MAAM,EAAE,cAAc,GAAG,sBAAsB,GAAG,QAAQ,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/G,2FAA2F;IAC3F,wBAAwB,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,qBAAqB,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,GAAG,WAAW,CAAA;KAAE,KAAK,IAAI,CAAC;IAChI,sEAAsE;IACtE,oBAAoB,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,SAAS,GAAG,SAAS,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAC;CAC5G;AAED,cAAc;AACd,MAAM,MAAM,aAAa,GAAG;IAC1B;;;OAGG;IACH,WAAW,EAAE,OAAO,CAAC;IACrB,4BAA4B;IAC5B,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,QAAQ,GAAG,SAAS,CAAC;IAClD,qFAAqF;IACrF,YAAY,EAAE,CAAC,SAAS,EAAE,wBAAwB,GAAG,SAAS,KAAK,IAAI,CAAC;CACzE,GAAG,aAAa,CAAC;AAElB;;GAEG;AACH,KAAK,aAAa,GACd;IACE;;;;OAIG;IACH,sBAAsB,EAAE,sBAAsB,CAAC;CAChD,GACD;IACE,8FAA8F;IAC9F,sBAAsB,EAAE,SAAS,CAAC;IAClC;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;CACvC,CAAC"}
@@ -2,12 +2,13 @@
2
2
  * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
3
3
  * See LICENSE.md in the project root for license terms and full copyright notice.
4
4
  *--------------------------------------------------------------------------------------------*/
5
- import { useCallback, useEffect, useRef, useState } from "react";
5
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
6
6
  import { HierarchyNode } from "@itwin/presentation-hierarchies";
7
7
  import { TreeActions } from "./internal/TreeActions.js";
8
- import { isTreeModelHierarchyNode, isTreeModelInfoNode, TreeModel } from "./internal/TreeModel.js";
8
+ import { TreeModel } from "./internal/TreeModel.js";
9
9
  import { useUnifiedTreeSelection } from "./internal/UseUnifiedSelection.js";
10
10
  import { safeDispose } from "./internal/Utils.js";
11
+ import { useLatest } from "./Utils.js";
11
12
  /**
12
13
  * A React hook that creates state for a tree component.
13
14
  *
@@ -39,14 +40,21 @@ export function useTree(props) {
39
40
  * @see `UnifiedSelectionProvider`
40
41
  * @public
41
42
  */
42
- export function useUnifiedSelectionTree({ sourceName, selectionStorage, ...props }) {
43
+ export function useUnifiedSelectionTree({ sourceName, selectionStorage, createSelectableForGenericNode, ...props }) {
43
44
  const { getTreeModelNode, ...rest } = useTreeInternal(props);
44
- return {
45
- ...rest,
46
- ...useUnifiedTreeSelection({ sourceName, selectionStorage, getTreeModelNode }),
47
- };
45
+ const selectionProps = useUnifiedTreeSelection({ sourceName, selectionStorage, getTreeModelNode, createSelectableForGenericNode });
46
+ if (rest.rootErrorRendererProps === undefined && rest.treeRendererProps?.rootNodes) {
47
+ return {
48
+ ...rest,
49
+ treeRendererProps: {
50
+ ...rest.treeRendererProps,
51
+ ...selectionProps,
52
+ },
53
+ };
54
+ }
55
+ return rest;
48
56
  }
49
- function useTreeInternal({ getHierarchyProvider, getFilteredPaths, onPerformanceMeasured, onHierarchyLimitExceeded, onHierarchyLoadError, }) {
57
+ function useTreeInternal({ getHierarchyProvider, getSearchPaths, onPerformanceMeasured, onHierarchyLimitExceeded, onHierarchyLoadError, }) {
50
58
  const [state, setState] = useState({
51
59
  model: { idToNode: new Map(), parentChildMap: new Map(), rootNode: { id: undefined, nodeData: undefined } },
52
60
  rootNodes: undefined,
@@ -67,7 +75,7 @@ function useTreeInternal({ getHierarchyProvider, getFilteredPaths, onPerformance
67
75
  const provider = getHierarchyProvider();
68
76
  provider.setFormatter(currentFormatter.current);
69
77
  const removeHierarchyChangedListener = provider.hierarchyChanged.addListener((hierarchyChangeArgs) => {
70
- const shouldDiscardState = hierarchyChangeArgs?.filterChange?.newFilter !== undefined;
78
+ const shouldDiscardState = hierarchyChangeArgs?.searchChange?.newSearch !== undefined;
71
79
  actions.reloadTree({ state: shouldDiscardState ? "discard" : "keep" });
72
80
  });
73
81
  actions.setHierarchyProvider(provider);
@@ -78,47 +86,49 @@ function useTreeInternal({ getHierarchyProvider, getFilteredPaths, onPerformance
78
86
  safeDispose(provider);
79
87
  };
80
88
  }, [actions, getHierarchyProvider]);
81
- const [isFiltering, setIsFiltering] = useState(false);
89
+ const [isSearching, setIsSearching] = useState(false);
82
90
  useEffect(() => {
83
91
  let disposed = false;
92
+ const controller = new AbortController();
84
93
  void (async () => {
85
94
  if (!hierarchyProvider) {
86
95
  return;
87
96
  }
88
- if (!getFilteredPaths) {
89
- hierarchyProvider.setHierarchyFilter(undefined);
90
- // reload tree in case hierarchy provider does not use hierarchy filter to load initial nodes
97
+ if (!getSearchPaths) {
98
+ hierarchyProvider.setHierarchySearch(undefined);
99
+ // reload tree in case hierarchy provider does not use hierarchy search to load initial nodes
91
100
  actions.reloadTree({ state: "keep" });
92
- setIsFiltering(false);
101
+ setIsSearching(false);
93
102
  return;
94
103
  }
95
- setIsFiltering(true);
104
+ setIsSearching(true);
96
105
  let paths;
97
106
  try {
98
- paths = await getFilteredPaths();
107
+ paths = await getSearchPaths({ abortSignal: controller.signal });
99
108
  }
100
109
  catch {
101
110
  }
102
111
  finally {
103
112
  if (!disposed) {
104
- hierarchyProvider.setHierarchyFilter(paths ? { paths } : undefined);
105
- setIsFiltering(false);
113
+ hierarchyProvider.setHierarchySearch(paths ? { paths } : undefined);
114
+ setIsSearching(false);
106
115
  }
107
116
  }
108
117
  })();
109
118
  return () => {
119
+ controller.abort();
110
120
  disposed = true;
111
121
  };
112
- }, [hierarchyProvider, getFilteredPaths, actions]);
122
+ }, [hierarchyProvider, getSearchPaths, actions]);
113
123
  const getTreeModelNode = useCallback((nodeId) => {
114
124
  return actions.getNode(nodeId);
115
125
  }, [actions]);
116
126
  const getNode = useCallback((nodeId) => {
117
127
  const node = actions.getNode(nodeId);
118
- if (!node || !isTreeModelHierarchyNode(node)) {
128
+ if (!node || node.id === undefined) {
119
129
  return undefined;
120
130
  }
121
- return createPresentationHierarchyNode(node, state.model);
131
+ return createTreeNode(node, state.model);
122
132
  }, [actions, state.model]);
123
133
  const expandNode = useCallback((nodeId, isExpanded) => {
124
134
  actions.expandNode(nodeId, isExpanded);
@@ -140,7 +150,7 @@ function useTreeInternal({ getHierarchyProvider, getFilteredPaths, onPerformance
140
150
  }, [hierarchyProvider]);
141
151
  const getHierarchyLevelDetails = useCallback((nodeId) => {
142
152
  const node = actions.getNode(nodeId);
143
- if (!hierarchyProvider || !node || isTreeModelInfoNode(node)) {
153
+ if (!hierarchyProvider || !node) {
144
154
  return undefined;
145
155
  }
146
156
  const hierarchyNode = node.nodeData;
@@ -160,16 +170,35 @@ function useTreeInternal({ getHierarchyProvider, getFilteredPaths, onPerformance
160
170
  setSizeLimit: (value) => actions.setHierarchyLimit(nodeId, value),
161
171
  };
162
172
  }, [actions, hierarchyProvider]);
173
+ const renderProps = useMemo(() => {
174
+ if (state.model.rootNode.error) {
175
+ return {
176
+ rootErrorRendererProps: {
177
+ error: state.model.rootNode.error,
178
+ reloadTree,
179
+ getHierarchyLevelDetails,
180
+ },
181
+ };
182
+ }
183
+ return {
184
+ rootErrorRendererProps: undefined,
185
+ treeRendererProps: state.rootNodes
186
+ ? {
187
+ rootNodes: state.rootNodes,
188
+ expandNode,
189
+ selectNodes,
190
+ isNodeSelected,
191
+ reloadTree,
192
+ getHierarchyLevelDetails,
193
+ }
194
+ : undefined,
195
+ };
196
+ }, [expandNode, getHierarchyLevelDetails, isNodeSelected, reloadTree, selectNodes, state.model.rootNode.error, state.rootNodes]);
163
197
  return {
164
- rootNodes: state.rootNodes,
165
- isLoading: !!state.model.rootNode.isLoading || isFiltering,
166
- expandNode,
167
- reloadTree,
168
- selectNodes,
169
- isNodeSelected,
198
+ ...renderProps,
199
+ isReloading: !!state.model.rootNode.isLoading || isSearching,
170
200
  getTreeModelNode,
171
201
  getNode,
172
- getHierarchyLevelDetails,
173
202
  setFormatter,
174
203
  };
175
204
  }
@@ -182,36 +211,13 @@ function generateTreeStructure(parentNodeId, model) {
182
211
  .map((childId) => model.idToNode.get(childId))
183
212
  .filter((node) => !!node)
184
213
  .map((node) => {
185
- if (isTreeModelHierarchyNode(node)) {
186
- return createPresentationHierarchyNode(node, model);
187
- }
188
- if (node.type === "ResultSetTooLarge") {
189
- return {
190
- id: node.id,
191
- parentNodeId,
192
- type: node.type,
193
- resultSetSizeLimit: node.resultSetSizeLimit,
194
- };
195
- }
196
- if (node.type === "NoFilterMatches") {
197
- return {
198
- id: node.id,
199
- parentNodeId,
200
- type: node.type,
201
- };
202
- }
203
- return {
204
- id: node.id,
205
- parentNodeId,
206
- type: node.type,
207
- message: node.message,
208
- };
214
+ return createTreeNode(node, model);
209
215
  });
210
216
  }
211
- function createPresentationHierarchyNode(modelNode, model) {
217
+ function createTreeNode(modelNode, model) {
212
218
  let children;
213
219
  return {
214
- ...toPresentationHierarchyNodeBase(modelNode),
220
+ ...toTreeNodeBase(modelNode),
215
221
  get children() {
216
222
  if (!children) {
217
223
  children = generateTreeStructure(modelNode.id, model);
@@ -220,7 +226,7 @@ function createPresentationHierarchyNode(modelNode, model) {
220
226
  },
221
227
  };
222
228
  }
223
- function toPresentationHierarchyNodeBase(node) {
229
+ function toTreeNodeBase(node) {
224
230
  return {
225
231
  id: node.id,
226
232
  label: node.label,
@@ -229,14 +235,7 @@ function toPresentationHierarchyNodeBase(node) {
229
235
  isExpanded: !!node.isExpanded,
230
236
  isFilterable: !HierarchyNode.isGroupingNode(node.nodeData) && !!node.nodeData.supportsFiltering && node.children,
231
237
  isFiltered: !!node.instanceFilter,
232
- extendedData: node.nodeData.extendedData,
238
+ error: node.error,
233
239
  };
234
240
  }
235
- function useLatest(value) {
236
- const ref = useRef(value);
237
- useEffect(() => {
238
- ref.current = value;
239
- }, [value]);
240
- return ref;
241
- }
242
241
  //# sourceMappingURL=UseTree.js.map