@itwin/tree-widget-react 3.0.0-dev.6 → 3.0.1

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 (141) hide show
  1. package/CHANGELOG.md +32 -1
  2. package/README.md +358 -240
  3. package/lib/cjs/components/trees/categories-tree/CategoriesTree.d.ts +6 -13
  4. package/lib/cjs/components/trees/categories-tree/CategoriesTree.js +2 -1
  5. package/lib/cjs/components/trees/categories-tree/CategoriesTree.js.map +1 -1
  6. package/lib/cjs/components/trees/categories-tree/CategoriesTreeButtons.d.ts +20 -1
  7. package/lib/cjs/components/trees/categories-tree/CategoriesTreeButtons.js +20 -2
  8. package/lib/cjs/components/trees/categories-tree/CategoriesTreeButtons.js.map +1 -1
  9. package/lib/cjs/components/trees/categories-tree/CategoriesTreeComponent.d.ts +7 -8
  10. package/lib/cjs/components/trees/categories-tree/CategoriesTreeComponent.js +2 -2
  11. package/lib/cjs/components/trees/categories-tree/CategoriesTreeComponent.js.map +1 -1
  12. package/lib/cjs/components/trees/categories-tree/CategoriesTreeDefinition.d.ts +2 -2
  13. package/lib/cjs/components/trees/categories-tree/CategoriesTreeDefinition.js +6 -3
  14. package/lib/cjs/components/trees/categories-tree/CategoriesTreeDefinition.js.map +1 -1
  15. package/lib/cjs/components/trees/categories-tree/UseCategoriesTree.d.ts +7 -10
  16. package/lib/cjs/components/trees/categories-tree/UseCategoriesTree.js +30 -3
  17. package/lib/cjs/components/trees/categories-tree/UseCategoriesTree.js.map +1 -1
  18. package/lib/cjs/components/trees/common/UseHierarchiesLocalization.d.ts +3 -3
  19. package/lib/cjs/components/trees/common/UseHierarchiesLocalization.js.map +1 -1
  20. package/lib/cjs/components/trees/common/UseHierarchyVisibility.d.ts +20 -0
  21. package/lib/cjs/components/trees/common/UseHierarchyVisibility.js +11 -1
  22. package/lib/cjs/components/trees/common/UseHierarchyVisibility.js.map +1 -1
  23. package/lib/cjs/components/trees/common/UseIModelChangeListener.js +1 -1
  24. package/lib/cjs/components/trees/common/UseIModelChangeListener.js.map +1 -1
  25. package/lib/cjs/components/trees/common/Utils.d.ts +3 -0
  26. package/lib/cjs/components/trees/common/Utils.js +1 -0
  27. package/lib/cjs/components/trees/common/Utils.js.map +1 -1
  28. package/lib/cjs/components/trees/common/components/Tree.d.ts +8 -21
  29. package/lib/cjs/components/trees/common/components/Tree.js +5 -4
  30. package/lib/cjs/components/trees/common/components/Tree.js.map +1 -1
  31. package/lib/cjs/components/trees/common/components/TreeNodeRenderer.d.ts +2 -5
  32. package/lib/cjs/components/trees/common/components/TreeNodeRenderer.js.map +1 -1
  33. package/lib/cjs/components/trees/common/components/TreeRenderer.d.ts +3 -10
  34. package/lib/cjs/components/trees/common/components/TreeRenderer.js +2 -2
  35. package/lib/cjs/components/trees/common/components/TreeRenderer.js.map +1 -1
  36. package/lib/cjs/components/trees/common/components/TreeRenderer.scss +0 -8
  37. package/lib/cjs/components/trees/common/components/VisibilityTree.d.ts +7 -17
  38. package/lib/cjs/components/trees/common/components/VisibilityTree.js.map +1 -1
  39. package/lib/cjs/components/trees/common/components/VisibilityTreeRenderer.d.ts +4 -5
  40. package/lib/cjs/components/trees/common/components/VisibilityTreeRenderer.js.map +1 -1
  41. package/lib/cjs/components/trees/external-sources-tree/ExternalSourcesTree.d.ts +3 -8
  42. package/lib/cjs/components/trees/external-sources-tree/ExternalSourcesTree.js.map +1 -1
  43. package/lib/cjs/components/trees/external-sources-tree/ExternalSourcesTreeComponent.d.ts +3 -3
  44. package/lib/cjs/components/trees/external-sources-tree/ExternalSourcesTreeComponent.js.map +1 -1
  45. package/lib/cjs/components/trees/external-sources-tree/ExternalSourcesTreeDefinition.js +8 -5
  46. package/lib/cjs/components/trees/external-sources-tree/ExternalSourcesTreeDefinition.js.map +1 -1
  47. package/lib/cjs/components/trees/imodel-content-tree/IModelContentTree.d.ts +3 -8
  48. package/lib/cjs/components/trees/imodel-content-tree/IModelContentTree.js.map +1 -1
  49. package/lib/cjs/components/trees/imodel-content-tree/IModelContentTreeComponent.d.ts +3 -3
  50. package/lib/cjs/components/trees/imodel-content-tree/IModelContentTreeComponent.js.map +1 -1
  51. package/lib/cjs/components/trees/imodel-content-tree/IModelContentTreeDefinition.d.ts +2 -1
  52. package/lib/cjs/components/trees/imodel-content-tree/IModelContentTreeDefinition.js +17 -14
  53. package/lib/cjs/components/trees/imodel-content-tree/IModelContentTreeDefinition.js.map +1 -1
  54. package/lib/cjs/components/trees/models-tree/ModelsTree.d.ts +6 -12
  55. package/lib/cjs/components/trees/models-tree/ModelsTree.js +9 -2
  56. package/lib/cjs/components/trees/models-tree/ModelsTree.js.map +1 -1
  57. package/lib/cjs/components/trees/models-tree/ModelsTreeButtons.d.ts +24 -3
  58. package/lib/cjs/components/trees/models-tree/ModelsTreeButtons.js +23 -3
  59. package/lib/cjs/components/trees/models-tree/ModelsTreeButtons.js.map +1 -1
  60. package/lib/cjs/components/trees/models-tree/ModelsTreeComponent.d.ts +10 -11
  61. package/lib/cjs/components/trees/models-tree/ModelsTreeComponent.js +2 -2
  62. package/lib/cjs/components/trees/models-tree/ModelsTreeComponent.js.map +1 -1
  63. package/lib/cjs/components/trees/models-tree/ModelsTreeDefinition.d.ts +5 -2
  64. package/lib/cjs/components/trees/models-tree/ModelsTreeDefinition.js +13 -10
  65. package/lib/cjs/components/trees/models-tree/ModelsTreeDefinition.js.map +1 -1
  66. package/lib/cjs/components/trees/models-tree/UseModelsTree.d.ts +10 -13
  67. package/lib/cjs/components/trees/models-tree/UseModelsTree.js +42 -3
  68. package/lib/cjs/components/trees/models-tree/UseModelsTree.js.map +1 -1
  69. package/lib/cjs/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.d.ts +21 -45
  70. package/lib/cjs/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js +12 -35
  71. package/lib/cjs/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js.map +1 -1
  72. package/lib/esm/components/trees/categories-tree/CategoriesTree.d.ts +6 -13
  73. package/lib/esm/components/trees/categories-tree/CategoriesTree.js +2 -1
  74. package/lib/esm/components/trees/categories-tree/CategoriesTree.js.map +1 -1
  75. package/lib/esm/components/trees/categories-tree/CategoriesTreeButtons.d.ts +20 -1
  76. package/lib/esm/components/trees/categories-tree/CategoriesTreeButtons.js +21 -3
  77. package/lib/esm/components/trees/categories-tree/CategoriesTreeButtons.js.map +1 -1
  78. package/lib/esm/components/trees/categories-tree/CategoriesTreeComponent.d.ts +7 -8
  79. package/lib/esm/components/trees/categories-tree/CategoriesTreeComponent.js +2 -2
  80. package/lib/esm/components/trees/categories-tree/CategoriesTreeComponent.js.map +1 -1
  81. package/lib/esm/components/trees/categories-tree/CategoriesTreeDefinition.d.ts +2 -2
  82. package/lib/esm/components/trees/categories-tree/CategoriesTreeDefinition.js +7 -4
  83. package/lib/esm/components/trees/categories-tree/CategoriesTreeDefinition.js.map +1 -1
  84. package/lib/esm/components/trees/categories-tree/UseCategoriesTree.d.ts +7 -10
  85. package/lib/esm/components/trees/categories-tree/UseCategoriesTree.js +30 -3
  86. package/lib/esm/components/trees/categories-tree/UseCategoriesTree.js.map +1 -1
  87. package/lib/esm/components/trees/common/UseHierarchiesLocalization.d.ts +3 -3
  88. package/lib/esm/components/trees/common/UseHierarchiesLocalization.js.map +1 -1
  89. package/lib/esm/components/trees/common/UseHierarchyVisibility.d.ts +20 -0
  90. package/lib/esm/components/trees/common/UseHierarchyVisibility.js +10 -1
  91. package/lib/esm/components/trees/common/UseHierarchyVisibility.js.map +1 -1
  92. package/lib/esm/components/trees/common/UseIModelChangeListener.js +1 -1
  93. package/lib/esm/components/trees/common/UseIModelChangeListener.js.map +1 -1
  94. package/lib/esm/components/trees/common/Utils.d.ts +3 -0
  95. package/lib/esm/components/trees/common/Utils.js +1 -0
  96. package/lib/esm/components/trees/common/Utils.js.map +1 -1
  97. package/lib/esm/components/trees/common/components/Tree.d.ts +8 -21
  98. package/lib/esm/components/trees/common/components/Tree.js +7 -6
  99. package/lib/esm/components/trees/common/components/Tree.js.map +1 -1
  100. package/lib/esm/components/trees/common/components/TreeNodeRenderer.d.ts +2 -5
  101. package/lib/esm/components/trees/common/components/TreeNodeRenderer.js.map +1 -1
  102. package/lib/esm/components/trees/common/components/TreeRenderer.d.ts +3 -10
  103. package/lib/esm/components/trees/common/components/TreeRenderer.js +2 -2
  104. package/lib/esm/components/trees/common/components/TreeRenderer.js.map +1 -1
  105. package/lib/esm/components/trees/common/components/TreeRenderer.scss +0 -8
  106. package/lib/esm/components/trees/common/components/VisibilityTree.d.ts +7 -17
  107. package/lib/esm/components/trees/common/components/VisibilityTree.js.map +1 -1
  108. package/lib/esm/components/trees/common/components/VisibilityTreeRenderer.d.ts +4 -5
  109. package/lib/esm/components/trees/common/components/VisibilityTreeRenderer.js.map +1 -1
  110. package/lib/esm/components/trees/external-sources-tree/ExternalSourcesTree.d.ts +3 -8
  111. package/lib/esm/components/trees/external-sources-tree/ExternalSourcesTree.js.map +1 -1
  112. package/lib/esm/components/trees/external-sources-tree/ExternalSourcesTreeComponent.d.ts +3 -3
  113. package/lib/esm/components/trees/external-sources-tree/ExternalSourcesTreeComponent.js.map +1 -1
  114. package/lib/esm/components/trees/external-sources-tree/ExternalSourcesTreeDefinition.js +9 -6
  115. package/lib/esm/components/trees/external-sources-tree/ExternalSourcesTreeDefinition.js.map +1 -1
  116. package/lib/esm/components/trees/imodel-content-tree/IModelContentTree.d.ts +3 -8
  117. package/lib/esm/components/trees/imodel-content-tree/IModelContentTree.js.map +1 -1
  118. package/lib/esm/components/trees/imodel-content-tree/IModelContentTreeComponent.d.ts +3 -3
  119. package/lib/esm/components/trees/imodel-content-tree/IModelContentTreeComponent.js.map +1 -1
  120. package/lib/esm/components/trees/imodel-content-tree/IModelContentTreeDefinition.d.ts +2 -1
  121. package/lib/esm/components/trees/imodel-content-tree/IModelContentTreeDefinition.js +18 -15
  122. package/lib/esm/components/trees/imodel-content-tree/IModelContentTreeDefinition.js.map +1 -1
  123. package/lib/esm/components/trees/models-tree/ModelsTree.d.ts +6 -12
  124. package/lib/esm/components/trees/models-tree/ModelsTree.js +9 -2
  125. package/lib/esm/components/trees/models-tree/ModelsTree.js.map +1 -1
  126. package/lib/esm/components/trees/models-tree/ModelsTreeButtons.d.ts +24 -3
  127. package/lib/esm/components/trees/models-tree/ModelsTreeButtons.js +23 -3
  128. package/lib/esm/components/trees/models-tree/ModelsTreeButtons.js.map +1 -1
  129. package/lib/esm/components/trees/models-tree/ModelsTreeComponent.d.ts +10 -11
  130. package/lib/esm/components/trees/models-tree/ModelsTreeComponent.js +2 -2
  131. package/lib/esm/components/trees/models-tree/ModelsTreeComponent.js.map +1 -1
  132. package/lib/esm/components/trees/models-tree/ModelsTreeDefinition.d.ts +5 -2
  133. package/lib/esm/components/trees/models-tree/ModelsTreeDefinition.js +14 -11
  134. package/lib/esm/components/trees/models-tree/ModelsTreeDefinition.js.map +1 -1
  135. package/lib/esm/components/trees/models-tree/UseModelsTree.d.ts +10 -13
  136. package/lib/esm/components/trees/models-tree/UseModelsTree.js +43 -4
  137. package/lib/esm/components/trees/models-tree/UseModelsTree.js.map +1 -1
  138. package/lib/esm/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.d.ts +21 -45
  139. package/lib/esm/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js +13 -36
  140. package/lib/esm/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js.map +1 -1
  141. package/package.json +34 -32
