@itwin/tree-widget-react 4.0.0-alpha.17 → 4.0.0-alpha.19

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 (169) hide show
  1. package/CHANGELOG.md +51 -1
  2. package/lib/esm/tree-widget-react/TreeWidget.d.ts +1 -3
  3. package/lib/esm/tree-widget-react/TreeWidget.js +19 -19
  4. package/lib/esm/tree-widget-react/TreeWidget.js.map +1 -1
  5. package/lib/esm/tree-widget-react/components/TreeWidgetComponentImpl.d.ts +1 -0
  6. package/lib/esm/tree-widget-react/components/TreeWidgetComponentImpl.js +1 -1
  7. package/lib/esm/tree-widget-react/components/TreeWidgetComponentImpl.js.map +1 -1
  8. package/lib/esm/tree-widget-react/components/TreeWidgetUiItemsProvider.js +1 -1
  9. package/lib/esm/tree-widget-react/components/TreeWidgetUiItemsProvider.js.map +1 -1
  10. package/lib/esm/tree-widget-react/components/tree-header/SearchBox.js +2 -2
  11. package/lib/esm/tree-widget-react/components/tree-header/SearchBox.js.map +1 -1
  12. package/lib/esm/tree-widget-react/components/tree-header/SelectableTree.js.map +1 -1
  13. package/lib/esm/tree-widget-react/components/tree-header/WidgetHeader.js.map +1 -1
  14. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTree.d.ts +3 -3
  15. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTree.js +2 -2
  16. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTree.js.map +1 -1
  17. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeButtons.d.ts +0 -2
  18. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeButtons.js +13 -11
  19. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeButtons.js.map +1 -1
  20. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeComponent.d.ts +1 -1
  21. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeComponent.js +2 -2
  22. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeComponent.js.map +1 -1
  23. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.d.ts +6 -10
  24. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.js +137 -92
  25. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.js.map +1 -1
  26. package/lib/esm/tree-widget-react/components/trees/categories-tree/UseCategoriesTree.js +12 -4
  27. package/lib/esm/tree-widget-react/components/trees/categories-tree/UseCategoriesTree.js.map +1 -1
  28. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.d.ts +30 -29
  29. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.js +405 -355
  30. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.js.map +1 -1
  31. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/UseFilteredPaths.d.ts +5 -3
  32. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/UseFilteredPaths.js +8 -6
  33. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/UseFilteredPaths.js.map +1 -1
  34. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/visibility/CategoriesTreeVisibilityHandler.d.ts +4 -1
  35. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/visibility/CategoriesTreeVisibilityHandler.js +20 -12
  36. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/visibility/CategoriesTreeVisibilityHandler.js.map +1 -1
  37. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/visibility/CategoriesTreeVisibilityHelper.d.ts +3 -1
  38. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/visibility/CategoriesTreeVisibilityHelper.js +13 -3
  39. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/visibility/CategoriesTreeVisibilityHelper.js.map +1 -1
  40. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/visibility/FilteredTree.d.ts +4 -1
  41. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/visibility/FilteredTree.js +8 -7
  42. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/visibility/FilteredTree.js.map +1 -1
  43. package/lib/esm/tree-widget-react/components/trees/classifications-tree/ClassificationsTree.d.ts +2 -2
  44. package/lib/esm/tree-widget-react/components/trees/classifications-tree/ClassificationsTree.js +6 -2
  45. package/lib/esm/tree-widget-react/components/trees/classifications-tree/ClassificationsTree.js.map +1 -1
  46. package/lib/esm/tree-widget-react/components/trees/classifications-tree/ClassificationsTreeComponent.d.ts +1 -1
  47. package/lib/esm/tree-widget-react/components/trees/classifications-tree/ClassificationsTreeComponent.js +2 -2
  48. package/lib/esm/tree-widget-react/components/trees/classifications-tree/ClassificationsTreeComponent.js.map +1 -1
  49. package/lib/esm/tree-widget-react/components/trees/classifications-tree/ClassificationsTreeDefinition.d.ts +3 -5
  50. package/lib/esm/tree-widget-react/components/trees/classifications-tree/ClassificationsTreeDefinition.js +45 -38
  51. package/lib/esm/tree-widget-react/components/trees/classifications-tree/ClassificationsTreeDefinition.js.map +1 -1
  52. package/lib/esm/tree-widget-react/components/trees/classifications-tree/UseClassificationsTree.js +8 -2
  53. package/lib/esm/tree-widget-react/components/trees/classifications-tree/UseClassificationsTree.js.map +1 -1
  54. package/lib/esm/tree-widget-react/components/trees/classifications-tree/internal/ClassificationsTreeIdsCache.d.ts +14 -20
  55. package/lib/esm/tree-widget-react/components/trees/classifications-tree/internal/ClassificationsTreeIdsCache.js +271 -275
  56. package/lib/esm/tree-widget-react/components/trees/classifications-tree/internal/ClassificationsTreeIdsCache.js.map +1 -1
  57. package/lib/esm/tree-widget-react/components/trees/classifications-tree/internal/UseFilteredPaths.d.ts +4 -2
  58. package/lib/esm/tree-widget-react/components/trees/classifications-tree/internal/UseFilteredPaths.js +3 -2
  59. package/lib/esm/tree-widget-react/components/trees/classifications-tree/internal/UseFilteredPaths.js.map +1 -1
  60. package/lib/esm/tree-widget-react/components/trees/classifications-tree/internal/visibility/ClassificationsTreeVisibilityHandler.js +22 -15
  61. package/lib/esm/tree-widget-react/components/trees/classifications-tree/internal/visibility/ClassificationsTreeVisibilityHandler.js.map +1 -1
  62. package/lib/esm/tree-widget-react/components/trees/classifications-tree/internal/visibility/ClassificationsTreeVisibilityHelper.js +5 -5
  63. package/lib/esm/tree-widget-react/components/trees/classifications-tree/internal/visibility/ClassificationsTreeVisibilityHelper.js.map +1 -1
  64. package/lib/esm/tree-widget-react/components/trees/classifications-tree/internal/visibility/FilteredTree.d.ts +7 -2
  65. package/lib/esm/tree-widget-react/components/trees/classifications-tree/internal/visibility/FilteredTree.js +15 -12
  66. package/lib/esm/tree-widget-react/components/trees/classifications-tree/internal/visibility/FilteredTree.js.map +1 -1
  67. package/lib/esm/tree-widget-react/components/trees/common/UseHierarchyVisibility.js.map +1 -1
  68. package/lib/esm/tree-widget-react/components/trees/common/Utils.d.ts +2 -1
  69. package/lib/esm/tree-widget-react/components/trees/common/Utils.js +8 -3
  70. package/lib/esm/tree-widget-react/components/trees/common/Utils.js.map +1 -1
  71. package/lib/esm/tree-widget-react/components/trees/common/components/EmptyTree.js +4 -4
  72. package/lib/esm/tree-widget-react/components/trees/common/components/EmptyTree.js.map +1 -1
  73. package/lib/esm/tree-widget-react/components/trees/common/components/ProgressOverlay.js.map +1 -1
  74. package/lib/esm/tree-widget-react/components/trees/common/components/SkeletonTree.d.ts +4 -1
  75. package/lib/esm/tree-widget-react/components/trees/common/components/SkeletonTree.js +4 -1
  76. package/lib/esm/tree-widget-react/components/trees/common/components/SkeletonTree.js.map +1 -1
  77. package/lib/esm/tree-widget-react/components/trees/common/components/Tree.js.map +1 -1
  78. package/lib/esm/tree-widget-react/components/trees/common/components/TreeNodeVisibilityButton.js.map +1 -1
  79. package/lib/esm/tree-widget-react/components/trees/common/components/VisibilityTree.d.ts +2 -2
  80. package/lib/esm/tree-widget-react/components/trees/common/components/VisibilityTree.js.map +1 -1
  81. package/lib/esm/tree-widget-react/components/trees/common/internal/AlwaysAndNeverDrawnElementInfo.d.ts +55 -18
  82. package/lib/esm/tree-widget-react/components/trees/common/internal/AlwaysAndNeverDrawnElementInfo.js +96 -76
  83. package/lib/esm/tree-widget-react/components/trees/common/internal/AlwaysAndNeverDrawnElementInfo.js.map +1 -1
  84. package/lib/esm/tree-widget-react/components/trees/common/internal/ModelCategoryElementsCountCache.d.ts +5 -8
  85. package/lib/esm/tree-widget-react/components/trees/common/internal/ModelCategoryElementsCountCache.js +52 -39
  86. package/lib/esm/tree-widget-react/components/trees/common/internal/ModelCategoryElementsCountCache.js.map +1 -1
  87. package/lib/esm/tree-widget-react/components/trees/common/internal/UseIModelAccess.d.ts +1 -1
  88. package/lib/esm/tree-widget-react/components/trees/common/internal/UseIModelAccess.js.map +1 -1
  89. package/lib/esm/tree-widget-react/components/trees/common/internal/Utils.d.ts +29 -4
  90. package/lib/esm/tree-widget-react/components/trees/common/internal/Utils.js +49 -4
  91. package/lib/esm/tree-widget-react/components/trees/common/internal/Utils.js.map +1 -1
  92. package/lib/esm/tree-widget-react/components/trees/common/internal/VisibilityUtils.d.ts +2 -7
  93. package/lib/esm/tree-widget-react/components/trees/common/internal/VisibilityUtils.js +30 -39
  94. package/lib/esm/tree-widget-react/components/trees/common/internal/VisibilityUtils.js.map +1 -1
  95. package/lib/esm/tree-widget-react/components/trees/common/internal/useGuid.d.ts +3 -0
  96. package/lib/esm/tree-widget-react/components/trees/common/internal/useGuid.js +12 -0
  97. package/lib/esm/tree-widget-react/components/trees/common/internal/useGuid.js.map +1 -0
  98. package/lib/esm/tree-widget-react/components/trees/common/internal/useTreeHooks/UseCachedVisibility.d.ts +5 -1
  99. package/lib/esm/tree-widget-react/components/trees/common/internal/useTreeHooks/UseCachedVisibility.js +25 -13
  100. package/lib/esm/tree-widget-react/components/trees/common/internal/useTreeHooks/UseCachedVisibility.js.map +1 -1
  101. package/lib/esm/tree-widget-react/components/trees/common/internal/useTreeHooks/UseIdsCache.d.ts +3 -0
  102. package/lib/esm/tree-widget-react/components/trees/common/internal/useTreeHooks/UseIdsCache.js +7 -7
  103. package/lib/esm/tree-widget-react/components/trees/common/internal/useTreeHooks/UseIdsCache.js.map +1 -1
  104. package/lib/esm/tree-widget-react/components/trees/common/internal/visibility/BaseFilteredTree.d.ts +8 -4
  105. package/lib/esm/tree-widget-react/components/trees/common/internal/visibility/BaseFilteredTree.js +16 -11
  106. package/lib/esm/tree-widget-react/components/trees/common/internal/visibility/BaseFilteredTree.js.map +1 -1
  107. package/lib/esm/tree-widget-react/components/trees/common/internal/visibility/BaseVisibilityHelper.d.ts +2 -1
  108. package/lib/esm/tree-widget-react/components/trees/common/internal/visibility/BaseVisibilityHelper.js +44 -28
  109. package/lib/esm/tree-widget-react/components/trees/common/internal/visibility/BaseVisibilityHelper.js.map +1 -1
  110. package/lib/esm/tree-widget-react/components/trees/common/useGuid.d.ts +2 -0
  111. package/lib/esm/tree-widget-react/components/trees/common/useGuid.js +11 -0
  112. package/lib/esm/tree-widget-react/components/trees/common/useGuid.js.map +1 -0
  113. package/lib/esm/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTree.d.ts +2 -2
  114. package/lib/esm/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTree.js +5 -2
  115. package/lib/esm/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTree.js.map +1 -1
  116. package/lib/esm/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTreeComponent.d.ts +2 -2
  117. package/lib/esm/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTreeComponent.js +2 -2
  118. package/lib/esm/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTreeComponent.js.map +1 -1
  119. package/lib/esm/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTreeDefinition.d.ts +4 -6
  120. package/lib/esm/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTreeDefinition.js +31 -26
  121. package/lib/esm/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTreeDefinition.js.map +1 -1
  122. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/IModelContentTree.d.ts +3 -3
  123. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/IModelContentTree.js +6 -4
  124. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/IModelContentTree.js.map +1 -1
  125. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/IModelContentTreeComponent.d.ts +2 -2
  126. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/IModelContentTreeComponent.js +2 -2
  127. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/IModelContentTreeComponent.js.map +1 -1
  128. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/IModelContentTreeDefinition.d.ts +1 -5
  129. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/IModelContentTreeDefinition.js +44 -44
  130. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/IModelContentTreeDefinition.js.map +1 -1
  131. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/internal/IModelContentTreeIdsCache.d.ts +3 -6
  132. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/internal/IModelContentTreeIdsCache.js +20 -16
  133. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/internal/IModelContentTreeIdsCache.js.map +1 -1
  134. package/lib/esm/tree-widget-react/components/trees/index.d.ts +1 -0
  135. package/lib/esm/tree-widget-react/components/trees/index.js +1 -0
  136. package/lib/esm/tree-widget-react/components/trees/index.js.map +1 -1
  137. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTree.d.ts +3 -3
  138. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTree.js +2 -2
  139. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTree.js.map +1 -1
  140. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeButtons.js +6 -3
  141. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeButtons.js.map +1 -1
  142. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeComponent.d.ts +1 -1
  143. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeComponent.js +2 -2
  144. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeComponent.js.map +1 -1
  145. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.d.ts +6 -10
  146. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.js +111 -69
  147. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.js.map +1 -1
  148. package/lib/esm/tree-widget-react/components/trees/models-tree/UseModelsTree.js +7 -2
  149. package/lib/esm/tree-widget-react/components/trees/models-tree/UseModelsTree.js.map +1 -1
  150. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.d.ts +17 -25
  151. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js +246 -265
  152. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js.map +1 -1
  153. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeNode.d.ts +1 -1
  154. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeNode.js.map +1 -1
  155. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/UseFilteredPaths.d.ts +3 -2
  156. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/UseFilteredPaths.js +9 -3
  157. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/UseFilteredPaths.js.map +1 -1
  158. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/visibility/FilteredTree.d.ts +4 -1
  159. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/visibility/FilteredTree.js +6 -6
  160. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/visibility/FilteredTree.js.map +1 -1
  161. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/visibility/ModelsTreeVisibilityHandler.js +17 -11
  162. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/visibility/ModelsTreeVisibilityHandler.js.map +1 -1
  163. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/visibility/ModelsTreeVisibilityHelper.js +3 -3
  164. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/visibility/ModelsTreeVisibilityHelper.js.map +1 -1
  165. package/lib/esm/tree-widget-react-internal.d.ts +2 -1
  166. package/lib/esm/tree-widget-react-internal.js +2 -1
  167. package/lib/esm/tree-widget-react-internal.js.map +1 -1
  168. package/lib/public/locales/en/TreeWidget.json +1 -1
  169. package/package.json +12 -12