package/README.md CHANGED
@@ -12,9 +12,9 @@ The new `3.0` version of the package contains a few notable changes, compared to
12
12
 
13
13
  - To allow easier customization of widget placement, the package now delivers a `createTreeWidget()` function that creates a tree widget definition, instead of a full `UiItemsProvider` implementation. See [Usage](#usage) section for details on how to use the new function.
14
14
 
15
- - The underlying engine for building hierarchies has been changed from `@itwin/presentation-components` to `@itwin/presentation-hierarchies-react`. This is a significant change as the new library runs plain ECSQL queries and handles hierarchy creation on the frontend, as opposed to the previous version that relied on the backend to provide hierarchy data. This change allows this package to use more optimal queries and to be more flexible in terms of hierarchy creation.
15
+ - The underlying engine for building hierarchies has been changed from `@itwin/presentation-components` to `@itwin/presentation-hierarchies-react`. This is a significant change as the new library runs plain ECSQL queries and handles hierarchy creation on the frontend, as opposed to the previous version that relied on the backend to provide hierarchy data. This change allows this package to use more optimal queries and to be more flexible in terms of hierarchy creation. As a result, we're seeing 30-40% performance improvement for loading nodes in the Models tree when using a web backend and orders of magnitude improvement when using a local backend (desktop & mobile case).
16
16
 
17
- This change adds a requirement for all tree components in this package to access iModels' metadata, which is achieved through a required `getSchemaContext` prop. See [Creating schema context](#creating-schema-context) section for an example implementation of this function.
17
+ This change adds a requirement for all tree components in this package to access iModels' metadata, which is achieved through a required `getSchemaContext` prop. See [Creating schema context](#creating-schema-context) section for an example implementation of this function. This also adds an `@itwin/ecschema-metadata` peer dependency on version `^4.0.0`.
18
18
 
19
19
  In addition, the new tree components don't rely on the global selection manager provided by `@itwin/presentation-frontend` package. Instead, they require a unified selection storage object created using `createStorage()` function from `@itwin/unified-selection` package. See sections of individual tree components for how to supply it to them, and [Creating unified selection storage](#creating-unified-selection-storage) section for an example for how to create the storage.
20
20
 
@@ -24,11 +24,16 @@ The new `3.0` version of the package contains a few notable changes, compared to
24
24
  | ----------------------------------------------- | ----------------------------------------------- |
25
25
  | ![Tree widget 2.x](./media/tree-widget-2.x.png) | ![Tree widget 3.0](./media/tree-widget-3.0.png) |
26
26
 
27
+ This change introduces an `@itwin/itwinui-react` peer dependency on version `^3.11.0`.
28
+
27
29
  - The tree components now have hierarchy level size limiting and filtering features always turned on. The features were already available in `2.x` versions, but were not enabled by default. See [Hierarchy level size limiting](#hierarchy-level-size-limiting) and [Hierarchy level filtering](#hierarchy-level-filtering) sections for more details.
28
30
 
31
+ - Behavior of header buttons like "Show all", "Hide all", etc. has been changed in filtered hierarchies' case. Previously they applied the visibility change on everything, no matter if the hierarchy is filtered or not. Now, when a hierarchy is filtered, only the nodes in the filtered hierarchy are affected.
32
+
29
33
  - Models tree:
30
34
  - The label filtering feature has been expanded to filter not only up to Models, but the whole hierarchy. This allows filtering the hierarchy to additionally find Category or Element nodes.
31
35
  - [Focus mode](#focus-mode) feature has been added to allow automatic hierarchy filtering as the application selection changes.
36
+ - In addition to the two filtering-related improvements above, we now allow displaying a subset of the tree by providing a `getFilteredPaths` function. See [Displaying a subset of the tree](#displaying-a-subset-of-the-tree) section for more details.
32
37
  - Display states' control has been modified to be hierarchy based. This means that changing display state of something deep in the hierarchy affects checkbox state of all its ancestors. And vice versa - changing display state of an ancestor affects all its descendants.
33
38
 
34
39
  ## Usage
@@ -37,50 +42,56 @@ Typically, the package is used with an [AppUI](https://github.com/iTwin/appui/tr
37
42
 
38
43
  In any case, **before** using any APIs or components delivered with the package, it needs to be initialized:
39
44
 
40
- ```ts
41
- import { IModelApp } from "@itwin/core-frontend";
45
+ <!-- [[include: [TreeWidget.TreeWidgetInitializeImports, TreeWidget.TreeWidgetInitialize], tsx]] -->
46
+ <!-- BEGIN EXTRACTION -->
47
+
48
+ ```tsx
42
49
  import { TreeWidget } from "@itwin/tree-widget-react";
50
+ import { IModelApp } from "@itwin/core-frontend";
43
51
 
44
52
  await TreeWidget.initialize(IModelApp.localization);
45
53
  ```
46
54
 
55
+ <!-- END EXTRACTION -->
56
+
47
57
  In [AppUI](https://github.com/iTwin/appui/tree/master/ui/appui-react) based applications widgets are typically provided using `UiItemsProvider` implementations. The `@itwin/tree-widget-react` package delivers `createTreeWidget` function that can be used to add the tree widget to UI through a `UiItemsProvider`:
48
58
 
49
- ```ts
59
+ <!-- [[include: [TreeWidget.RegisterExampleImports, TreeWidget.RegisterExample], tsx]] -->
60
+ <!-- BEGIN EXTRACTION -->
61
+
62
+ ```tsx
50
63
  import { UiItemsManager } from "@itwin/appui-react";
51
64
  import { createTreeWidget, ModelsTreeComponent } from "@itwin/tree-widget-react";
52
65
 
53
66
  UiItemsManager.register({
54
67
  id: "tree-widget-provider",
55
- getWidgets: () => [
56
- createTreeWidget({
57
- trees: [
58
- // add the Models tree component delivered with the package
59
- {
60
- id: ModelsTreeComponent.id,
61
- getLabel: () => ModelsTreeComponent.getLabel(),
62
- render: (props) => (
63
- <ModelsTreeComponent
64
- // see "Models tree" section for details regarding `getSchemaContext` and `selectionStorage` props
65
- getSchemaContext={getSchemaContext}
66
- selectionStorage={unifiedSelectionStorage}
67
- selectionMode={"extended"}
68
- />
69
- ),
70
- },
71
- // add a custom component
72
- {
73
- id: "my-tree-id",
74
- startIcon: <MyTreeIcon />,
75
- getLabel: () => "My Custom Tree",
76
- render: () => <>This is my custom tree.</>,
77
- },
78
- ],
79
- }),
80
- ],
68
+ getWidgets: () =>
69
+ [
70
+ createTreeWidget({
71
+ trees: [
72
+ // add a custom component
73
+ { id: "my-tree-id", startIcon: <svg />, getLabel: () => "My Custom Tree", render: () => <>This is my custom tree.</> },
74
+ // add the Models tree component delivered with the package
75
+ {
76
+ id: ModelsTreeComponent.id,
77
+ getLabel: () => ModelsTreeComponent.getLabel(),
78
+ render: (props) => (
79
+ <ModelsTreeComponent
80
+ // see "Creating schema context" section for example implementation
81
+ getSchemaContext={getSchemaContext}
82
+ // see "Creating unified selection storage" section for example implementation
83
+ selectionStorage={unifiedSelectionStorage}
84
+ />
85
+ ),
86
+ },
87
+ ],
88
+ }),
89
+ ] as readonly Widget[],
81
90
  });
82
91
  ```
83
92
 
93
+ <!-- END EXTRACTION -->
94
+
84
95
  As seen in the above code snippet, `createTreeWidget` takes a list of trees that are displayed in the widget. This package delivers a number of tree components for everyone's use (see below), but providing custom trees is also an option.
85
96
 
86
97
  ## Components
@@ -99,44 +110,30 @@ The component renders a tree that tries to replicate how a typical "Models" tree
99
110
 
100
111
  Typical usage:
101
112
 
113
+ <!-- [[include: [TreeWidget.ModelsTreeExampleImports, TreeWidget.ModelsTreeExample], tsx]] -->
114
+ <!-- BEGIN EXTRACTION -->
115
+
102
116
  ```tsx
103
- import { IModelConnection } from "@itwin/core-frontend";
104
- import { SchemaContext } from "@itwin/ecschema-metadata";
105
- import { SelectionStorage } from "@itwin/unified-selection";
106
117
  import { ModelsTreeComponent } from "@itwin/tree-widget-react";
107
118
 
108
- // The Models tree requires a unified selection storage to support selection synchronization with the
109
- // application. The storage should be created once per application and shared across multiple selection-enabled
110
- // components.
111
- function getUnifiedSelectionStorage(): SelectionStorage {
112
- // see "Creating unified selection storage" section for example implementation
113
- }
114
-
115
- // Schema context is used by Models tree to access iModels metadata. Similar to selection storage, it should be
116
- // created once per application and shared across multiple components.
117
- function getSchemaContext(imodel: IModelConnection): SchemaContext {
118
- // see "Creating schema context" section for example implementation
119
- }
120
-
121
119
  function MyWidget() {
122
120
  return (
123
121
  <ModelsTreeComponent
122
+ // see "Creating schema context" section for example implementation
124
123
  getSchemaContext={getSchemaContext}
125
- selectionStorage={getUnifiedSelectionStorage()}
124
+ // see "Creating unified selection storage" section for example implementation
125
+ selectionStorage={unifiedSelectionStorage}
126
126
  headerButtons={[
127
- (props) => <ModelsTreeComponent.ShowAllButton {...props} />,
128
- (props) => <ModelsTreeComponent.HideAllButton {...props} />,
129
- (props) => <MyCustomButton />,
127
+ (props) => <ModelsTreeComponent.ShowAllButton {...props} key={"ShowAllButton"} />,
128
+ (props) => <ModelsTreeComponent.HideAllButton {...props} key={"HideAllButton"} />,
130
129
  ]}
131
- selectionMode={"extended"}
132
- hierarchyConfig={{
133
- elementClassGrouping: "enable",
134
- }}
135
130
  />
136
131
  );
137
132
  }
138
133
  ```
139
134
 
135
+ <!-- END EXTRACTION -->
136
+
140
137
  Available header buttons:
141
138
 
142
139
  - `ModelsTreeComponent.ShowAllButton` makes everything in the iModel displayed.
@@ -161,13 +158,48 @@ This package provides building blocks for custom models tree:
161
158
 
162
159
  Example:
163
160
 
161
+ <!-- [[include: [TreeWidget.CustomModelsTreeExampleImports, TreeWidget.CustomModelsTreeExample], tsx]] -->
162
+ <!-- BEGIN EXTRACTION -->
163
+
164
164
  ```tsx
165
+ import { TreeWithHeader, useModelsTree, useModelsTreeButtonProps, VisibilityTree, VisibilityTreeRenderer } from "@itwin/tree-widget-react";
166
+ import type { SelectionStorage } from "@itwin/unified-selection";
167
+ import type { IModelConnection, Viewport } from "@itwin/core-frontend";
168
+ import type { SchemaContext } from "@itwin/ecschema-metadata";
169
+ import type { ComponentPropsWithoutRef } from "react";
170
+
171
+ type VisibilityTreeRendererProps = ComponentPropsWithoutRef<typeof VisibilityTreeRenderer>;
172
+ type CustomModelsTreeRendererProps = Parameters<ComponentPropsWithoutRef<typeof VisibilityTree>["treeRenderer"]>[0];
173
+ function CustomModelsTreeRenderer(props: CustomModelsTreeRendererProps) {
174
+ const getLabel = props.getLabel;
175
+ const getLabelCallback = useCallback<Required<VisibilityTreeRendererProps>["getLabel"]>(
176
+ (node) => {
177
+ const originalLabel = getLabel(node);
178
+ return <>Custom node - {originalLabel}</>;
179
+ },
180
+ [getLabel],
181
+ );
182
+ return <VisibilityTreeRenderer {...props} getLabel={getLabelCallback} getSublabel={getSublabel} />;
183
+ }
184
+
185
+ interface CustomModelsTreeProps {
186
+ imodel: IModelConnection;
187
+ viewport: Viewport;
188
+ getSchemaContext: (imodel: IModelConnection) => SchemaContext;
189
+ selectionStorage: SelectionStorage;
190
+ }
191
+
165
192
  function CustomModelsTreeComponent({ imodel, viewport, getSchemaContext, selectionStorage }: CustomModelsTreeProps) {
166
- const buttonProps = useModelsTreeButtonProps({ imodel, viewport });
193
+ const { buttonProps } = useModelsTreeButtonProps({ imodel, viewport });
167
194
  const { modelsTreeProps, rendererProps } = useModelsTree({ activeView: viewport });
168
195
 
169
196
  return (
170
- <TreeWithHeader buttons={[<ModelsTreeComponent.ShowAllButton {...buttonProps} />, <ModelsTreeComponent.HideAllButton {...buttonProps} />]}>
197
+ <TreeWithHeader
198
+ buttons={[
199
+ <ModelsTreeComponent.ShowAllButton {...buttonProps} key={"ShowAllButton"} />,
200
+ <ModelsTreeComponent.HideAllButton {...buttonProps} key={"HideAllButton"} />,
201
+ ]}
202
+ >
171
203
  <VisibilityTree
172
204
  {...modelsTreeProps}
173
205
  getSchemaContext={getSchemaContext}
@@ -178,49 +210,54 @@ function CustomModelsTreeComponent({ imodel, viewport, getSchemaContext, selecti
178
210
  </TreeWithHeader>
179
211
  );
180
212
  }
181
-
182
- type VisibilityTreeRendererProps = ComponentPropsWithoutRef<typeof VisibilityTreeRenderer>;
183
- type CustomModelsTreeRendererProps = Parameters<ComponentPropsWithoutRef<typeof VisibilityTree>["treeRenderer"]>[0];
184
-
185
- function CustomModelsTreeRenderer(props: CustomModelsTreeRendererProps) {
186
- const getLabel = useCallback<Required<VisibilityTreeRendererProps>["getLabel"]>(
187
- (node) => {
188
- const originalLabel = props.getLabel(node);
189
- return <>Custom node - {originalLabel}</>;
190
- },
191
- [props.getLabel],
192
- );
193
- return <VisibilityTreeRenderer {...props} getLabel={getLabel} getSublabel={getSublabel} />;
194
- }
195
213
  ```
196
214
 
215
+ <!-- END EXTRACTION -->
216
+
197
217
  #### Displaying a subset of the tree
198
218
 
199
219
  Models tree allows displaying a subset of all nodes by providing a `getFilteredPaths` function, which receives a `createInstanceKeyPaths` function for creating hierarchy node paths from instance keys or an instance label and returns a list of hierarchy node paths targeting some nodes. When these paths are provided, the displayed hierarchy consists only of the targeted nodes, their ancestors, and their children. Example implementation of `getFilteredPaths`:
200
220
 
221
+ <!-- [[include: [TreeWidget.GetFilteredPathsComponentExample], tsx]] -->
222
+ <!-- BEGIN EXTRACTION -->
223
+
201
224
  ```tsx
202
- const getFilteredPaths = async ({ createInstanceKeyPaths }) => {
203
- return createInstanceKeyPaths({
204
- // list of instance keys representing nodes that should be displayed in the hierarchy
205
- keys: myInstanceKeys,
206
- // instead of providing instance keys, a label can be provided to display all nodes that contain it
207
- // label: "MyLabel"
208
- });
209
- };
210
- ```
225
+ type UseModelsTreeProps = Parameters<typeof useModelsTree>[0];
226
+ type GetFilteredPathsType = Exclude<UseModelsTreeProps["getFilteredPaths"], undefined>;
227
+ interface CustomModelsTreeProps {
228
+ viewport: Viewport;
229
+ selectionStorage: SelectionStorage;
230
+ imodel: IModelConnection;
231
+ targetItems: InstanceKey[];
232
+ }
211
233
 
212
- The `ModelsTree` component displays a message when too many matches are found while filtering the tree; for this reason, it is recommended to throw `FilterLimitExceededError` that is provided by this package when the displayed subset is too large. Typically, this error is thrown when there are more than 100 matches. The error is cleared when a new reference for `getFilteredPaths` is provided.
234
+ function CustomModelsTreeComponent({ viewport, selectionStorage, imodel, targetItems }: CustomModelsTreeProps) {
235
+ const getFilteredPaths = useCallback<GetFilteredPathsType>(
236
+ async ({ createInstanceKeyPaths }) => {
237
+ return createInstanceKeyPaths({
238
+ // list of instance keys representing nodes that should be displayed in the hierarchy
239
+ targetItems,
240
+ });
241
+ },
242
+ [targetItems],
243
+ );
213
244
 
214
- When a filter is provided or instance focus mode is used, the hierarchy automatically expands to show the targeted nodes. This might not be desirable when displaying a subset of the hierarchy and can be disabled by adding the `autoExpand: false` option to each path returned by `getFilteredPaths`:
245
+ const { modelsTreeProps, rendererProps } = useModelsTree({ activeView: viewport, getFilteredPaths });
215
246
 
216
- ```tsx
217
- const getFilteredPaths = async ({ createInstanceKeyPaths }) => {
218
- const paths = await createInstanceKeyPaths({ keys: myInstanceKeys });
219
- // disable auto-expansion
220
- return paths.map((path) => ({ path, options: { autoExpand: false } }));
221
- };
247
+ return (
248
+ <VisibilityTree
249
+ {...modelsTreeProps}
250
+ getSchemaContext={getSchemaContext}
251
+ selectionStorage={selectionStorage}
252
+ imodel={imodel}
253
+ treeRenderer={(props) => <VisibilityTreeRenderer {...props} {...rendererProps} />}
254
+ />
255
+ );
256
+ }
222
257
  ```
223
258
 
259
+ <!-- END EXTRACTION -->
260
+
224
261
  ### Categories tree
225
262
 
226
263
  The component, based on the active view, renders a hierarchy of either spatial (3d) or drawing (2d) categories. The hierarchy consists of two levels - the category (spatial or drawing) and its sub-categories. There's also a header that renders categories search box and various visibility control buttons.
@@ -229,40 +266,27 @@ The component, based on the active view, renders a hierarchy of either spatial (
229
266
 
230
267
  Typical usage:
231
268
 
232
- ```tsx
233
- import { IModelConnection } from "@itwin/core-frontend";
234
- import { SchemaContext } from "@itwin/ecschema-metadata";
235
- import { SelectionStorage } from "@itwin/unified-selection";
236
- import { CategoriesTreeComponent, CategoriesTreeComponent } from "@itwin/tree-widget-react";
237
-
238
- // The Categories tree requires a unified selection storage to support selection synchronization with the
239
- // application. The storage should be created once per application and shared across multiple selection-enabled
240
- // components.
241
- function getUnifiedSelectionStorage(): SelectionStorage {
242
- // see "Creating unified selection storage" section for example implementation
243
- }
269
+ <!-- [[include: [TreeWidget.CategoriesTreeExampleImports, TreeWidget.CategoriesTreeExample], tsx]] -->
270
+ <!-- BEGIN EXTRACTION -->
244
271
 
245
- // Schema context is used by Categories tree to access iModels metadata. Similar to selection storage, it should be
246
- // created once per application and shared across multiple components.
247
- function getSchemaContext(imodel: IModelConnection): SchemaContext {
248
- // see "Creating schema context" section for example implementation
249
- }
272
+ ```tsx
273
+ import { CategoriesTreeComponent } from "@itwin/tree-widget-react";
250
274
 
251
275
  function MyWidget() {
252
276
  return (
253
277
  <CategoriesTreeComponent
278
+ // see "Creating schema context" section for example implementation
254
279
  getSchemaContext={getSchemaContext}
255
- selectionStorage={getUnifiedSelectionStorage()}
256
- headerButtons={[
257
- (props) => <CategoriesTreeComponent.ShowAllButton {...props} />,
258
- (props) => <CategoriesTreeComponent.HideAllButton {...props} />,
259
- (props) => <MyCustomButton />,
260
- ]}
280
+ // see "Creating unified selection storage" section for example implementation
281
+ selectionStorage={unifiedSelectionStorage}
282
+ headerButtons={[(props) => <CategoriesTreeComponent.ShowAllButton {...props} />, (props) => <CategoriesTreeComponent.HideAllButton {...props} />]}
261
283
  />
262
284
  );
263
285
  }
264
286
  ```
265
287
 
288
+ <!-- END EXTRACTION -->
289
+
266
290
  Available header buttons:
267
291
 
268
292
  - `ModelsTreeComponent.ShowAllButton` makes all categories and their subcategories displayed.
@@ -278,44 +302,68 @@ This package provides building blocks for custom categories tree:
278
302
 
279
303
  Example:
280
304
 
281
- ```tsx
282
- function CustomCategoriesTreeComponent({ imodel, viewport, getSchemaContext, selectionStorage }: CustomCategoriesTreeProps) {
283
- const buttonProps = useCategoriesTreeButtonProps({ imodel, viewport });
284
- const { categoriesTreeProps, rendererProps } = useCategoriesTree({ activeView: viewport });
305
+ <!-- [[include: [TreeWidget.CustomCategoriesTreeExampleImports, TreeWidget.CustomCategoriesTreeExample], tsx]] -->
306
+ <!-- BEGIN EXTRACTION -->
285
307
 
286
- return (
287
- <TreeWithHeader buttons={[<CategoriesTreeComponent.ShowAllButton {...buttonProps} />, <CategoriesTreeComponent.HideAllButton {...buttonProps} />]}>
288
- <VisibilityTree
289
- {...categoriesTreeProps}
290
- getSchemaContext={getSchemaContext}
291
- selectionStorage={selectionStorage}
292
- imodel={imodel}
293
- treeRenderer={(props) => <CustomCategoriesTreeRenderer {...props} {...rendererProps} />}
294
- />
295
- </TreeWithHeader>
296
- );
297
- }
308
+ ```tsx
309
+ import { TreeWithHeader, useCategoriesTree, useCategoriesTreeButtonProps, VisibilityTree, VisibilityTreeRenderer } from "@itwin/tree-widget-react";
310
+ import type { IModelConnection, Viewport } from "@itwin/core-frontend";
311
+ import type { SelectionStorage } from "@itwin/unified-selection";
312
+ import type { SchemaContext } from "@itwin/ecschema-metadata";
313
+ import type { ComponentPropsWithoutRef } from "react";
298
314
 
299
315
  type VisibilityTreeRendererProps = ComponentPropsWithoutRef<typeof VisibilityTreeRenderer>;
300
316
  type CustomCategoriesTreeRendererProps = Parameters<ComponentPropsWithoutRef<typeof VisibilityTree>["treeRenderer"]>[0];
301
317
 
302
318
  function CustomCategoriesTreeRenderer(props: CustomCategoriesTreeRendererProps) {
303
- const getLabel = useCallback<Required<VisibilityTreeRendererProps>["getLabel"]>(
319
+ const getLabel = props.getLabel;
320
+ const getLabelCallback = useCallback<Required<VisibilityTreeRendererProps>["getLabel"]>(
304
321
  (node) => {
305
- const originalLabel = props.getLabel(node);
322
+ const originalLabel = getLabel(node);
306
323
  return <>Custom node - {originalLabel}</>;
307
324
  },
308
- [props.getLabel],
325
+ [getLabel],
309
326
  );
310
327
 
311
328
  const getSublabel = useCallback<Required<VisibilityTreeRendererProps>["getSublabel"]>(() => {
312
329
  return <>Custom sub label</>;
313
330
  }, []);
314
331
 
315
- return <VisibilityTreeRenderer {...props} getLabel={getLabel} getSublabel={getSublabel} />;
332
+ return <VisibilityTreeRenderer {...props} getLabel={getLabelCallback} getSublabel={getSublabel} />;
333
+ }
334
+
335
+ interface CustomCategoriesTreeProps {
336
+ imodel: IModelConnection;
337
+ viewport: Viewport;
338
+ getSchemaContext: (imodel: IModelConnection) => SchemaContext;
339
+ selectionStorage: SelectionStorage;
340
+ }
341
+
342
+ function CustomCategoriesTreeComponent({ imodel, viewport, getSchemaContext, selectionStorage }: CustomCategoriesTreeProps) {
343
+ const { buttonProps } = useCategoriesTreeButtonProps({ viewport });
344
+ const { categoriesTreeProps, rendererProps } = useCategoriesTree({ activeView: viewport, filter: "" });
345
+
346
+ return (
347
+ <TreeWithHeader
348
+ buttons={[
349
+ <CategoriesTreeComponent.ShowAllButton {...buttonProps} key={"ShowAllButton"} />,
350
+ <CategoriesTreeComponent.HideAllButton {...buttonProps} key={"HideAllButton"} />,
351
+ ]}
352
+ >
353
+ <VisibilityTree
354
+ {...categoriesTreeProps}
355
+ getSchemaContext={getSchemaContext}
356
+ selectionStorage={selectionStorage}
357
+ imodel={imodel}
358
+ treeRenderer={(props) => <CustomCategoriesTreeRenderer {...props} {...rendererProps} />}
359
+ />
360
+ </TreeWithHeader>
361
+ );
316
362
  }
317
363
  ```
318
364
 
365
+ <!-- END EXTRACTION -->
366
+
319
367
  ### iModel content tree
320
368
 
321
369
  The component renders a similar hierarchy to [Models tree](#models-tree), but with the following changes:
@@ -331,35 +379,26 @@ In general, the component is expected to be used by advanced users to inspect co
331
379
 
332
380
  Typical usage:
333
381
 
382
+ <!-- [[include: [TreeWidget.ImodelContentTreeExampleImports, TreeWidget.ImodelContentTreeExample], tsx]] -->
383
+ <!-- BEGIN EXTRACTION -->
384
+
334
385
  ```tsx
335
- import { IModelConnection } from "@itwin/core-frontend";
336
- import { SchemaContext } from "@itwin/ecschema-metadata";
337
- import { SelectionStorage } from "@itwin/unified-selection";
338
386
  import { IModelContentTreeComponent } from "@itwin/tree-widget-react";
339
387
 
340
- // The iModel content tree requires a unified selection storage to support selection synchronization with the
341
- // application. The storage should be created once per application and shared across multiple selection-enabled
342
- // components.
343
- function getUnifiedSelectionStorage(): SelectionStorage {
344
- // see "Creating unified selection storage" section for example implementation
345
- }
346
-
347
- // Schema context is used by iModel content tree to access iModels metadata. Similar to selection storage, it should be
348
- // created once per application and shared across multiple components.
349
- function getSchemaContext(imodel: IModelConnection): SchemaContext {
350
- // see "Creating schema context" section for example implementation
351
- }
352
-
353
388
  function MyWidget() {
354
389
  return (
355
390
  <IModelContentTreeComponent
391
+ // see "Creating schema context" section for example implementation
356
392
  getSchemaContext={getSchemaContext}
357
- selectionStorage={getUnifiedSelectionStorage()}
393
+ // see "Creating unified selection storage" section for example implementation
394
+ selectionStorage={unifiedSelectionStorage}
358
395
  />
359
396
  );
360
397
  }
361
398
  ```
362
399
 
400
+ <!-- END EXTRACTION -->
401
+
363
402
  ### Custom trees
364
403
 
365
404
  The package delivers a set of building blocks for creating trees that look and feel similar to the tree components provided by this package.
@@ -373,40 +412,69 @@ A "basic" tree is a tree that renders the hierarchy without visibility control -
373
412
 
374
413
  Example:
375
414
 
415
+ <!-- [[include: [TreeWidget.CustomTreeExampleImports, TreeWidget.CustomTreeExample], tsx]] -->
416
+ <!-- BEGIN EXTRACTION -->
417
+
376
418
  ```tsx
377
- import { ComponentPropsWithoutRef } from "react";
378
- import { IModelConnection } from "@itwin/core-frontend";
379
- import { SchemaContext } from "@itwin/ecschema-metadata";
380
- import { SelectionStorage } from "@itwin/unified-selection";
419
+ import type { ComponentPropsWithoutRef } from "react";
420
+ import type { IModelConnection } from "@itwin/core-frontend";
381
421
  import { Tree, TreeRenderer } from "@itwin/tree-widget-react";
382
-
383
-
384
- function getUnifiedSelectionStorage(): SelectionStorage {
385
- // see "Creating unified selection storage" section for example implementation
386
- }
387
-
388
- function getSchemaContext(imodel: IModelConnection): SchemaContext {
389
- // see "Creating schema context" section for example implementation
390
- }
422
+ import { createClassBasedHierarchyDefinition, createNodesQueryClauseFactory } from "@itwin/presentation-hierarchies";
423
+ import { createBisInstanceLabelSelectClauseFactory } from "@itwin/presentation-shared";
391
424
 
392
425
  type TreeProps = ComponentPropsWithoutRef<typeof Tree>;
393
426
  const getHierarchyDefinition: TreeProps["getHierarchyDefinition"] = ({ imodelAccess }) => {
394
427
  // create a hierarchy definition that defines what should be shown in the tree
395
428
  // see https://github.com/iTwin/presentation/blob/master/packages/hierarchies/README.md#hierarchy-definition
429
+ const nodesQueryFactory = createNodesQueryClauseFactory({ imodelAccess });
430
+ const labelsQueryFactory = createBisInstanceLabelSelectClauseFactory({ classHierarchyInspector: imodelAccess });
431
+ return createClassBasedHierarchyDefinition({
432
+ classHierarchyInspector: imodelAccess,
433
+ hierarchy: {
434
+ // For root nodes, select all BisCore.GeometricModel3d instances
435
+ rootNodes: async () => [
436
+ {
437
+ fullClassName: "BisCore.GeometricModel3d",
438
+ query: {
439
+ ecsql: `
440
+ SELECT
441
+ ${await nodesQueryFactory.createSelectClause({
442
+ ecClassId: { selector: "this.ECClassId" },
443
+ ecInstanceId: { selector: "this.ECInstanceId" },
444
+ nodeLabel: {
445
+ selector: await labelsQueryFactory.createSelectClause({ classAlias: "this", className: "BisCore.GeometricModel3d" }),
446
+ },
447
+ })}
448
+ FROM BisCore.GeometricModel3d this
449
+ `,
450
+ },
451
+ },
452
+ ],
453
+ childNodes: [],
454
+ },
455
+ });
456
+ };
457
+
458
+ interface MyTreeProps {
459
+ imodel: IModelConnection;
396
460
  }
397
461
 
398
462
  function MyTree({ imodel }: MyTreeProps) {
399
- return <Tree
400
- treeName="MyTree"
401
- imodel={imodel}
402
- selectionStorage={getUnifiedSelectionStorage()}
403
- getSchemaContext={getSchemaContext}
404
- getHierarchyDefinition={getHierarchyDefinition}
405
- treeRenderer={(props) => <TreeRenderer {...props} />}
406
- />;
463
+ return (
464
+ <Tree
465
+ treeName="MyTree"
466
+ imodel={imodel}
467
+ selectionStorage={unifiedSelectionStorage}
468
+ getSchemaContext={getSchemaContext}
469
+ getHierarchyDefinition={getHierarchyDefinition}
470
+ treeRenderer={(props) => <TreeRenderer {...props} />}
471
+ />
472
+ );
407
473
  }
408
474
  ```
409
475
 
476
+ <!-- END EXTRACTION -->
477
+
410
478
  #### Custom visibility tree
411
479
 
412
480
  A visibility tree is a tree that renders the hierarchy and allows controlling visibility control through the use of "eye" checkboxes - see [Models](#models-tree) and [Categories](#categories-tree) trees. Core components:
@@ -416,34 +484,56 @@ A visibility tree is a tree that renders the hierarchy and allows controlling vi
416
484
 
417
485
  Example:
418
486
 
487
+ <!-- [[include: [TreeWidget.CustomVisibilityTreeExampleImports, TreeWidget.CustomVisibilityTreeExample], tsx]] -->
488
+ <!-- BEGIN EXTRACTION -->
489
+
419
490
  ```tsx
420
- import { ComponentPropsWithoutRef } from "react";
421
491
  import { BeEvent } from "@itwin/core-bentley";
422
- import { IModelConnection } from "@itwin/core-frontend";
423
- import { SchemaContext } from "@itwin/ecschema-metadata";
424
- import { SelectionStorage } from "@itwin/unified-selection";
425
492
  import { VisibilityTree, VisibilityTreeRenderer } from "@itwin/tree-widget-react";
426
-
427
-
428
- function getUnifiedSelectionStorage(): SelectionStorage {
429
- // see "Creating unified selection storage" section for example implementation
430
- }
431
-
432
- function getSchemaContext(imodel: IModelConnection): SchemaContext {
433
- // see "Creating schema context" section for example implementation
434
- }
493
+ import { createClassBasedHierarchyDefinition, createNodesQueryClauseFactory } from "@itwin/presentation-hierarchies";
494
+ import { createBisInstanceLabelSelectClauseFactory } from "@itwin/presentation-shared";
495
+ import type { ComponentPropsWithoutRef } from "react";
496
+ import type { IModelConnection } from "@itwin/core-frontend";
435
497
 
436
498
  type VisibilityTreeProps = ComponentPropsWithoutRef<typeof VisibilityTree>;
437
499
  const getHierarchyDefinition: VisibilityTreeProps["getHierarchyDefinition"] = ({ imodelAccess }) => {
438
500
  // create a hierarchy definition that defines what should be shown in the tree
439
501
  // see https://github.com/iTwin/presentation/blob/master/packages/hierarchies/README.md#hierarchy-definition
440
- }
502
+ const nodesQueryFactory = createNodesQueryClauseFactory({ imodelAccess });
503
+ const labelsQueryFactory = createBisInstanceLabelSelectClauseFactory({ classHierarchyInspector: imodelAccess });
504
+ return createClassBasedHierarchyDefinition({
505
+ classHierarchyInspector: imodelAccess,
506
+ hierarchy: {
507
+ // For root nodes, select all BisCore.GeometricModel3d instances
508
+ rootNodes: async () => [
509
+ {
510
+ fullClassName: "BisCore.GeometricModel3d",
511
+ query: {
512
+ ecsql: `
513
+ SELECT
514
+ ${await nodesQueryFactory.createSelectClause({
515
+ ecClassId: { selector: "this.ECClassId" },
516
+ ecInstanceId: { selector: "this.ECInstanceId" },
517
+ nodeLabel: {
518
+ selector: await labelsQueryFactory.createSelectClause({ classAlias: "this", className: "BisCore.GeometricModel3d" }),
519
+ },
520
+ })}
521
+ FROM BisCore.GeometricModel3d this
522
+ `,
523
+ },
524
+ },
525
+ ],
526
+ childNodes: [],
527
+ },
528
+ });
529
+ };
441
530
 
442
- const visibilityHandlerFactory: VisibilityTreeProps["visibilityHandlerFactory"] = ({ imodelAccess }) => {
531
+ const visibilityHandlerFactory: VisibilityTreeProps["visibilityHandlerFactory"] = () => {
443
532
  return {
444
533
  // event that can be used to notify tree when visibility of instances represented by tree nodes changes from outside.
445
534
  onVisibilityChange: new BeEvent(),
446
535
  async getVisibilityStatus(node: HierarchyNode): Promise<VisibilityStatus> {
536
+ return { state: "visible" };
447
537
  // determine visibility status of the instance represented by tree node.
448
538
  },
449
539
  async changeVisibility(node: HierarchyNode, on: boolean): Promise<void> {
@@ -453,21 +543,29 @@ const visibilityHandlerFactory: VisibilityTreeProps["visibilityHandlerFactory"]
453
543
  // if necessary, do some clean up before new visibility handler is created or component is unmounted.
454
544
  },
455
545
  };
546
+ };
547
+
548
+ interface MyVisibilityTreeProps {
549
+ imodel: IModelConnection;
456
550
  }
457
551
 
458
552
  function MyVisibilityTree({ imodel }: MyVisibilityTreeProps) {
459
- return <VisibilityTree
460
- treeName="MyVisibilityTree"
461
- imodel={imodel}
462
- selectionStorage={getUnifiedSelectionStorage()}
463
- getSchemaContext={getSchemaContext}
464
- getHierarchyDefinition={getHierarchyDefinition}
465
- visibilityHandlerFactory={visibilityFactory}
466
- treeRenderer={(props) => <VisibilityTreeRenderer {...props} />}
467
- />;
553
+ return (
554
+ <VisibilityTree
555
+ treeName="MyVisibilityTree"
556
+ imodel={imodel}
557
+ selectionStorage={unifiedSelectionStorage}
558
+ getSchemaContext={getSchemaContext}
559
+ getHierarchyDefinition={getHierarchyDefinition}
560
+ visibilityHandlerFactory={visibilityHandlerFactory}
561
+ treeRenderer={(props) => <VisibilityTreeRenderer {...props} />}
562
+ />
563
+ );
468
564
  }
469
565
  ```
470
566
 
567
+ <!-- END EXTRACTION -->
568
+
471
569
  ### Hierarchy level size limiting
472
570
 
473
571
  All tree components in this package enforce a hierarchy level size limit. This means that when a node is expanded, only a certain number of child nodes are loaded. The limit is enforced to prevent loading too many nodes at once and to keep the performance of the tree components at an acceptable level.
@@ -488,9 +586,13 @@ Tree components that support selection synchronization, require a unified select
488
586
 
489
587
  Typically, we want one unified selection storage per application - this makes sure that selection in all application's components is synchronized. Below is an example implementation of `getUnifiedSelectionStorage` function that creates the storage and clears it when an iModel is closed:
490
588
 
491
- ```ts
589
+ <!-- [[include: [TreeWidget.SelectionStorageExampleImports, TreeWidget.SelectionStorageExample], tsx]] -->
590
+ <!-- BEGIN EXTRACTION -->
591
+
592
+ ```tsx
492
593
  import { IModelConnection } from "@itwin/core-frontend";
493
- import { createStorage, SelectionStorage } from "@itwin/unified-selection";
594
+ import { createStorage } from "@itwin/unified-selection";
595
+ import type { SelectionStorage } from "@itwin/unified-selection";
494
596
 
495
597
  let unifiedSelectionStorage: SelectionStorage | undefined;
496
598
  function getUnifiedSelectionStorage(): SelectionStorage {
@@ -504,28 +606,34 @@ function getUnifiedSelectionStorage(): SelectionStorage {
504
606
  }
505
607
  ```
506
608
 
507
- In case the application is also using components driven by APIs from `@itwin/presentation-frontend` package, which has its own selection manager, the single unified selection storage object should be passed to [`Presentation.initialize`](https://www.itwinjs.org/reference/presentation-frontend/core/presentation/initializestatic/) function, e.g.:
609
+ <!-- END EXTRACTION -->
610
+
611
+ In case the application is also using components driven by APIs from `@itwin/presentation-frontend` package, which has its own selection manager, the single unified selection storage object should be passed to [`initialize`](https://www.itwinjs.org/reference/presentation-frontend/core/presentation/initializestatic/) function, e.g.:
508
612
 
509
- ```ts
613
+ <!-- [[include: [TreeWidget.SelectionStorageInitializeExampleImports, TreeWidget.SelectionStorageInitializeExample], tsx]] -->
614
+ <!-- BEGIN EXTRACTION -->
615
+
616
+ ```tsx
510
617
  import { Presentation } from "@itwin/presentation-frontend";
511
618
 
512
- Presentation.initialize({
513
- selection: {
514
- selectionStorage: getUnifiedSelectionStorage(),
515
- },
516
- });
619
+ await Presentation.initialize({ selection: { selectionStorage: getUnifiedSelectionStorage() } });
517
620
  ```
518
621
 
622
+ <!-- END EXTRACTION -->
623
+
519
624
  ### Creating schema context
520
625
 
521
626
  All tree components delivered with the package require a [`SchemaContext`](https://www.itwinjs.org/reference/ecschema-metadata/context/schemacontext/) to be able to access iModels metadata.
522
627
 
523
628
  Typically, we want one schema context per iModel per application - this allows schema information to be shared across components, saving memory and time required to access the metadata. Below is an example implementation of `getSchemaContext` function, required by tree components:
524
629
 
525
- ```ts
526
- import { IModelConnection } from "@itwin/core-frontend";
630
+ <!-- [[include: [TreeWidget.GetSchemaContextExampleImports, TreeWidget.GetSchemaContextExample], tsx]] -->
631
+ <!-- BEGIN EXTRACTION -->
632
+
633
+ ```tsx
527
634
  import { SchemaContext } from "@itwin/ecschema-metadata";
528
635
  import { ECSchemaRpcLocater } from "@itwin/ecschema-rpcinterface-common";
636
+ import type { IModelConnection } from "@itwin/core-frontend";
529
637
 
530
638
  const schemaContextCache = new Map<string, SchemaContext>();
531
639
  function getSchemaContext(imodel: IModelConnection) {
@@ -542,13 +650,15 @@ function getSchemaContext(imodel: IModelConnection) {
542
650
  }
543
651
  ```
544
652
 
653
+ <!-- END EXTRACTION -->
654
+
545
655
  ## Telemetry
546
656
 
547
657
  ### Performance tracking
548
658
 
549
659
  Components from this package allows consumers to track performance of specific features.
550
660
 
551
- This can be achieved by passing `onPerformanceMeasured` function to `CategoriesTreeComponent`, `ModelsTreeComponent`, `IModelContentTreeComponent` or `TreeWidgetUiItemsProvider`. The function is invoked with feature id and time elapsed as the component is being used. List of tracked features:
661
+ This can be achieved by passing `onPerformanceMeasured` function to `CategoriesTreeComponent`, `ModelsTreeComponent`, `IModelContentTreeComponent`. The function is invoked with feature id and time elapsed as the component is being used. List of tracked features:
552
662
 
553
663
  - `"{tree}-initial-load"` - time it takes to load initial nodes after the tree is created.
554
664
  - `"{tree}-hierarchy-level-load"` - time it takes to load child nodes when a node is expanded.
@@ -560,7 +670,7 @@ Where `{tree}` specifies which tree component the feature is of.
560
670
 
561
671
  Components from this package allows consumers to track the usage of specific features.
562
672
 
563
- This can be achieved by passing `onFeatureUsed` function to `CategoriesTreeComponent`, `ModelsTreeComponent`, `IModelContentTreeComponent` or `TreeWidgetUiItemsProvider`. The function is invoked with feature id as the component is being used. List of tracked features:
673
+ This can be achieved by passing `onFeatureUsed` function to `CategoriesTreeComponent`, `ModelsTreeComponent`, `IModelContentTreeComponent`. The function is invoked with feature id as the component is being used. List of tracked features:
564
674
 
565
675
  - `"choose-{tree}"` - when a tree is selected in the tree selector.
566
676
  - `"use-{tree}"` - when an interaction with a tree hierarchy happens. This includes any kind of interaction with nodes, including them being expanded/collapsed, selected, filtered, their visibility change, etc.
@@ -585,62 +695,70 @@ Where `{tree}` specifies which tree component the feature is of.
585
695
 
586
696
  ### Example
587
697
 
588
- ```ts
589
- import { UiItemsManager } from "@itwin/appui-react";
590
- import { TreeWidgetUiItemsProvider } from "@itwin/tree-widget-react";
591
-
592
- UiItemsManager.register(
593
- new TreeWidgetUiItemsProvider({
594
- onPerformanceMeasured={(feature, elapsedTime) => {
595
- telemetryClient.log(`TreeWidget [${feature}] took ${elapsedTime} ms`);
596
- }},
597
- onFeatureUsed={(feature) => {
598
- telemetryClient.log(`TreeWidget [${feature}] used`);
599
- }},
600
- })
601
- );
602
- ```
603
-
604
698
  For individual tree components the callbacks should be supplied through props:
605
699
 
700
+ <!-- [[include: [TreeWidget.TelemetryTreeComponentExampleImports, TreeWidget.TelemetryTreeComponentExample], tsx]] -->
701
+ <!-- BEGIN EXTRACTION -->
702
+
606
703
  ```tsx
607
- import { ModelsTreeComponent } from "@itwin/tree-widget-react";
704
+ import { IModelContentTreeComponent } from "@itwin/tree-widget-react";
608
705
 
609
706
  function MyWidget() {
610
707
  return (
611
- <ModelsTreeComponent
612
- {...otherProps}
708
+ <IModelContentTreeComponent
613
709
  onPerformanceMeasured={(feature, elapsedTime) => {
614
- console.log(`TreeWidget [${feature}] took ${elapsedTime} ms`)
710
+ console.log(`TreeWidget [${feature}] took ${elapsedTime} ms`);
615
711
  }}
616
712
  onFeatureUsed={(feature) => {
617
- console.log(`TreeWidget [${feature}] used`)
713
+ console.log(`TreeWidget [${feature}] used`);
618
714
  }}
715
+ getSchemaContext={getSchemaContext}
716
+ selectionStorage={unifiedSelectionStorage}
619
717
  />
620
718
  );
621
719
  }
622
720
  ```
623
721
 
722
+ <!-- END EXTRACTION -->
723
+
624
724
  For custom tree components `TelemetryContextProvider` should be used:
625
725
 
726
+ <!-- [[include: [TreeWidget.TelemetryCustomTreeExampleImports, TreeWidget.TelemetryCustomTreeExample], tsx]] -->
727
+ <!-- BEGIN EXTRACTION -->
728
+
626
729
  ```tsx
627
- import { TelemetryContextProvider } from "@itwin/tree-widget-react";
730
+ import { TelemetryContextProvider, useCategoriesTree, VisibilityTree, VisibilityTreeRenderer } from "@itwin/tree-widget-react";
628
731
 
629
732
  function MyWidget() {
630
- return <TelemetryContextProvider
631
- componentIdentifier="MyTree"
632
- onPerformanceMeasured={(feature, elapsedTime) => {
633
- console.log(`TreeWidget [${feature}] took ${elapsedTime} ms`)
634
- }}
635
- onFeatureUsed={(feature) => {
636
- console.log(`TreeWidget [${feature}] used`)
637
- }}
638
- >
639
- <MyTree />
640
- </TelemetryContextProvider>;
733
+ return (
734
+ <TelemetryContextProvider
735
+ componentIdentifier="MyTree"
736
+ onPerformanceMeasured={(feature, elapsedTime) => {
737
+ console.log(`TreeWidget [${feature}] took ${elapsedTime} ms`);
738
+ }}
739
+ onFeatureUsed={(feature) => {
740
+ console.log(`TreeWidget [${feature}] used`);
741
+ }}
742
+ >
743
+ <MyTree />
744
+ </TelemetryContextProvider>
745
+ );
641
746
  }
642
747
 
643
748
  function MyTree() {
644
- // see "Custom trees" section for example implementation
749
+ const { categoriesTreeProps, rendererProps } = useCategoriesTree({ activeView: viewport, filter: "" });
750
+ return (
751
+ // VisibilityTree will use provided telemetry context to report used features and their performance
752
+ <VisibilityTree
753
+ {...categoriesTreeProps}
754
+ getSchemaContext={getSchemaContext}
755
+ selectionStorage={unifiedSelectionStorage}
756
+ imodel={imodel}
757
+ treeRenderer={(props) => <VisibilityTreeRenderer {...props} {...rendererProps} />}
758
+ />
759
+ );
760
+ // see "Custom trees" section for more example implementations
645
761
  }
646
762
  ```
763
+
764
+ <!-- END EXTRACTION -->