@@ -3,8 +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, useState } from "react";
6
- import { defaultIfEmpty, EMPTY, filter, firstValueFrom, from, fromEventPattern, map, mergeMap, of, Subject, takeUntil, tap } from "rxjs";
7
- import { HierarchyNodeKey } from "@itwin/presentation-hierarchies";
6
+ import { defaultIfEmpty, EMPTY, filter, firstValueFrom, from, fromEventPattern, map, mergeMap, Subject, takeUntil, tap } from "rxjs";
7
+ import { assert } from "@itwin/core-bentley";
8
+ import { HierarchyNode, HierarchyNodeKey } from "@itwin/presentation-hierarchies";
8
9
  import { HierarchyVisibilityOverrideHandler } from "../../UseHierarchyVisibility.js";
9
10
  import { AlwaysAndNeverDrawnElementInfo } from "../AlwaysAndNeverDrawnElementInfo.js";
10
11
  import { toVoidPromise } from "../Rxjs.js";
@@ -13,13 +14,14 @@ import { createVisibilityChangeEventListener } from "../VisibilityChangeEventLis
13
14
  /** @internal */
14
15
  export function useCachedVisibility(props) {
15
16
  const [filteredPaths, setFilteredPaths] = useState(undefined);
16
- const { activeView, getCache, createFilteredTree, createTreeSpecificVisibilityHandler } = props;
17
+ const { activeView, getCache, createFilteredTree, createTreeSpecificVisibilityHandler, componentId } = props;
17
18
  const [visibilityHandlerFactory, setVisibilityHandlerFactory] = useState(() => createVisibilityHandlerFactory({
18
19
  activeView,
19
20
  getCache,
20
21
  createFilteredTree,
21
22
  createTreeSpecificVisibilityHandler,
22
23
  filteringPaths: filteredPaths,
24
+ componentId,
23
25
  }));
24
26
  useEffect(() => {
25
27
  setVisibilityHandlerFactory(() => createVisibilityHandlerFactory({
@@ -28,8 +30,9 @@ export function useCachedVisibility(props) {
28
30
  createFilteredTree,
29
31
  createTreeSpecificVisibilityHandler,
30
32
  filteringPaths: filteredPaths,
33
+ componentId,
31
34
  }));
32
- }, [activeView, getCache, filteredPaths, createFilteredTree, createTreeSpecificVisibilityHandler]);
35
+ }, [activeView, getCache, filteredPaths, createFilteredTree, createTreeSpecificVisibilityHandler, componentId]);
33
36
  return {
34
37
  visibilityHandlerFactory,
35
38
  onFilteredPathsChanged: useCallback((paths) => setFilteredPaths(paths), []),
@@ -37,8 +40,9 @@ export function useCachedVisibility(props) {
37
40
  };
38
41
  }
39
42
  function createVisibilityHandlerFactory(props) {
40
- const { activeView, createFilteredTree, createTreeSpecificVisibilityHandler, getCache, filteringPaths } = props;
43
+ const { activeView, createFilteredTree, createTreeSpecificVisibilityHandler, getCache, filteringPaths, componentId } = props;
41
44
  return ({ imodelAccess }) => new HierarchyVisibilityHandlerImpl({
45
+ componentId,
42
46
  viewport: activeView,
43
47
  getFilteredTree: () => {
44
48
  if (filteringPaths) {
@@ -80,7 +84,7 @@ export class HierarchyVisibilityHandlerImpl {
80
84
  displayStyle: true,
81
85
  },
82
86
  });
83
- this.#alwaysAndNeverDrawnElements = new AlwaysAndNeverDrawnElementInfo(this.#props.viewport);
87
+ this.#alwaysAndNeverDrawnElements = new AlwaysAndNeverDrawnElementInfo({ viewport: this.#props.viewport, componentId: props.componentId });
84
88
  this.#treeSpecificVisibilityHandler = this.#props.getTreeSpecificVisibilityHandler(this.#alwaysAndNeverDrawnElements, new HierarchyVisibilityOverrideHandler(this));
85
89
  this.#filteredTree = this.#props.getFilteredTree();
86
90
  }
@@ -121,13 +125,23 @@ export class HierarchyVisibilityHandlerImpl {
121
125
  this.#treeSpecificVisibilityHandler[Symbol.dispose]();
122
126
  }
123
127
  getVisibilityStatusInternal(node) {
124
- if (node.filtering?.filteredChildrenIdentifierPaths?.length && !node.filtering.isFilterTarget) {
128
+ if (HierarchyNode.isClassGroupingNode(node)) {
129
+ if (node.extendedData?.hasDirectNonFilteredTargets && !node.filtering?.hasFilterTargetAncestor) {
130
+ return this.getFilteredNodeVisibility({ node });
131
+ }
132
+ }
133
+ if (HierarchyNode.isInstancesNode(node) && node.filtering?.filteredChildrenIdentifierPaths?.length && !node.filtering.isFilterTarget) {
125
134
  return this.getFilteredNodeVisibility({ node });
126
135
  }
127
136
  return this.#treeSpecificVisibilityHandler.getVisibilityStatus(node);
128
137
  }
129
138
  changeVisibilityStatusInternal(node, on) {
130
- if (node.filtering?.filteredChildrenIdentifierPaths?.length && !node.filtering.isFilterTarget) {
139
+ if (HierarchyNode.isClassGroupingNode(node)) {
140
+ if (node.extendedData?.hasDirectNonFilteredTargets && !node.filtering?.hasFilterTargetAncestor) {
141
+ return this.changeFilteredNodeVisibility({ node, on });
142
+ }
143
+ }
144
+ if (HierarchyNode.isInstancesNode(node) && node.filtering?.filteredChildrenIdentifierPaths?.length && !node.filtering.isFilterTarget) {
131
145
  return this.changeFilteredNodeVisibility({ node, on });
132
146
  }
133
147
  return this.#treeSpecificVisibilityHandler.changeVisibilityStatus(node, on);
@@ -140,13 +154,11 @@ export class HierarchyVisibilityHandlerImpl {
140
154
  return this.#treeSpecificVisibilityHandler.getFilterTargetsVisibilityStatus(targets);
141
155
  }));
142
156
  }
143
- getFilteredTreeTargets({ node }) {
144
- if (!this.#filteredTree) {
145
- return of(undefined);
146
- }
157
+ getFilteredTreeTargets({ node, }) {
158
+ assert(this.#filteredTree !== undefined);
147
159
  return from(this.#filteredTree).pipe(map((filteredTree) => filteredTree.getFilterTargets(node)));
148
160
  }
149
- changeFilteredNodeVisibility({ on, node }) {
161
+ changeFilteredNodeVisibility({ on, node, }) {
150
162
  return this.getFilteredTreeTargets({ node }).pipe(mergeMap((targets) => {
151
163
  if (!targets) {
152
164
  return EMPTY;
@@ -1 +1 @@
1
- {"version":3,"file":"UseCachedVisibility.js","sourceRoot":"","sources":["../../../../../../../../src/tree-widget-react/components/trees/common/internal/useTreeHooks/UseCachedVisibility.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, useState } from \"react\";\nimport { defaultIfEmpty, EMPTY, filter, firstValueFrom, from, fromEventPattern, map, mergeMap, of, Subject, takeUntil, tap } from \"rxjs\";\nimport { HierarchyNodeKey } from \"@itwin/presentation-hierarchies\";\nimport { HierarchyVisibilityOverrideHandler } from \"../../UseHierarchyVisibility.js\";\nimport { AlwaysAndNeverDrawnElementInfo } from \"../AlwaysAndNeverDrawnElementInfo.js\";\nimport { toVoidPromise } from \"../Rxjs.js\";\nimport { createVisibilityStatus } from \"../Tooltip.js\";\nimport { createVisibilityChangeEventListener } from \"../VisibilityChangeEventListener.js\";\n\nimport type { Observable } from \"rxjs\";\nimport type { HierarchyFilteringPath, HierarchyNode } from \"@itwin/presentation-hierarchies\";\nimport type { ECClassHierarchyInspector } from \"@itwin/presentation-shared\";\nimport type { VisibilityTreeProps } from \"../../components/VisibilityTree.js\";\nimport type { TreeWidgetViewport } from \"../../TreeWidgetViewport.js\";\nimport type { HierarchyVisibilityHandler, VisibilityStatus } from \"../../UseHierarchyVisibility.js\";\nimport type { FilteredTree } from \"../visibility/BaseFilteredTree.js\";\nimport type { TreeSpecificVisibilityHandler } from \"../visibility/BaseVisibilityHelper.js\";\nimport type { IVisibilityChangeEventListener } from \"../VisibilityChangeEventListener.js\";\n\n/** @internal */\nexport interface CreateFilteredTreeProps<TCache> {\n getCache: () => TCache;\n imodelAccess: ECClassHierarchyInspector;\n filteringPaths: HierarchyFilteringPath[];\n}\n\n/** @internal */\nexport interface CreateTreeSpecificVisibilityHandlerProps<TCache> {\n info: AlwaysAndNeverDrawnElementInfo;\n getCache: () => TCache;\n viewport: TreeWidgetViewport;\n overrideHandler: HierarchyVisibilityOverrideHandler;\n}\n\n/** @internal */\nexport interface UseCachedVisibilityProps<TCache, TFilterTargets> {\n activeView: TreeWidgetViewport;\n getCache: () => TCache;\n createFilteredTree: (props: CreateFilteredTreeProps<TCache>) => Promise<FilteredTree<TFilterTargets>>;\n createTreeSpecificVisibilityHandler: (props: CreateTreeSpecificVisibilityHandlerProps<TCache>) => TreeSpecificVisibilityHandler<TFilterTargets> & Disposable;\n}\n\n/** @internal */\nexport function useCachedVisibility<TCache, TFilterTargets>(props: UseCachedVisibilityProps<TCache, TFilterTargets>) {\n const [filteredPaths, setFilteredPaths] = useState<HierarchyFilteringPath[] | undefined>(undefined);\n const { activeView, getCache, createFilteredTree, createTreeSpecificVisibilityHandler } = props;\n\n const [visibilityHandlerFactory, setVisibilityHandlerFactory] = useState<VisibilityTreeProps[\"visibilityHandlerFactory\"]>(() =>\n createVisibilityHandlerFactory({\n activeView,\n getCache,\n createFilteredTree,\n createTreeSpecificVisibilityHandler,\n filteringPaths: filteredPaths,\n }),\n );\n\n useEffect(() => {\n setVisibilityHandlerFactory(() =>\n createVisibilityHandlerFactory({\n activeView,\n getCache,\n createFilteredTree,\n createTreeSpecificVisibilityHandler,\n filteringPaths: filteredPaths,\n }),\n );\n }, [activeView, getCache, filteredPaths, createFilteredTree, createTreeSpecificVisibilityHandler]);\n\n return {\n visibilityHandlerFactory,\n onFilteredPathsChanged: useCallback((paths: HierarchyFilteringPath[] | undefined) => setFilteredPaths(paths), []),\n filteredPaths,\n };\n}\n\nfunction createVisibilityHandlerFactory<TCache, TFilterTargets>(\n props: UseCachedVisibilityProps<TCache, TFilterTargets> & {\n filteringPaths: HierarchyFilteringPath[] | undefined;\n },\n): VisibilityTreeProps[\"visibilityHandlerFactory\"] {\n const { activeView, createFilteredTree, createTreeSpecificVisibilityHandler, getCache, filteringPaths } = props;\n return ({ imodelAccess }) =>\n new HierarchyVisibilityHandlerImpl<TFilterTargets>({\n viewport: activeView,\n getFilteredTree: (): Promise<FilteredTree<TFilterTargets>> | undefined => {\n if (filteringPaths) {\n return createFilteredTree({ imodelAccess, filteringPaths, getCache });\n }\n return undefined;\n },\n getTreeSpecificVisibilityHandler: (info, overrideHandler) =>\n createTreeSpecificVisibilityHandler({\n info,\n getCache,\n viewport: activeView,\n overrideHandler,\n }),\n });\n}\n\n/** @internal */\nexport interface HierarchyVisibilityHandlerImplProps<TFilterTargets> {\n viewport: TreeWidgetViewport;\n getTreeSpecificVisibilityHandler: (\n info: AlwaysAndNeverDrawnElementInfo,\n overrideHandler: HierarchyVisibilityOverrideHandler,\n ) => TreeSpecificVisibilityHandler<TFilterTargets> & Disposable;\n getFilteredTree: () => Promise<FilteredTree<TFilterTargets>> | undefined;\n}\n\n/**\n * Class that handles visibility of hierarchy nodes in a tree.\n *\n * - It provides methods to get and change visibility status of nodes.\n * - Also handles filtered tree nodes visibility.\n * - Listens to visibility change events and updates visibility status accordingly.\n * @internal\n */\nexport class HierarchyVisibilityHandlerImpl<TFilterTargets> implements HierarchyVisibilityHandler, Disposable {\n readonly #props: HierarchyVisibilityHandlerImplProps<TFilterTargets>;\n readonly #eventListener: IVisibilityChangeEventListener;\n readonly #alwaysAndNeverDrawnElements: AlwaysAndNeverDrawnElementInfo;\n #treeSpecificVisibilityHandler: TreeSpecificVisibilityHandler<TFilterTargets> & Disposable;\n #changeRequest = new Subject<{ key: HierarchyNodeKey; depth: number }>();\n #filteredTree: Promise<FilteredTree<TFilterTargets>> | undefined;\n\n constructor(props: HierarchyVisibilityHandlerImplProps<TFilterTargets>) {\n this.#props = props;\n this.#eventListener = createVisibilityChangeEventListener({\n viewport: this.#props.viewport,\n listeners: {\n models: true,\n categories: true,\n elements: true,\n displayStyle: true,\n },\n });\n this.#alwaysAndNeverDrawnElements = new AlwaysAndNeverDrawnElementInfo(this.#props.viewport);\n this.#treeSpecificVisibilityHandler = this.#props.getTreeSpecificVisibilityHandler(\n this.#alwaysAndNeverDrawnElements,\n new HierarchyVisibilityOverrideHandler(this),\n );\n this.#filteredTree = this.#props.getFilteredTree();\n }\n\n public get onVisibilityChange() {\n return this.#eventListener.onVisibilityChange;\n }\n\n public async getVisibilityStatus(node: HierarchyNode): Promise<VisibilityStatus> {\n return firstValueFrom(\n this.getVisibilityStatusInternal(node).pipe(\n // unsubscribe from the observable if the change request for this node is received\n takeUntil(this.#changeRequest.pipe(filter(({ key, depth }) => depth === node.parentKeys.length && HierarchyNodeKey.equals(node.key, key)))),\n // unsubscribe if visibility changes\n takeUntil(\n fromEventPattern(\n (handler) => {\n this.#eventListener.onVisibilityChange.addListener(handler);\n },\n (handler) => {\n this.#eventListener.onVisibilityChange.removeListener(handler);\n },\n ),\n ),\n defaultIfEmpty(createVisibilityStatus(\"hidden\")),\n ),\n );\n }\n\n public async changeVisibility(node: HierarchyNode, shouldDisplay: boolean): Promise<void> {\n // notify about new change request\n this.#changeRequest.next({ key: node.key, depth: node.parentKeys.length });\n\n const changeObservable = this.changeVisibilityStatusInternal(node, shouldDisplay).pipe(\n // unsubscribe from the observable if the change request for this node is received\n takeUntil(this.#changeRequest.pipe(filter(({ key, depth }) => depth === node.parentKeys.length && HierarchyNodeKey.equals(node.key, key)))),\n tap({\n subscribe: () => {\n this.#eventListener.suppressChangeEvents();\n this.#alwaysAndNeverDrawnElements.suppressChangeEvents();\n },\n finalize: () => {\n this.#eventListener.resumeChangeEvents();\n this.#alwaysAndNeverDrawnElements.resumeChangeEvents();\n },\n }),\n );\n\n return toVoidPromise(changeObservable);\n }\n\n public [Symbol.dispose]() {\n this.#eventListener[Symbol.dispose]();\n this.#alwaysAndNeverDrawnElements[Symbol.dispose]();\n this.#treeSpecificVisibilityHandler[Symbol.dispose]();\n }\n\n private getVisibilityStatusInternal(node: HierarchyNode) {\n if (node.filtering?.filteredChildrenIdentifierPaths?.length && !node.filtering.isFilterTarget) {\n return this.getFilteredNodeVisibility({ node });\n }\n return this.#treeSpecificVisibilityHandler.getVisibilityStatus(node);\n }\n\n private changeVisibilityStatusInternal(node: HierarchyNode, on: boolean): Observable<void> {\n if (node.filtering?.filteredChildrenIdentifierPaths?.length && !node.filtering.isFilterTarget) {\n return this.changeFilteredNodeVisibility({ node, on });\n }\n return this.#treeSpecificVisibilityHandler.changeVisibilityStatus(node, on);\n }\n\n private getFilteredNodeVisibility(props: { node: HierarchyNode }) {\n return this.getFilteredTreeTargets(props).pipe(\n mergeMap((targets) => {\n if (!targets) {\n return EMPTY;\n }\n return this.#treeSpecificVisibilityHandler.getFilterTargetsVisibilityStatus(targets);\n }),\n );\n }\n\n private getFilteredTreeTargets({ node }: { node: HierarchyNode }): Observable<TFilterTargets | undefined> {\n if (!this.#filteredTree) {\n return of(undefined);\n }\n return from(this.#filteredTree).pipe(map((filteredTree) => filteredTree.getFilterTargets(node)));\n }\n\n private changeFilteredNodeVisibility({ on, node }: { on: boolean; node: HierarchyNode }) {\n return this.getFilteredTreeTargets({ node }).pipe(\n mergeMap((targets) => {\n if (!targets) {\n return EMPTY;\n }\n return this.#treeSpecificVisibilityHandler.changeFilterTargetsVisibilityStatus(targets, on);\n }),\n );\n }\n}\n"]}
1
+ {"version":3,"file":"UseCachedVisibility.js","sourceRoot":"","sources":["../../../../../../../../src/tree-widget-react/components/trees/common/internal/useTreeHooks/UseCachedVisibility.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, useState } from \"react\";\nimport { defaultIfEmpty, EMPTY, filter, firstValueFrom, from, fromEventPattern, map, mergeMap, Subject, takeUntil, tap } from \"rxjs\";\nimport { assert } from \"@itwin/core-bentley\";\nimport { HierarchyNode, HierarchyNodeKey } from \"@itwin/presentation-hierarchies\";\nimport { HierarchyVisibilityOverrideHandler } from \"../../UseHierarchyVisibility.js\";\nimport { AlwaysAndNeverDrawnElementInfo } from \"../AlwaysAndNeverDrawnElementInfo.js\";\nimport { toVoidPromise } from \"../Rxjs.js\";\nimport { createVisibilityStatus } from \"../Tooltip.js\";\nimport { createVisibilityChangeEventListener } from \"../VisibilityChangeEventListener.js\";\n\nimport type { Observable } from \"rxjs\";\nimport type { GuidString } from \"@itwin/core-bentley\";\nimport type { ClassGroupingNodeKey, HierarchyFilteringPath, InstancesNodeKey } from \"@itwin/presentation-hierarchies\";\nimport type { ECClassHierarchyInspector } from \"@itwin/presentation-shared\";\nimport type { VisibilityTreeProps } from \"../../components/VisibilityTree.js\";\nimport type { TreeWidgetViewport } from \"../../TreeWidgetViewport.js\";\nimport type { HierarchyVisibilityHandler, VisibilityStatus } from \"../../UseHierarchyVisibility.js\";\nimport type { FilteredTree } from \"../visibility/BaseFilteredTree.js\";\nimport type { TreeSpecificVisibilityHandler } from \"../visibility/BaseVisibilityHelper.js\";\nimport type { IVisibilityChangeEventListener } from \"../VisibilityChangeEventListener.js\";\n\n/** @internal */\nexport interface CreateFilteredTreeProps<TCache> {\n getCache: () => TCache;\n imodelAccess: ECClassHierarchyInspector;\n filteringPaths: HierarchyFilteringPath[];\n}\n\n/** @internal */\nexport interface CreateTreeSpecificVisibilityHandlerProps<TCache> {\n info: AlwaysAndNeverDrawnElementInfo;\n getCache: () => TCache;\n viewport: TreeWidgetViewport;\n overrideHandler: HierarchyVisibilityOverrideHandler;\n}\n\n/** @internal */\nexport interface UseCachedVisibilityProps<TCache, TFilterTargets> {\n componentId: GuidString;\n activeView: TreeWidgetViewport;\n getCache: () => TCache;\n createFilteredTree: (props: CreateFilteredTreeProps<TCache>) => Promise<FilteredTree<TFilterTargets>>;\n createTreeSpecificVisibilityHandler: (props: CreateTreeSpecificVisibilityHandlerProps<TCache>) => TreeSpecificVisibilityHandler<TFilterTargets> & Disposable;\n}\n\n/** @internal */\nexport function useCachedVisibility<TCache, TFilterTargets>(props: UseCachedVisibilityProps<TCache, TFilterTargets>) {\n const [filteredPaths, setFilteredPaths] = useState<HierarchyFilteringPath[] | undefined>(undefined);\n const { activeView, getCache, createFilteredTree, createTreeSpecificVisibilityHandler, componentId } = props;\n\n const [visibilityHandlerFactory, setVisibilityHandlerFactory] = useState<VisibilityTreeProps[\"visibilityHandlerFactory\"]>(() =>\n createVisibilityHandlerFactory({\n activeView,\n getCache,\n createFilteredTree,\n createTreeSpecificVisibilityHandler,\n filteringPaths: filteredPaths,\n componentId,\n }),\n );\n\n useEffect(() => {\n setVisibilityHandlerFactory(() =>\n createVisibilityHandlerFactory({\n activeView,\n getCache,\n createFilteredTree,\n createTreeSpecificVisibilityHandler,\n filteringPaths: filteredPaths,\n componentId,\n }),\n );\n }, [activeView, getCache, filteredPaths, createFilteredTree, createTreeSpecificVisibilityHandler, componentId]);\n\n return {\n visibilityHandlerFactory,\n onFilteredPathsChanged: useCallback((paths: HierarchyFilteringPath[] | undefined) => setFilteredPaths(paths), []),\n filteredPaths,\n };\n}\n\nfunction createVisibilityHandlerFactory<TCache, TFilterTargets>(\n props: UseCachedVisibilityProps<TCache, TFilterTargets> & {\n filteringPaths: HierarchyFilteringPath[] | undefined;\n },\n): VisibilityTreeProps[\"visibilityHandlerFactory\"] {\n const { activeView, createFilteredTree, createTreeSpecificVisibilityHandler, getCache, filteringPaths, componentId } = props;\n return ({ imodelAccess }) =>\n new HierarchyVisibilityHandlerImpl<TFilterTargets>({\n componentId,\n viewport: activeView,\n getFilteredTree: (): Promise<FilteredTree<TFilterTargets>> | undefined => {\n if (filteringPaths) {\n return createFilteredTree({ imodelAccess, filteringPaths, getCache });\n }\n return undefined;\n },\n getTreeSpecificVisibilityHandler: (info, overrideHandler) =>\n createTreeSpecificVisibilityHandler({\n info,\n getCache,\n viewport: activeView,\n overrideHandler,\n }),\n });\n}\n\n/** @internal */\nexport interface HierarchyVisibilityHandlerImplProps<TFilterTargets> {\n viewport: TreeWidgetViewport;\n getTreeSpecificVisibilityHandler: (\n info: AlwaysAndNeverDrawnElementInfo,\n overrideHandler: HierarchyVisibilityOverrideHandler,\n ) => TreeSpecificVisibilityHandler<TFilterTargets> & Disposable;\n getFilteredTree: () => Promise<FilteredTree<TFilterTargets>> | undefined;\n componentId?: GuidString;\n}\n\n/**\n * Class that handles visibility of hierarchy nodes in a tree.\n *\n * - It provides methods to get and change visibility status of nodes.\n * - Also handles filtered tree nodes visibility.\n * - Listens to visibility change events and updates visibility status accordingly.\n * @internal\n */\nexport class HierarchyVisibilityHandlerImpl<TFilterTargets> implements HierarchyVisibilityHandler, Disposable {\n readonly #props: HierarchyVisibilityHandlerImplProps<TFilterTargets>;\n readonly #eventListener: IVisibilityChangeEventListener;\n readonly #alwaysAndNeverDrawnElements: AlwaysAndNeverDrawnElementInfo;\n #treeSpecificVisibilityHandler: TreeSpecificVisibilityHandler<TFilterTargets> & Disposable;\n #changeRequest = new Subject<{ key: HierarchyNodeKey; depth: number }>();\n #filteredTree: Promise<FilteredTree<TFilterTargets>> | undefined;\n\n constructor(props: HierarchyVisibilityHandlerImplProps<TFilterTargets>) {\n this.#props = props;\n this.#eventListener = createVisibilityChangeEventListener({\n viewport: this.#props.viewport,\n listeners: {\n models: true,\n categories: true,\n elements: true,\n displayStyle: true,\n },\n });\n this.#alwaysAndNeverDrawnElements = new AlwaysAndNeverDrawnElementInfo({ viewport: this.#props.viewport, componentId: props.componentId });\n this.#treeSpecificVisibilityHandler = this.#props.getTreeSpecificVisibilityHandler(\n this.#alwaysAndNeverDrawnElements,\n new HierarchyVisibilityOverrideHandler(this),\n );\n this.#filteredTree = this.#props.getFilteredTree();\n }\n\n public get onVisibilityChange() {\n return this.#eventListener.onVisibilityChange;\n }\n\n public async getVisibilityStatus(node: HierarchyNode): Promise<VisibilityStatus> {\n return firstValueFrom(\n this.getVisibilityStatusInternal(node).pipe(\n // unsubscribe from the observable if the change request for this node is received\n takeUntil(this.#changeRequest.pipe(filter(({ key, depth }) => depth === node.parentKeys.length && HierarchyNodeKey.equals(node.key, key)))),\n // unsubscribe if visibility changes\n takeUntil(\n fromEventPattern(\n (handler) => {\n this.#eventListener.onVisibilityChange.addListener(handler);\n },\n (handler) => {\n this.#eventListener.onVisibilityChange.removeListener(handler);\n },\n ),\n ),\n defaultIfEmpty(createVisibilityStatus(\"hidden\")),\n ),\n );\n }\n\n public async changeVisibility(node: HierarchyNode, shouldDisplay: boolean): Promise<void> {\n // notify about new change request\n this.#changeRequest.next({ key: node.key, depth: node.parentKeys.length });\n\n const changeObservable = this.changeVisibilityStatusInternal(node, shouldDisplay).pipe(\n // unsubscribe from the observable if the change request for this node is received\n takeUntil(this.#changeRequest.pipe(filter(({ key, depth }) => depth === node.parentKeys.length && HierarchyNodeKey.equals(node.key, key)))),\n tap({\n subscribe: () => {\n this.#eventListener.suppressChangeEvents();\n this.#alwaysAndNeverDrawnElements.suppressChangeEvents();\n },\n finalize: () => {\n this.#eventListener.resumeChangeEvents();\n this.#alwaysAndNeverDrawnElements.resumeChangeEvents();\n },\n }),\n );\n\n return toVoidPromise(changeObservable);\n }\n\n public [Symbol.dispose]() {\n this.#eventListener[Symbol.dispose]();\n this.#alwaysAndNeverDrawnElements[Symbol.dispose]();\n this.#treeSpecificVisibilityHandler[Symbol.dispose]();\n }\n\n private getVisibilityStatusInternal(node: HierarchyNode) {\n if (HierarchyNode.isClassGroupingNode(node)) {\n if (node.extendedData?.hasDirectNonFilteredTargets && !node.filtering?.hasFilterTargetAncestor) {\n return this.getFilteredNodeVisibility({ node });\n }\n }\n\n if (HierarchyNode.isInstancesNode(node) && node.filtering?.filteredChildrenIdentifierPaths?.length && !node.filtering.isFilterTarget) {\n return this.getFilteredNodeVisibility({ node });\n }\n return this.#treeSpecificVisibilityHandler.getVisibilityStatus(node);\n }\n\n private changeVisibilityStatusInternal(node: HierarchyNode, on: boolean): Observable<void> {\n if (HierarchyNode.isClassGroupingNode(node)) {\n if (node.extendedData?.hasDirectNonFilteredTargets && !node.filtering?.hasFilterTargetAncestor) {\n return this.changeFilteredNodeVisibility({ node, on });\n }\n }\n if (HierarchyNode.isInstancesNode(node) && node.filtering?.filteredChildrenIdentifierPaths?.length && !node.filtering.isFilterTarget) {\n return this.changeFilteredNodeVisibility({ node, on });\n }\n return this.#treeSpecificVisibilityHandler.changeVisibilityStatus(node, on);\n }\n\n private getFilteredNodeVisibility(props: {\n node: HierarchyNode & {\n key: ClassGroupingNodeKey | InstancesNodeKey;\n };\n }) {\n return this.getFilteredTreeTargets(props).pipe(\n mergeMap((targets) => {\n if (!targets) {\n return EMPTY;\n }\n return this.#treeSpecificVisibilityHandler.getFilterTargetsVisibilityStatus(targets);\n }),\n );\n }\n\n private getFilteredTreeTargets({\n node,\n }: {\n node: HierarchyNode & {\n key: ClassGroupingNodeKey | InstancesNodeKey;\n };\n }): Observable<TFilterTargets | undefined> {\n assert(this.#filteredTree !== undefined);\n return from(this.#filteredTree).pipe(map((filteredTree) => filteredTree.getFilterTargets(node)));\n }\n\n private changeFilteredNodeVisibility({\n on,\n node,\n }: {\n on: boolean;\n node: HierarchyNode & {\n key: ClassGroupingNodeKey | InstancesNodeKey;\n };\n }) {\n return this.getFilteredTreeTargets({ node }).pipe(\n mergeMap((targets) => {\n if (!targets) {\n return EMPTY;\n }\n return this.#treeSpecificVisibilityHandler.changeFilterTargetsVisibilityStatus(targets, on);\n }),\n );\n }\n}\n"]}
@@ -1,14 +1,17 @@
1
+ import type { GuidString } from "@itwin/core-bentley";
1
2
  import type { IModelConnection } from "@itwin/core-frontend";
2
3
  /** @internal */
3
4
  export interface CreateCacheProps<TCacheSpecificProps> {
4
5
  imodel: IModelConnection;
5
6
  specificProps: TCacheSpecificProps;
7
+ componentId: GuidString;
6
8
  }
7
9
  /** @internal */
8
10
  export interface UseIdsCacheProps<TCache, TCacheSpecificProps> {
9
11
  imodel: IModelConnection;
10
12
  createCache: (props: CreateCacheProps<TCacheSpecificProps>) => TCache;
11
13
  cacheSpecificProps: TCacheSpecificProps;
14
+ componentId: GuidString;
12
15
  }
13
16
  /** @internal */
14
17
  export declare function useIdsCache<TCache extends Disposable, TCacheSpecificProps extends object>(props: UseIdsCacheProps<TCache, TCacheSpecificProps>): {
@@ -12,32 +12,32 @@ export function useIdsCache(props) {
12
12
  cacheRef.current = undefined;
13
13
  });
14
14
  const { imodel, createCache, cacheSpecificProps } = props;
15
- const createCacheGetterRef = useRef((currImodel, specificProps) => {
15
+ const createCacheGetterRef = useRef((currImodel, specificProps, componentId) => {
16
16
  return () => {
17
17
  if (cacheRef.current === undefined) {
18
- cacheRef.current = createCache({ imodel: currImodel, specificProps });
18
+ cacheRef.current = createCache({ imodel: currImodel, specificProps, componentId });
19
19
  }
20
20
  return cacheRef.current;
21
21
  };
22
22
  });
23
- const [getCache, setCacheGetter] = useState(() => createCacheGetterRef.current(imodel, cacheSpecificProps));
23
+ const [getCache, setCacheGetter] = useState(() => createCacheGetterRef.current(imodel, cacheSpecificProps, props.componentId));
24
24
  useEffect(() => {
25
25
  // clear cache in case it was created before `useEffect` was run first time
26
26
  clearCacheRef.current();
27
27
  // make sure all cache users rerender
28
- setCacheGetter(() => createCacheGetterRef.current(imodel, cacheSpecificProps));
28
+ setCacheGetter(() => createCacheGetterRef.current(imodel, cacheSpecificProps, props.componentId));
29
29
  return () => {
30
30
  // eslint-disable-next-line react-hooks/exhaustive-deps
31
31
  clearCacheRef.current();
32
32
  };
33
- }, [imodel, cacheSpecificProps]);
33
+ }, [imodel, cacheSpecificProps, props.componentId]);
34
34
  useIModelChangeListener({
35
35
  imodel,
36
36
  action: useCallback(() => {
37
37
  clearCacheRef.current();
38
38
  // make sure all cache users rerender
39
- setCacheGetter(() => createCacheGetterRef.current(imodel, cacheSpecificProps));
40
- }, [imodel, cacheSpecificProps]),
39
+ setCacheGetter(() => createCacheGetterRef.current(imodel, cacheSpecificProps, props.componentId));
40
+ }, [imodel, cacheSpecificProps, props.componentId]),
41
41
  });
42
42
  return {
43
43
  getCache,
@@ -1 +1 @@
1
- {"version":3,"file":"UseIdsCache.js","sourceRoot":"","sources":["../../../../../../../../src/tree-widget-react/components/trees/common/internal/useTreeHooks/UseIdsCache.ts"],"names":[],"mappings":"AAAA;;;gGAGgG;AAEhG,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjE,OAAO,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AAiBxE,gBAAgB;AAChB,MAAM,UAAU,WAAW,CACzB,KAAoD;IAEpD,MAAM,QAAQ,GAAG,MAAM,CAAqB,SAAS,CAAC,CAAC;IACvD,MAAM,aAAa,GAAG,MAAM,CAAC,GAAG,EAAE;QAChC,QAAQ,CAAC,OAAO,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;QACvC,QAAQ,CAAC,OAAO,GAAG,SAAS,CAAC;IAC/B,CAAC,CAAC,CAAC;IACH,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,kBAAkB,EAAE,GAAG,KAAK,CAAC;IAE1D,MAAM,oBAAoB,GAAG,MAAM,CAAC,CAAC,UAA4B,EAAE,aAAkC,EAAE,EAAE;QACvG,OAAO,GAAG,EAAE;YACV,IAAI,QAAQ,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;gBACnC,QAAQ,CAAC,OAAO,GAAG,WAAW,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,aAAa,EAAE,CAAC,CAAC;YACxE,CAAC;YACD,OAAO,QAAQ,CAAC,OAAO,CAAC;QAC1B,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,QAAQ,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAe,GAAG,EAAE,CAAC,oBAAoB,CAAC,OAAO,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC,CAAC;IAE1H,SAAS,CAAC,GAAG,EAAE;QACb,2EAA2E;QAC3E,aAAa,CAAC,OAAO,EAAE,CAAC;QAExB,qCAAqC;QACrC,cAAc,CAAC,GAAG,EAAE,CAAC,oBAAoB,CAAC,OAAO,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC,CAAC;QAC/E,OAAO,GAAG,EAAE;YACV,uDAAuD;YACvD,aAAa,CAAC,OAAO,EAAE,CAAC;QAC1B,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC,CAAC;IAEjC,uBAAuB,CAAC;QACtB,MAAM;QACN,MAAM,EAAE,WAAW,CAAC,GAAG,EAAE;YACvB,aAAa,CAAC,OAAO,EAAE,CAAC;YACxB,qCAAqC;YACrC,cAAc,CAAC,GAAG,EAAE,CAAC,oBAAoB,CAAC,OAAO,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC,CAAC;QACjF,CAAC,EAAE,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;KACjC,CAAC,CAAC;IAEH,OAAO;QACL,QAAQ;KACT,CAAC;AACJ,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, useEffect, useRef, useState } from \"react\";\nimport { useIModelChangeListener } from \"../UseIModelChangeListener.js\";\n\nimport type { IModelConnection } from \"@itwin/core-frontend\";\n\n/** @internal */\nexport interface CreateCacheProps<TCacheSpecificProps> {\n imodel: IModelConnection;\n specificProps: TCacheSpecificProps;\n}\n\n/** @internal */\nexport interface UseIdsCacheProps<TCache, TCacheSpecificProps> {\n imodel: IModelConnection;\n createCache: (props: CreateCacheProps<TCacheSpecificProps>) => TCache;\n cacheSpecificProps: TCacheSpecificProps;\n}\n\n/** @internal */\nexport function useIdsCache<TCache extends Disposable, TCacheSpecificProps extends object>(\n props: UseIdsCacheProps<TCache, TCacheSpecificProps>,\n): { getCache: () => TCache } {\n const cacheRef = useRef<TCache | undefined>(undefined);\n const clearCacheRef = useRef(() => {\n cacheRef.current?.[Symbol.dispose]?.();\n cacheRef.current = undefined;\n });\n const { imodel, createCache, cacheSpecificProps } = props;\n\n const createCacheGetterRef = useRef((currImodel: IModelConnection, specificProps: TCacheSpecificProps) => {\n return () => {\n if (cacheRef.current === undefined) {\n cacheRef.current = createCache({ imodel: currImodel, specificProps });\n }\n return cacheRef.current;\n };\n });\n\n const [getCache, setCacheGetter] = useState<() => TCache>(() => createCacheGetterRef.current(imodel, cacheSpecificProps));\n\n useEffect(() => {\n // clear cache in case it was created before `useEffect` was run first time\n clearCacheRef.current();\n\n // make sure all cache users rerender\n setCacheGetter(() => createCacheGetterRef.current(imodel, cacheSpecificProps));\n return () => {\n // eslint-disable-next-line react-hooks/exhaustive-deps\n clearCacheRef.current();\n };\n }, [imodel, cacheSpecificProps]);\n\n useIModelChangeListener({\n imodel,\n action: useCallback(() => {\n clearCacheRef.current();\n // make sure all cache users rerender\n setCacheGetter(() => createCacheGetterRef.current(imodel, cacheSpecificProps));\n }, [imodel, cacheSpecificProps]),\n });\n\n return {\n getCache,\n };\n}\n"]}
1
+ {"version":3,"file":"UseIdsCache.js","sourceRoot":"","sources":["../../../../../../../../src/tree-widget-react/components/trees/common/internal/useTreeHooks/UseIdsCache.ts"],"names":[],"mappings":"AAAA;;;gGAGgG;AAEhG,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjE,OAAO,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AAoBxE,gBAAgB;AAChB,MAAM,UAAU,WAAW,CACzB,KAAoD;IAEpD,MAAM,QAAQ,GAAG,MAAM,CAAqB,SAAS,CAAC,CAAC;IACvD,MAAM,aAAa,GAAG,MAAM,CAAC,GAAG,EAAE;QAChC,QAAQ,CAAC,OAAO,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;QACvC,QAAQ,CAAC,OAAO,GAAG,SAAS,CAAC;IAC/B,CAAC,CAAC,CAAC;IACH,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,kBAAkB,EAAE,GAAG,KAAK,CAAC;IAE1D,MAAM,oBAAoB,GAAG,MAAM,CAAC,CAAC,UAA4B,EAAE,aAAkC,EAAE,WAAuB,EAAE,EAAE;QAChI,OAAO,GAAG,EAAE;YACV,IAAI,QAAQ,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;gBACnC,QAAQ,CAAC,OAAO,GAAG,WAAW,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,aAAa,EAAE,WAAW,EAAE,CAAC,CAAC;YACrF,CAAC;YACD,OAAO,QAAQ,CAAC,OAAO,CAAC;QAC1B,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,QAAQ,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAe,GAAG,EAAE,CAAC,oBAAoB,CAAC,OAAO,CAAC,MAAM,EAAE,kBAAkB,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC;IAE7I,SAAS,CAAC,GAAG,EAAE;QACb,2EAA2E;QAC3E,aAAa,CAAC,OAAO,EAAE,CAAC;QAExB,qCAAqC;QACrC,cAAc,CAAC,GAAG,EAAE,CAAC,oBAAoB,CAAC,OAAO,CAAC,MAAM,EAAE,kBAAkB,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC;QAClG,OAAO,GAAG,EAAE;YACV,uDAAuD;YACvD,aAAa,CAAC,OAAO,EAAE,CAAC;QAC1B,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,MAAM,EAAE,kBAAkB,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC;IAEpD,uBAAuB,CAAC;QACtB,MAAM;QACN,MAAM,EAAE,WAAW,CAAC,GAAG,EAAE;YACvB,aAAa,CAAC,OAAO,EAAE,CAAC;YACxB,qCAAqC;YACrC,cAAc,CAAC,GAAG,EAAE,CAAC,oBAAoB,CAAC,OAAO,CAAC,MAAM,EAAE,kBAAkB,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC;QACpG,CAAC,EAAE,CAAC,MAAM,EAAE,kBAAkB,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC;KACpD,CAAC,CAAC;IAEH,OAAO;QACL,QAAQ;KACT,CAAC;AACJ,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, useEffect, useRef, useState } from \"react\";\nimport { useIModelChangeListener } from \"../UseIModelChangeListener.js\";\n\nimport type { GuidString } from \"@itwin/core-bentley\";\nimport type { IModelConnection } from \"@itwin/core-frontend\";\n\n/** @internal */\nexport interface CreateCacheProps<TCacheSpecificProps> {\n imodel: IModelConnection;\n specificProps: TCacheSpecificProps;\n componentId: GuidString;\n}\n\n/** @internal */\nexport interface UseIdsCacheProps<TCache, TCacheSpecificProps> {\n imodel: IModelConnection;\n createCache: (props: CreateCacheProps<TCacheSpecificProps>) => TCache;\n cacheSpecificProps: TCacheSpecificProps;\n componentId: GuidString;\n}\n\n/** @internal */\nexport function useIdsCache<TCache extends Disposable, TCacheSpecificProps extends object>(\n props: UseIdsCacheProps<TCache, TCacheSpecificProps>,\n): { getCache: () => TCache } {\n const cacheRef = useRef<TCache | undefined>(undefined);\n const clearCacheRef = useRef(() => {\n cacheRef.current?.[Symbol.dispose]?.();\n cacheRef.current = undefined;\n });\n const { imodel, createCache, cacheSpecificProps } = props;\n\n const createCacheGetterRef = useRef((currImodel: IModelConnection, specificProps: TCacheSpecificProps, componentId: GuidString) => {\n return () => {\n if (cacheRef.current === undefined) {\n cacheRef.current = createCache({ imodel: currImodel, specificProps, componentId });\n }\n return cacheRef.current;\n };\n });\n\n const [getCache, setCacheGetter] = useState<() => TCache>(() => createCacheGetterRef.current(imodel, cacheSpecificProps, props.componentId));\n\n useEffect(() => {\n // clear cache in case it was created before `useEffect` was run first time\n clearCacheRef.current();\n\n // make sure all cache users rerender\n setCacheGetter(() => createCacheGetterRef.current(imodel, cacheSpecificProps, props.componentId));\n return () => {\n // eslint-disable-next-line react-hooks/exhaustive-deps\n clearCacheRef.current();\n };\n }, [imodel, cacheSpecificProps, props.componentId]);\n\n useIModelChangeListener({\n imodel,\n action: useCallback(() => {\n clearCacheRef.current();\n // make sure all cache users rerender\n setCacheGetter(() => createCacheGetterRef.current(imodel, cacheSpecificProps, props.componentId));\n }, [imodel, cacheSpecificProps, props.componentId]),\n });\n\n return {\n getCache,\n };\n}\n"]}
@@ -1,6 +1,6 @@
1
- import { HierarchyFilteringPath } from "@itwin/presentation-hierarchies";
1
+ import { HierarchyFilteringPath, HierarchyNode } from "@itwin/presentation-hierarchies";
2
2
  import type { Id64String } from "@itwin/core-bentley";
3
- import type { HierarchyNode } from "@itwin/presentation-hierarchies";
3
+ import type { ClassGroupingNodeKey, InstancesNodeKey } from "@itwin/presentation-hierarchies";
4
4
  import type { InstanceKey } from "@itwin/presentation-shared";
5
5
  /** @internal */
6
6
  export type FilteredTreeNodeChildren<TFilteredTreeNode> = Map<Id64String, TFilteredTreeNode>;
@@ -57,7 +57,9 @@ export declare abstract class FilteredNodesHandler<TProcessedFilteredNodes, TFil
57
57
  parent: TFilteredTreeNode | FilteredTreeRootNode<TFilteredTreeNode>;
58
58
  }): TFilteredTreeNode;
59
59
  processFilteredNodes(): Promise<{
60
- getNodeFilterTargets: (node: HierarchyNode) => TFilterTargets | undefined;
60
+ getNodeFilterTargets: (node: HierarchyNode & {
61
+ key: ClassGroupingNodeKey | InstancesNodeKey;
62
+ }) => TFilterTargets | undefined;
61
63
  }>;
62
64
  /** Takes a new node and adds it to the tree structure. */
63
65
  accept(props: {
@@ -72,7 +74,9 @@ export declare abstract class FilteredNodesHandler<TProcessedFilteredNodes, TFil
72
74
  }
73
75
  /** @internal */
74
76
  export interface FilteredTree<TFilterTargets> {
75
- getFilterTargets: (node: HierarchyNode) => TFilterTargets | undefined;
77
+ getFilterTargets: (node: HierarchyNode & {
78
+ key: ClassGroupingNodeKey | InstancesNodeKey;
79
+ }) => TFilterTargets | undefined;
76
80
  }
77
81
  /** @internal */
78
82
  export interface CreateFilteredTreeProps<TProcessedFilteredNodes, TFilterTargets, TFilteredTreeNode extends BaseFilteredTreeNode<TFilteredTreeNode>> {
@@ -2,7 +2,8 @@
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 { HierarchyFilteringPath, HierarchyNodeIdentifier, HierarchyNodeKey } from "@itwin/presentation-hierarchies";
5
+ import { Id64 } from "@itwin/core-bentley";
6
+ import { HierarchyFilteringPath, HierarchyNode, HierarchyNodeIdentifier, HierarchyNodeKey } from "@itwin/presentation-hierarchies";
6
7
  /**
7
8
  * Class that provides methods to handle filtered nodes in a tree structure.
8
9
  *
@@ -39,10 +40,6 @@ export class FilteredNodesHandler {
39
40
  /** Takes a specific node and gets all filter targets related to it. */
40
41
  getNodeFilterTargets(node, processedFilteredNodes) {
41
42
  let lookupParents = [this.root];
42
- const nodeKey = node.key;
43
- if (!HierarchyNodeKey.isInstances(nodeKey)) {
44
- return undefined;
45
- }
46
43
  // find the filtered parent nodes of the `node`
47
44
  for (const parentKey of node.parentKeys) {
48
45
  if (!HierarchyNodeKey.isInstances(parentKey)) {
@@ -50,24 +47,32 @@ export class FilteredNodesHandler {
50
47
  }
51
48
  // tree node might be merged from multiple instances. As filtered tree stores only one instance per node, we need to find all matching nodes
52
49
  // and use them when checking for matching node in one level deeper.
53
- const parentNodes = this.findMatchingFilteredNodes(lookupParents, parentKey.instanceKeys);
50
+ const parentNodes = this.findMatchingFilteredNodes(lookupParents, parentKey.instanceKeys.map((key) => key.id));
54
51
  if (parentNodes.length === 0) {
55
52
  return undefined;
56
53
  }
57
54
  lookupParents = parentNodes;
58
55
  }
56
+ const ids = HierarchyNode.isInstancesNode(node) ? node.key.instanceKeys.map(({ id }) => id) : node.groupedInstanceKeys.map(({ id }) => id);
59
57
  // find filtered nodes that match the `node`
60
- const filteredNodes = this.findMatchingFilteredNodes(lookupParents, nodeKey.instanceKeys);
58
+ const filteredNodes = this.findMatchingFilteredNodes(lookupParents, ids);
61
59
  if (filteredNodes.length === 0) {
62
60
  return undefined;
63
61
  }
64
62
  return this.convertNodesToFilterTargets(filteredNodes, processedFilteredNodes);
65
63
  }
66
64
  /** Finds filtered nodes that match the given keys. */
67
- findMatchingFilteredNodes(lookupParents, keys) {
68
- return lookupParents
69
- .flatMap((lookup) => keys.map((key) => lookup.children?.get(key.id)))
70
- .filter((lookupNode) => lookupNode !== undefined);
65
+ findMatchingFilteredNodes(lookupParents, ids) {
66
+ return lookupParents.flatMap((lookup) => {
67
+ const childrenArray = Array();
68
+ for (const id of Id64.iterable(ids)) {
69
+ const node = lookup.children?.get(id);
70
+ if (node) {
71
+ childrenArray.push(node);
72
+ }
73
+ }
74
+ return childrenArray;
75
+ });
71
76
  }
72
77
  }
73
78
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"BaseFilteredTree.js","sourceRoot":"","sources":["../../../../../../../../src/tree-widget-react/components/trees/common/internal/visibility/BaseFilteredTree.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 { HierarchyFilteringPath, HierarchyNodeIdentifier, HierarchyNodeKey } from \"@itwin/presentation-hierarchies\";\n\nimport type { Id64String } from \"@itwin/core-bentley\";\nimport type { HierarchyNode } from \"@itwin/presentation-hierarchies\";\nimport type { InstanceKey } from \"@itwin/presentation-shared\";\n\n/** @internal */\nexport type FilteredTreeNodeChildren<TFilteredTreeNode> = Map<Id64String, TFilteredTreeNode>;\n\n/**\n * A generic interface for a filtered tree root node.\n *\n * It differs from `BaseFilteredTreeNode` in that it only contains children details and nothing else.\n * @internal\n */\nexport interface FilteredTreeRootNode<TFilteredTreeNode extends BaseFilteredTreeNode<TFilteredTreeNode>> {\n children: FilteredTreeNodeChildren<TFilteredTreeNode>;\n}\n\n/**\n * A generic interface for a filtered tree node.\n *\n * It represents every node in a filtered tree structure.\n * @internal\n * */\nexport interface BaseFilteredTreeNode<TFilteredTreeNode extends BaseFilteredTreeNode<TFilteredTreeNode>> {\n type: string;\n id: Id64String;\n children?: FilteredTreeNodeChildren<TFilteredTreeNode>;\n isFilterTarget: boolean;\n}\n\n/**\n * Class that provides methods to handle filtered nodes in a tree structure.\n *\n * It provides two methods that can be shared across different filtered trees:\n * - `processFilteredNodes` - processes filtered nodes and returns a function to get filter targets for a node.\n * - `accept` - accepts a new node and adds it to the tree structure.\n * @internal\n */\nexport abstract class FilteredNodesHandler<TProcessedFilteredNodes, TFilterTargets, TFilteredTreeNode extends BaseFilteredTreeNode<TFilteredTreeNode>> {\n public readonly root: FilteredTreeRootNode<TFilteredTreeNode> = {\n children: new Map(),\n };\n public readonly filteredNodesArr = new Array<TFilteredTreeNode>();\n\n /** Returns filtered tree node type based on its' className */\n public abstract getType(className: string): Promise<TFilteredTreeNode[\"type\"]>;\n /** Converts nodes to filter targets */\n public abstract convertNodesToFilterTargets(filteredNodes: TFilteredTreeNode[], processedFilteredNodes: TProcessedFilteredNodes): TFilterTargets | undefined;\n /**\n * Processes filtered nodes.\n *\n * Nodes are created using filtering paths, and some information is not present in the filtering paths.\n * Because of this, some nodes may need to be processed to get additional information.\n *\n * E.g. Retrieving categoryId of elements can't be done using filtering paths.\n */\n public abstract getProcessedFilteredNodes(): Promise<TProcessedFilteredNodes>;\n /** Creates filtered nodes */\n public abstract createFilteredTreeNode(props: {\n type: TFilteredTreeNode[\"type\"];\n id: Id64String;\n isFilterTarget: boolean;\n parent: TFilteredTreeNode | FilteredTreeRootNode<TFilteredTreeNode>;\n }): TFilteredTreeNode;\n\n public async processFilteredNodes(): Promise<{ getNodeFilterTargets: (node: HierarchyNode) => TFilterTargets | undefined }> {\n const processedFilteredNodes = await this.getProcessedFilteredNodes();\n return {\n getNodeFilterTargets: (node: HierarchyNode) => this.getNodeFilterTargets(node, processedFilteredNodes),\n };\n }\n\n /** Takes a new node and adds it to the tree structure. */\n public async accept(props: {\n instanceKey: InstanceKey;\n parentNode: TFilteredTreeNode | FilteredTreeRootNode<TFilteredTreeNode>;\n isFilterTarget: boolean;\n }): Promise<TFilteredTreeNode> {\n const { instanceKey, parentNode, isFilterTarget } = props;\n const type = await this.getType(instanceKey.className);\n\n const newNode = this.createFilteredTreeNode({\n type,\n id: instanceKey.id,\n isFilterTarget,\n parent: parentNode,\n });\n (parentNode.children ??= new Map()).set(instanceKey.id, newNode);\n this.filteredNodesArr.push(newNode);\n return newNode;\n }\n\n /** Takes a specific node and gets all filter targets related to it. */\n private getNodeFilterTargets(node: HierarchyNode, processedFilteredNodes: TProcessedFilteredNodes): TFilterTargets | undefined {\n let lookupParents: Array<{ children?: Map<Id64String, TFilteredTreeNode> }> = [this.root];\n\n const nodeKey = node.key;\n if (!HierarchyNodeKey.isInstances(nodeKey)) {\n return undefined;\n }\n\n // find the filtered parent nodes of the `node`\n for (const parentKey of node.parentKeys) {\n if (!HierarchyNodeKey.isInstances(parentKey)) {\n continue;\n }\n\n // tree node might be merged from multiple instances. As filtered tree stores only one instance per node, we need to find all matching nodes\n // and use them when checking for matching node in one level deeper.\n const parentNodes = this.findMatchingFilteredNodes(lookupParents, parentKey.instanceKeys);\n if (parentNodes.length === 0) {\n return undefined;\n }\n lookupParents = parentNodes;\n }\n\n // find filtered nodes that match the `node`\n const filteredNodes = this.findMatchingFilteredNodes(lookupParents, nodeKey.instanceKeys);\n if (filteredNodes.length === 0) {\n return undefined;\n }\n\n return this.convertNodesToFilterTargets(filteredNodes, processedFilteredNodes);\n }\n\n /** Finds filtered nodes that match the given keys. */\n private findMatchingFilteredNodes(lookupParents: Array<{ children?: Map<Id64String, TFilteredTreeNode> }>, keys: InstanceKey[]) {\n return lookupParents\n .flatMap((lookup) => keys.map((key) => lookup.children?.get(key.id)))\n .filter((lookupNode): lookupNode is TFilteredTreeNode => lookupNode !== undefined);\n }\n}\n\n/** @internal */\nexport interface FilteredTree<TFilterTargets> {\n getFilterTargets: (node: HierarchyNode) => TFilterTargets | undefined;\n}\n\n/** @internal */\nexport interface CreateFilteredTreeProps<TProcessedFilteredNodes, TFilterTargets, TFilteredTreeNode extends BaseFilteredTreeNode<TFilteredTreeNode>> {\n filteredNodesHandler: FilteredNodesHandler<TProcessedFilteredNodes, TFilterTargets, TFilteredTreeNode>;\n filteringPaths: HierarchyFilteringPath[];\n}\n\n/**\n * Function iterates over filtering paths and creates uses `filteredNodesHandler` to create a filtered tree.\n * @internal\n */\nexport async function createFilteredTree<TProcessedFilteredNodes, TFilterTargets, TFilteredTreeNode extends BaseFilteredTreeNode<TFilteredTreeNode>>(\n props: CreateFilteredTreeProps<TProcessedFilteredNodes, TFilterTargets, TFilteredTreeNode>,\n): Promise<FilteredTree<TFilterTargets>> {\n const { filteringPaths, filteredNodesHandler } = props;\n\n for (const filteringPath of filteringPaths) {\n const normalizedPath = HierarchyFilteringPath.normalize(filteringPath).path;\n\n let parentNode: FilteredTreeRootNode<TFilteredTreeNode> | TFilteredTreeNode = filteredNodesHandler.root;\n for (let i = 0; i < normalizedPath.length; ++i) {\n if (\"type\" in parentNode && \"isFilterTarget\" in parentNode && parentNode.isFilterTarget) {\n break;\n }\n\n const identifier = normalizedPath[i];\n\n if (!HierarchyNodeIdentifier.isInstanceNodeIdentifier(identifier)) {\n break;\n }\n\n const currentNode: TFilteredTreeNode | undefined = parentNode.children?.get(identifier.id);\n if (currentNode !== undefined) {\n parentNode = currentNode;\n continue;\n }\n parentNode = await filteredNodesHandler.accept({\n instanceKey: identifier,\n parentNode,\n isFilterTarget: i === normalizedPath.length - 1,\n });\n }\n }\n const processedFilteredNodes = await filteredNodesHandler.processFilteredNodes();\n return {\n getFilterTargets: (node: HierarchyNode) => processedFilteredNodes.getNodeFilterTargets(node),\n };\n}\n"]}
1
+ {"version":3,"file":"BaseFilteredTree.js","sourceRoot":"","sources":["../../../../../../../../src/tree-widget-react/components/trees/common/internal/visibility/BaseFilteredTree.ts"],"names":[],"mappings":"AAAA;;;gGAGgG;AAEhG,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAC3C,OAAO,EAAE,sBAAsB,EAAE,aAAa,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAgCnI;;;;;;;GAOG;AACH,MAAM,OAAgB,oBAAoB;IACxB,IAAI,GAA4C;QAC9D,QAAQ,EAAE,IAAI,GAAG,EAAE;KACpB,CAAC;IACc,gBAAgB,GAAG,IAAI,KAAK,EAAqB,CAAC;IAuB3D,KAAK,CAAC,oBAAoB;QAG/B,MAAM,sBAAsB,GAAG,MAAM,IAAI,CAAC,yBAAyB,EAAE,CAAC;QACtE,OAAO;YACL,oBAAoB,EAAE,CAAC,IAAsE,EAAE,EAAE,CAAC,IAAI,CAAC,oBAAoB,CAAC,IAAI,EAAE,sBAAsB,CAAC;SAC1J,CAAC;IACJ,CAAC;IAED,0DAA0D;IACnD,KAAK,CAAC,MAAM,CAAC,KAInB;QACC,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAE,GAAG,KAAK,CAAC;QAC1D,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;QAEvD,MAAM,OAAO,GAAG,IAAI,CAAC,sBAAsB,CAAC;YAC1C,IAAI;YACJ,EAAE,EAAE,WAAW,CAAC,EAAE;YAClB,cAAc;YACd,MAAM,EAAE,UAAU;SACnB,CAAC,CAAC;QACH,CAAC,UAAU,CAAC,QAAQ,KAAK,IAAI,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QACjE,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACpC,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,uEAAuE;IAC/D,oBAAoB,CAC1B,IAAsE,EACtE,sBAA+C;QAE/C,IAAI,aAAa,GAAuE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEpG,+CAA+C;QAC/C,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACxC,IAAI,CAAC,gBAAgB,CAAC,WAAW,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC7C,SAAS;YACX,CAAC;YAED,4IAA4I;YAC5I,oEAAoE;YACpE,MAAM,WAAW,GAAG,IAAI,CAAC,yBAAyB,CAChD,aAAa,EACb,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAC5C,CAAC;YACF,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC7B,OAAO,SAAS,CAAC;YACnB,CAAC;YACD,aAAa,GAAG,WAAW,CAAC;QAC9B,CAAC;QAED,MAAM,GAAG,GAAG,aAAa,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;QAC3I,4CAA4C;QAC5C,MAAM,aAAa,GAAG,IAAI,CAAC,yBAAyB,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;QACzE,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,OAAO,IAAI,CAAC,2BAA2B,CAAC,aAAa,EAAE,sBAAsB,CAAC,CAAC;IACjF,CAAC;IAED,sDAAsD;IAC9C,yBAAyB,CAAC,aAAiF,EAAE,GAAY;QAC/H,OAAO,aAAa,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE;YACtC,MAAM,aAAa,GAAG,KAAK,EAAqB,CAAC;YACjD,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBACpC,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;gBACtC,IAAI,IAAI,EAAE,CAAC;oBACT,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC3B,CAAC;YACH,CAAC;YACD,OAAO,aAAa,CAAC;QACvB,CAAC,CAAC,CAAC;IACL,CAAC;CACF;AAaD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,KAA0F;IAE1F,MAAM,EAAE,cAAc,EAAE,oBAAoB,EAAE,GAAG,KAAK,CAAC;IAEvD,KAAK,MAAM,aAAa,IAAI,cAAc,EAAE,CAAC;QAC3C,MAAM,cAAc,GAAG,sBAAsB,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC;QAE5E,IAAI,UAAU,GAAgE,oBAAoB,CAAC,IAAI,CAAC;QACxG,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,cAAc,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC;YAC/C,IAAI,MAAM,IAAI,UAAU,IAAI,gBAAgB,IAAI,UAAU,IAAI,UAAU,CAAC,cAAc,EAAE,CAAC;gBACxF,MAAM;YACR,CAAC;YAED,MAAM,UAAU,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;YAErC,IAAI,CAAC,uBAAuB,CAAC,wBAAwB,CAAC,UAAU,CAAC,EAAE,CAAC;gBAClE,MAAM;YACR,CAAC;YAED,MAAM,WAAW,GAAkC,UAAU,CAAC,QAAQ,EAAE,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;YAC3F,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;gBAC9B,UAAU,GAAG,WAAW,CAAC;gBACzB,SAAS;YACX,CAAC;YACD,UAAU,GAAG,MAAM,oBAAoB,CAAC,MAAM,CAAC;gBAC7C,WAAW,EAAE,UAAU;gBACvB,UAAU;gBACV,cAAc,EAAE,CAAC,KAAK,cAAc,CAAC,MAAM,GAAG,CAAC;aAChD,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,MAAM,sBAAsB,GAAG,MAAM,oBAAoB,CAAC,oBAAoB,EAAE,CAAC;IACjF,OAAO;QACL,gBAAgB,EAAE,CAAC,IAAsE,EAAE,EAAE,CAAC,sBAAsB,CAAC,oBAAoB,CAAC,IAAI,CAAC;KAChJ,CAAC;AACJ,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 { Id64 } from \"@itwin/core-bentley\";\nimport { HierarchyFilteringPath, HierarchyNode, HierarchyNodeIdentifier, HierarchyNodeKey } from \"@itwin/presentation-hierarchies\";\n\nimport type { Id64Arg, Id64String } from \"@itwin/core-bentley\";\nimport type { ClassGroupingNodeKey, InstancesNodeKey } from \"@itwin/presentation-hierarchies\";\nimport type { InstanceKey } from \"@itwin/presentation-shared\";\n\n/** @internal */\nexport type FilteredTreeNodeChildren<TFilteredTreeNode> = Map<Id64String, TFilteredTreeNode>;\n\n/**\n * A generic interface for a filtered tree root node.\n *\n * It differs from `BaseFilteredTreeNode` in that it only contains children details and nothing else.\n * @internal\n */\nexport interface FilteredTreeRootNode<TFilteredTreeNode extends BaseFilteredTreeNode<TFilteredTreeNode>> {\n children: FilteredTreeNodeChildren<TFilteredTreeNode>;\n}\n\n/**\n * A generic interface for a filtered tree node.\n *\n * It represents every node in a filtered tree structure.\n * @internal\n * */\nexport interface BaseFilteredTreeNode<TFilteredTreeNode extends BaseFilteredTreeNode<TFilteredTreeNode>> {\n type: string;\n id: Id64String;\n children?: FilteredTreeNodeChildren<TFilteredTreeNode>;\n isFilterTarget: boolean;\n}\n\n/**\n * Class that provides methods to handle filtered nodes in a tree structure.\n *\n * It provides two methods that can be shared across different filtered trees:\n * - `processFilteredNodes` - processes filtered nodes and returns a function to get filter targets for a node.\n * - `accept` - accepts a new node and adds it to the tree structure.\n * @internal\n */\nexport abstract class FilteredNodesHandler<TProcessedFilteredNodes, TFilterTargets, TFilteredTreeNode extends BaseFilteredTreeNode<TFilteredTreeNode>> {\n public readonly root: FilteredTreeRootNode<TFilteredTreeNode> = {\n children: new Map(),\n };\n public readonly filteredNodesArr = new Array<TFilteredTreeNode>();\n\n /** Returns filtered tree node type based on its' className */\n public abstract getType(className: string): Promise<TFilteredTreeNode[\"type\"]>;\n /** Converts nodes to filter targets */\n public abstract convertNodesToFilterTargets(filteredNodes: TFilteredTreeNode[], processedFilteredNodes: TProcessedFilteredNodes): TFilterTargets | undefined;\n /**\n * Processes filtered nodes.\n *\n * Nodes are created using filtering paths, and some information is not present in the filtering paths.\n * Because of this, some nodes may need to be processed to get additional information.\n *\n * E.g. Retrieving categoryId of elements can't be done using filtering paths.\n */\n public abstract getProcessedFilteredNodes(): Promise<TProcessedFilteredNodes>;\n /** Creates filtered nodes */\n public abstract createFilteredTreeNode(props: {\n type: TFilteredTreeNode[\"type\"];\n id: Id64String;\n isFilterTarget: boolean;\n parent: TFilteredTreeNode | FilteredTreeRootNode<TFilteredTreeNode>;\n }): TFilteredTreeNode;\n\n public async processFilteredNodes(): Promise<{\n getNodeFilterTargets: (node: HierarchyNode & { key: ClassGroupingNodeKey | InstancesNodeKey }) => TFilterTargets | undefined;\n }> {\n const processedFilteredNodes = await this.getProcessedFilteredNodes();\n return {\n getNodeFilterTargets: (node: HierarchyNode & { key: ClassGroupingNodeKey | InstancesNodeKey }) => this.getNodeFilterTargets(node, processedFilteredNodes),\n };\n }\n\n /** Takes a new node and adds it to the tree structure. */\n public async accept(props: {\n instanceKey: InstanceKey;\n parentNode: TFilteredTreeNode | FilteredTreeRootNode<TFilteredTreeNode>;\n isFilterTarget: boolean;\n }): Promise<TFilteredTreeNode> {\n const { instanceKey, parentNode, isFilterTarget } = props;\n const type = await this.getType(instanceKey.className);\n\n const newNode = this.createFilteredTreeNode({\n type,\n id: instanceKey.id,\n isFilterTarget,\n parent: parentNode,\n });\n (parentNode.children ??= new Map()).set(instanceKey.id, newNode);\n this.filteredNodesArr.push(newNode);\n return newNode;\n }\n\n /** Takes a specific node and gets all filter targets related to it. */\n private getNodeFilterTargets(\n node: HierarchyNode & { key: ClassGroupingNodeKey | InstancesNodeKey },\n processedFilteredNodes: TProcessedFilteredNodes,\n ): TFilterTargets | undefined {\n let lookupParents: Array<FilteredTreeRootNode<TFilteredTreeNode> | TFilteredTreeNode> = [this.root];\n\n // find the filtered parent nodes of the `node`\n for (const parentKey of node.parentKeys) {\n if (!HierarchyNodeKey.isInstances(parentKey)) {\n continue;\n }\n\n // tree node might be merged from multiple instances. As filtered tree stores only one instance per node, we need to find all matching nodes\n // and use them when checking for matching node in one level deeper.\n const parentNodes = this.findMatchingFilteredNodes(\n lookupParents,\n parentKey.instanceKeys.map((key) => key.id),\n );\n if (parentNodes.length === 0) {\n return undefined;\n }\n lookupParents = parentNodes;\n }\n\n const ids = HierarchyNode.isInstancesNode(node) ? node.key.instanceKeys.map(({ id }) => id) : node.groupedInstanceKeys.map(({ id }) => id);\n // find filtered nodes that match the `node`\n const filteredNodes = this.findMatchingFilteredNodes(lookupParents, ids);\n if (filteredNodes.length === 0) {\n return undefined;\n }\n\n return this.convertNodesToFilterTargets(filteredNodes, processedFilteredNodes);\n }\n\n /** Finds filtered nodes that match the given keys. */\n private findMatchingFilteredNodes(lookupParents: Array<FilteredTreeRootNode<TFilteredTreeNode> | TFilteredTreeNode>, ids: Id64Arg) {\n return lookupParents.flatMap((lookup) => {\n const childrenArray = Array<TFilteredTreeNode>();\n for (const id of Id64.iterable(ids)) {\n const node = lookup.children?.get(id);\n if (node) {\n childrenArray.push(node);\n }\n }\n return childrenArray;\n });\n }\n}\n\n/** @internal */\nexport interface FilteredTree<TFilterTargets> {\n getFilterTargets: (node: HierarchyNode & { key: ClassGroupingNodeKey | InstancesNodeKey }) => TFilterTargets | undefined;\n}\n\n/** @internal */\nexport interface CreateFilteredTreeProps<TProcessedFilteredNodes, TFilterTargets, TFilteredTreeNode extends BaseFilteredTreeNode<TFilteredTreeNode>> {\n filteredNodesHandler: FilteredNodesHandler<TProcessedFilteredNodes, TFilterTargets, TFilteredTreeNode>;\n filteringPaths: HierarchyFilteringPath[];\n}\n\n/**\n * Function iterates over filtering paths and creates uses `filteredNodesHandler` to create a filtered tree.\n * @internal\n */\nexport async function createFilteredTree<TProcessedFilteredNodes, TFilterTargets, TFilteredTreeNode extends BaseFilteredTreeNode<TFilteredTreeNode>>(\n props: CreateFilteredTreeProps<TProcessedFilteredNodes, TFilterTargets, TFilteredTreeNode>,\n): Promise<FilteredTree<TFilterTargets>> {\n const { filteringPaths, filteredNodesHandler } = props;\n\n for (const filteringPath of filteringPaths) {\n const normalizedPath = HierarchyFilteringPath.normalize(filteringPath).path;\n\n let parentNode: FilteredTreeRootNode<TFilteredTreeNode> | TFilteredTreeNode = filteredNodesHandler.root;\n for (let i = 0; i < normalizedPath.length; ++i) {\n if (\"type\" in parentNode && \"isFilterTarget\" in parentNode && parentNode.isFilterTarget) {\n break;\n }\n\n const identifier = normalizedPath[i];\n\n if (!HierarchyNodeIdentifier.isInstanceNodeIdentifier(identifier)) {\n break;\n }\n\n const currentNode: TFilteredTreeNode | undefined = parentNode.children?.get(identifier.id);\n if (currentNode !== undefined) {\n parentNode = currentNode;\n continue;\n }\n parentNode = await filteredNodesHandler.accept({\n instanceKey: identifier,\n parentNode,\n isFilterTarget: i === normalizedPath.length - 1,\n });\n }\n }\n const processedFilteredNodes = await filteredNodesHandler.processFilteredNodes();\n return {\n getFilterTargets: (node: HierarchyNode & { key: ClassGroupingNodeKey | InstancesNodeKey }) => processedFilteredNodes.getNodeFilterTargets(node),\n };\n}\n"]}
@@ -40,7 +40,7 @@ export interface BaseTreeVisibilityHandlerOverrides {
40
40
  }
41
41
  /** @internal */
42
42
  export interface BaseIdsCache {
43
- hasSubModel: (elementId: Id64String) => Promise<boolean>;
43
+ hasSubModel: (elementId: Id64String) => Observable<boolean>;
44
44
  getElementsCount: (props: {
45
45
  modelId: Id64String;
46
46
  categoryId: Id64String;
@@ -66,6 +66,7 @@ export interface BaseIdsCache {
66
66
  }>;
67
67
  getSubModels: (props: {
68
68
  modelIds: Id64Arg;
69
+ categoryId?: Id64String;
69
70
  } | {
70
71
  categoryIds: Id64Arg;
71
72
  modelId: Id64String | undefined;
@@ -2,10 +2,10 @@
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 { concat, concatAll, defaultIfEmpty, defer, EMPTY, filter, forkJoin, from, map, merge, mergeMap, of, reduce, shareReplay, startWith, Subject, take, takeUntil, tap, } from "rxjs";
5
+ import { concat, concatAll, defaultIfEmpty, defer, EMPTY, filter, forkJoin, from, identity, map, merge, mergeMap, of, reduce, shareReplay, startWith, Subject, take, takeLast, takeUntil, tap, } from "rxjs";
6
6
  import { assert, Id64 } from "@itwin/core-bentley";
7
7
  import { createVisibilityStatus } from "../Tooltip.js";
8
- import { getSetFromId64Arg, setDifference, setIntersection } from "../Utils.js";
8
+ import { getSetFromId64Arg, releaseMainThreadOnItemsCount, setDifference, setIntersection } from "../Utils.js";
9
9
  import { changeElementStateNoChildrenOperator, enableCategoryDisplay, getVisibilityFromAlwaysAndNeverDrawnElementsImpl, mergeVisibilityStatuses, } from "../VisibilityUtils.js";
10
10
  /**
11
11
  * Base class for visibility status getters and modifiers.
@@ -199,7 +199,24 @@ export class BaseVisibilityHelper {
199
199
  }
200
200
  return (modelIdFromProps
201
201
  ? from(Id64.iterable(categoryIds)).pipe(map((categoryId) => ({ id: categoryId, models: modelIdFromProps })))
202
- : this.#props.baseIdsCache.getModels({ categoryIds })).pipe(map(({ id, models }) => {
202
+ : this.#props.baseIdsCache.getModels({ categoryIds })).pipe(mergeMap(({ id, models }) => {
203
+ if (!this.#props.viewport.isAlwaysDrawnExclusive) {
204
+ return of({ id, models });
205
+ }
206
+ // Ignore categories that don't have root geometric elements in always drawn exclusive mode
207
+ if (!models) {
208
+ return EMPTY;
209
+ }
210
+ return from(Id64.iterable(models)).pipe(mergeMap((modelId) => forkJoin({
211
+ modelId: of(modelId),
212
+ elementCount: this.#props.baseIdsCache.getElementsCount({ modelId, categoryId: id }),
213
+ })), reduce((acc, { modelId, elementCount }) => {
214
+ if (elementCount > 0) {
215
+ acc.models.push(modelId);
216
+ }
217
+ return acc;
218
+ }, { id, models: new Array() }), filter(({ models: modelsWithElements }) => modelsWithElements.length > 0));
219
+ }), map(({ id, models }) => {
203
220
  const acc = { categoryId: id, visibleModels: new Array(), hiddenModels: new Array() };
204
221
  if (!models) {
205
222
  return acc;
@@ -217,7 +234,7 @@ export class BaseVisibilityHelper {
217
234
  return merge(
218
235
  // For hidden models we only need to check subModels
219
236
  hiddenModels.length > 0
220
- ? this.#props.baseIdsCache.getSubModels({ modelIds: hiddenModels }).pipe(mergeMap(({ subModels }) => {
237
+ ? this.#props.baseIdsCache.getSubModels({ modelIds: hiddenModels, categoryId }).pipe(mergeMap(({ subModels }) => {
221
238
  if (subModels && Id64.sizeOf(subModels) > 0) {
222
239
  return this.getModelsVisibilityStatus({
223
240
  modelIds: subModels,
@@ -241,7 +258,7 @@ export class BaseVisibilityHelper {
241
258
  return this.getSubCategoriesVisibilityStatus({ categoryId, modelId: modelIdFromProps, subCategoryIds: subCategories });
242
259
  }
243
260
  return EMPTY;
244
- }))).pipe(defaultIfEmpty(createVisibilityStatus(this.#props.viewport.viewsCategory(categoryId) ? "visible" : "hidden")));
261
+ }))).pipe(defaultIfEmpty(createVisibilityStatus(!this.#props.viewport.isAlwaysDrawnExclusive && this.#props.viewport.viewsCategory(categoryId) ? "visible" : "hidden")));
245
262
  }), mergeVisibilityStatuses);
246
263
  });
247
264
  return this.#props.overrideHandler
@@ -294,7 +311,7 @@ export class BaseVisibilityHelper {
294
311
  }
295
312
  // TODO: check child elements that are subModels
296
313
  if (!this.#props.viewport.viewsModel(modelId)) {
297
- return from(elementIds).pipe(mergeMap((elementId) => from(this.#props.baseIdsCache.hasSubModel(elementId)).pipe(mergeMap((isSubModel) => {
314
+ return from(elementIds).pipe(releaseMainThreadOnItemsCount(100), mergeMap((elementId) => this.#props.baseIdsCache.hasSubModel(elementId).pipe(mergeMap((isSubModel) => {
298
315
  if (isSubModel) {
299
316
  return this.getModelsVisibilityStatus({
300
317
  modelIds: elementId,
@@ -311,7 +328,7 @@ export class BaseVisibilityHelper {
311
328
  elements: elementIds,
312
329
  defaultStatus: () => this.getVisibleModelCategoriesDirectVisibilityStatus({ categoryIds: categoryId, modelId }),
313
330
  }).pipe(mergeMap((visibilityStatusAlwaysAndNeverDraw) => {
314
- return from(Id64.iterable(elementIds)).pipe(mergeMap((elementId) => from(this.#props.baseIdsCache.hasSubModel(elementId)).pipe(mergeMap((isSubModel) => {
331
+ return from(Id64.iterable(elementIds)).pipe(mergeMap((elementId) => this.#props.baseIdsCache.hasSubModel(elementId).pipe(mergeMap((isSubModel) => {
315
332
  if (isSubModel) {
316
333
  return this.getModelsVisibilityStatus({
317
334
  modelIds: elementId,
@@ -353,14 +370,14 @@ export class BaseVisibilityHelper {
353
370
  }));
354
371
  }
355
372
  const { modelId, categoryIds } = props.queryProps;
356
- const totalCount = from(Id64.iterable(categoryIds)).pipe(mergeMap((categoryId) => this.#props.baseIdsCache.getElementsCount({ modelId, categoryId })), reduce((acc, specificModelCategoryCount) => {
357
- return acc + specificModelCategoryCount;
358
- }, 0));
359
- return forkJoin({
360
- totalCount,
361
- alwaysDrawn: this.#alwaysAndNeverDrawnElements.getAlwaysDrawnElements(props.queryProps),
362
- neverDrawn: this.#alwaysAndNeverDrawnElements.getNeverDrawnElements(props.queryProps),
363
- }).pipe(
373
+ return from(Id64.iterable(categoryIds)).pipe(releaseMainThreadOnItemsCount(100), mergeMap((categoryId) => {
374
+ return forkJoin({
375
+ categoryId: of(categoryId),
376
+ totalCount: this.#props.baseIdsCache.getElementsCount({ modelId, categoryId }),
377
+ alwaysDrawn: this.#alwaysAndNeverDrawnElements.getAlwaysOrNeverDrawnElements({ modelIds: modelId, categoryIds: categoryId, setType: "always" }),
378
+ neverDrawn: this.#alwaysAndNeverDrawnElements.getAlwaysOrNeverDrawnElements({ modelIds: modelId, categoryIds: categoryId, setType: "never" }),
379
+ });
380
+ }),
364
381
  // There is a known bug:
365
382
  // Categories that don't have root elements will make visibility result incorrect
366
383
  // E.g.:
@@ -369,13 +386,17 @@ export class BaseVisibilityHelper {
369
386
  // - ChildElementB (CategoryB is hidden) ChildElementB is in always drawn list
370
387
  // Result will be "partial" because CategoryB will return hidden visibility, even though all elements are visible
371
388
  // TODO fix with: https://github.com/iTwin/viewer-components-react/issues/1100
372
- map((state) => {
373
- return getVisibilityFromAlwaysAndNeverDrawnElementsImpl({
389
+ mergeMap((state) => {
390
+ if (this.#props.viewport.isAlwaysDrawnExclusive && state.totalCount === 0) {
391
+ return EMPTY;
392
+ }
393
+ return of(getVisibilityFromAlwaysAndNeverDrawnElementsImpl({
374
394
  ...props,
375
395
  ...state,
376
396
  viewport,
377
- });
378
- }));
397
+ defaultStatus: () => props.defaultStatus(state.categoryId),
398
+ }));
399
+ }), defaultIfEmpty(createVisibilityStatus("hidden")), mergeVisibilityStatuses);
379
400
  }
380
401
  /**
381
402
  * Changes visibility status of models.
@@ -422,19 +443,14 @@ export class BaseVisibilityHelper {
422
443
  }
423
444
  return acc;
424
445
  }, new Set())),
425
- modelAlwaysDrawnElements: this.#alwaysAndNeverDrawnElements.getAlwaysDrawnElements({ modelId }),
426
- }).pipe(mergeMap(async ({ allModelCategories, modelAlwaysDrawnElements }) => {
446
+ modelAlwaysDrawnElements: this.#alwaysAndNeverDrawnElements.getAlwaysOrNeverDrawnElements({ modelIds: modelId, setType: "always" }),
447
+ }).pipe(mergeMap(({ allModelCategories, modelAlwaysDrawnElements }) => {
427
448
  const alwaysDrawn = this.#props.viewport.alwaysDrawn;
428
449
  if (alwaysDrawn && modelAlwaysDrawnElements) {
429
450
  viewport.setAlwaysDrawn({ elementIds: setDifference(alwaysDrawn, modelAlwaysDrawnElements) });
430
451
  }
431
- const categoriesToOverride = categoriesToNotOverride
432
- ? setDifference(allModelCategories, getSetFromId64Arg(categoriesToNotOverride))
433
- : allModelCategories;
434
- categoriesToOverride.forEach((categoryId) => {
435
- this.changeCategoryStateInViewportAccordingToModelVisibility(modelId, categoryId, false, false);
436
- });
437
452
  viewport.changeModelDisplay({ modelIds: modelId, display: true });
453
+ return from(Id64.iterable(allModelCategories)).pipe(categoriesToNotOverride ? filter((modelCategory) => !Id64.has(categoriesToNotOverride, modelCategory)) : identity, map((categoryId) => this.changeCategoryStateInViewportAccordingToModelVisibility(modelId, categoryId, false, false)), takeLast(1), defaultIfEmpty(undefined));
438
454
  }));
439
455
  }
440
456
  /** Adds per-model category overrides based on category visibility in category selector. */
@@ -542,7 +558,7 @@ export class BaseVisibilityHelper {
542
558
  return this.queueElementsVisibilityChange(elementIds, on, isDisplayedByDefault);
543
559
  }),
544
560
  // Change visibility of elements that are models
545
- from(Id64.iterable(elementIds)).pipe(mergeMap((elementId) => from(this.#props.baseIdsCache.hasSubModel(elementId)).pipe(mergeMap((isSubModel) => {
561
+ from(Id64.iterable(elementIds)).pipe(releaseMainThreadOnItemsCount(100), mergeMap((elementId) => this.#props.baseIdsCache.hasSubModel(elementId).pipe(mergeMap((isSubModel) => {
546
562
  if (isSubModel) {
547
563
  return this.changeModelsVisibilityStatus({ modelIds: elementId, on });
548
564
  }