@itwin/unified-selection 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +26 -134
  3. package/lib/cjs/unified-selection/CachingHiliteSetProvider.d.ts +3 -1
  4. package/lib/cjs/unified-selection/CachingHiliteSetProvider.d.ts.map +1 -1
  5. package/lib/cjs/unified-selection/CachingHiliteSetProvider.js +3 -1
  6. package/lib/cjs/unified-selection/CachingHiliteSetProvider.js.map +1 -1
  7. package/lib/cjs/unified-selection/EnableUnifiedSelectionSyncWithIModel.d.ts +18 -10
  8. package/lib/cjs/unified-selection/EnableUnifiedSelectionSyncWithIModel.d.ts.map +1 -1
  9. package/lib/cjs/unified-selection/EnableUnifiedSelectionSyncWithIModel.js +40 -16
  10. package/lib/cjs/unified-selection/EnableUnifiedSelectionSyncWithIModel.js.map +1 -1
  11. package/lib/cjs/unified-selection/SelectionScope.d.ts +11 -4
  12. package/lib/cjs/unified-selection/SelectionScope.d.ts.map +1 -1
  13. package/lib/cjs/unified-selection/SelectionScope.js.map +1 -1
  14. package/lib/cjs/unified-selection.d.ts +1 -1
  15. package/lib/cjs/unified-selection.d.ts.map +1 -1
  16. package/lib/cjs/unified-selection.js.map +1 -1
  17. package/lib/esm/unified-selection/CachingHiliteSetProvider.d.ts +3 -1
  18. package/lib/esm/unified-selection/CachingHiliteSetProvider.d.ts.map +1 -1
  19. package/lib/esm/unified-selection/CachingHiliteSetProvider.js +3 -1
  20. package/lib/esm/unified-selection/CachingHiliteSetProvider.js.map +1 -1
  21. package/lib/esm/unified-selection/EnableUnifiedSelectionSyncWithIModel.d.ts +18 -10
  22. package/lib/esm/unified-selection/EnableUnifiedSelectionSyncWithIModel.d.ts.map +1 -1
  23. package/lib/esm/unified-selection/EnableUnifiedSelectionSyncWithIModel.js +40 -16
  24. package/lib/esm/unified-selection/EnableUnifiedSelectionSyncWithIModel.js.map +1 -1
  25. package/lib/esm/unified-selection/SelectionScope.d.ts +11 -4
  26. package/lib/esm/unified-selection/SelectionScope.d.ts.map +1 -1
  27. package/lib/esm/unified-selection/SelectionScope.js.map +1 -1
  28. package/lib/esm/unified-selection.d.ts +1 -1
  29. package/lib/esm/unified-selection.d.ts.map +1 -1
  30. package/lib/esm/unified-selection.js.map +1 -1
  31. package/package.json +9 -9
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # @itwin/unified-selection
2
2
 
3
+ ## 1.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#901](https://github.com/iTwin/presentation/pull/901): Export `SelectionScope` type to make it easier for consumers to define "active scope" type.
8
+
9
+ APIs that use this type:
10
+
11
+ - The `scope` prop of `computeSelection` function.
12
+ - Return type of `activeScopeProvider` callback prop of `enableUnifiedSelectionSyncWithIModel` function.
13
+
14
+ - [#895](https://github.com/iTwin/presentation/pull/895): `createCachingHiliteSetProvider`: Added a `createHiliteSetProvider` prop to allow using custom hilite sets for given iModel selections.
15
+
16
+ ### Patch Changes
17
+
18
+ - [#884](https://github.com/iTwin/presentation/pull/884): Fix `enableUnifiedSelectionSyncWithIModel` not properly syncing `SelectionSet` and `SelectionStorage` with 4.x `itwinjs-core`.
19
+
20
+ When the selection change was made by a tool in graphics view (through the `SelectionSet`), the `SelectionStorage` was updated correctly, but the `IModelConnection.hiliteSet` - wasn't. As a result, clearing selection through graphics view wouldn't clear the hilite set and keep the elements hilited.
21
+
3
22
  ## 1.3.0
4
23
 
5
24
  ### Minor Changes
package/README.md CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  Copyright © Bentley Systems, Incorporated. All rights reserved. See LICENSE.md for license terms and full copyright notice.
4
4
 
5
- The `@itwin/unified-selection` package provides API for managing [unified selection](https://www.itwinjs.org/presentation/unified-selection/).
5
+ The purpose of the `@itwin/unified-selection` package and unified selection in general is to act as a single source of truth of what is selected in an [iTwin.js](https://www.itwinjs.org/) application.
6
6
 
7
- ## Basic concepts
7
+ ## Concepts
8
8
 
9
9
  The API consists of a few very basic concepts:
10
10
 
@@ -23,21 +23,22 @@ The API consists of a few very basic concepts:
23
23
 
24
24
  The package delivers the `createStorage()` function to create an instance of `SelectionStorage`. Consumers are also expected to call `SelectionStorage.clearStorage` whenever an iModel is closed to free up memory.
25
25
 
26
- ## Basic usage
26
+ ## Usage example
27
27
 
28
28
  ```ts
29
- // create a global selection store (generally, somewhere in main.ts or similar)
30
- import { createStore } from "@itwin/unified-selection";
31
- const unifiedSelection = createStore();
29
+ // Create a global selection store (generally, somewhere in main.ts or similar). This store
30
+ // must be shared across all the application's components to ensure unified selection experience.
31
+ import { createStorage } from "@itwin/unified-selection";
32
+ const unifiedSelection = createStorage();
32
33
 
33
- // the store should to be cleaned up when iModels are closed to free up memory, e.g.:
34
+ // The store should to be cleaned up when iModels are closed to free up memory, e.g.:
34
35
  import { IModelConnection } from "@itwin/core-frontend";
35
36
  import { createIModelKey } from "@itwin/presentation-core-interop";
36
37
  IModelConnection.onClose.addListener((imodel) => {
37
- unifiedSelection.clearStorage(createIModelKey(imodel));
38
+ unifiedSelection.clearStorage({ imodelKey: createIModelKey(imodel) });
38
39
  });
39
40
 
40
- // add a demo selection listener
41
+ // A demo selection listener logs selection changes to the console:
41
42
  import { Selectables } from "@itwin/unified-selection";
42
43
  unifiedSelection.selectionChangeEvent.addListener(({ imodelKey, source, changeType, selectables }) => {
43
44
  const suffix = `in ${imodelKey} iModel from ${source} component`;
@@ -58,137 +59,28 @@ unifiedSelection.selectionChangeEvent.addListener(({ imodelKey, source, changeTy
58
59
  }
59
60
  });
60
61
 
61
- // in some component
62
+ // An interactive component that allows selecting elements, representing something in an iModel, may want to
63
+ // add that something to unified selection:
62
64
  MyComponent.onECInstanceSelected((imodel: IModelConnection, key: { className: string; id: Id64String }) => {
63
65
  unifiedSelection.addToSelection({ imodelKey: createIModelKey(imodel), source: "MyComponent", selectables: [key] });
64
66
  });
65
67
  ```
66
68
 
67
- ## Details
69
+ ## Learning
68
70
 
69
- ### Selection levels
71
+ Are you migrating from `SelectionManager` in `@itwin/presentation-frontend`? Check out our [Migrating from `SelectionManager`](./learning/MigrationGuide.md) learning page!
70
72
 
71
- By default, whenever a component changes unified selection, that happens at 0th (top) selection level. And similarly, whenever a component requests current selection from the storage, by default the top selection level is used. However, there are cases when we want to have multiple levels of selection.
73
+ Below is a list of learning material related integrating unified selection into your components:
72
74
 
73
- For example, let's say there're 3 components: _A_, _B_ and _C_:
75
+ - General topics:
76
+ - [Selection levels](./learning/SelectionLevels.md)
77
+ - [Selection scopes](./learning/SelectionScopes.md)
78
+ - [Hilite sets](./learning/HiliteSets.md)
79
+ - [Caveats](./learning/Caveats.md)
80
+ - Integrating with iTwin.js components:
81
+ - [Viewport / iModel](./learning/SyncWithIModelConnection.md)
82
+ - [Tree](./learning/SyncWithTree.md)
83
+ - [Property grid](./learning/SyncWithPropertyGrid.md)
84
+ - [Table](./learning/SyncWithTable.md)
74
85
 
75
- - _Component A_ shows a list of elements and allows selecting them.
76
- - _Component B_ shows a list of elements selected in _Component A_ and allows selecting them individually. Selecting an individual element should not change selection in _Component A_ or content in _Component B_ itself.
77
- - _Component C_ shows properties of elements selected either in _Component A_ or _Component B_.
78
-
79
- The behavior described above can't be achieved using just one level of selection, because as soon as selection is made in _Component B_, that selection would get represented in _Component A_, and _Component B_ would change what it's displaying to the individual element.
80
-
81
- That can be fixed by introducing another selection level, but before the components can be configured, here are a few key facts about selection levels:
82
-
83
- - Higher level selection has lower index. So top level selection is 0, lower level is 1, and so on.
84
- - Changing higher level selection clears all lower level selections.
85
- - Lower level selection doesn't have to be a sub-set of higher level selection.
86
-
87
- With that in mind, the above components _A_, _B_ and _C_ can be configured as follows:
88
-
89
- - _Component A_ only cares about top level selection. Whenever something is selected in the component, unified selection is updated at the top level. Similarly, whenever unified selection changes, the component only reacts if that happened at the top level.
90
- - _Component B_ reloads its content if the selection changes at the top level. Row selection is handled using lower level, so selecting a row doesn't affect _Component A's_ selection or _Component B's_ content.
91
- - _Component C_ reloads its content no matter the selection level.
92
-
93
- ### Hilite sets
94
-
95
- > **Note:** hilite = highlight
96
-
97
- `@itwin/core-frontend` contains a concept called the [HiliteSet](https://www.itwinjs.org/reference/core-frontend/selectionset/hiliteset/). This concept is tightly related to unified selection, because, generally, we want selected elements to be highlighted in the application's graphics views. The `HiliteSet` object contains IDs of 3 types of elements: [GeometricModel](https://www.itwinjs.org/reference/core-backend/models/geometricmodel/), [SubCategory](https://www.itwinjs.org/reference/core-backend/imodels/subcategory/) and [GeometricElement](https://www.itwinjs.org/reference/core-backend/elements/geometricelement/). On the other hand, the unified selection API allows selecting other kinds of elements too, so IDs of these elements need to be mapped to the supported ones. The rules are as follows:
98
-
99
- - for `BisCore.Subject` return IDs of all geometric models that are recursively under that Subject,
100
- - for `BisCore.Model` just return its ID,
101
- - for `BisCore.PhysicalPartition` just return ID of a model that models it,
102
- - for `BisCore.Category` return IDs of all its _SubCategories_,
103
- - for `BisCore.SubCategory` just return its ID,
104
- - for `BisCore.GeometricElement` return ID of its own and all its child elements recursively.
105
-
106
- So for example when unified selection contains a Subject, the hilite set for it will contain all models under that Subject, it's child Subjects, their child Subjects, etc. Given such hilite set, the viewport component hilites all elements in those models.
107
-
108
- The `@itwin/unified-selection` package delivers APIs for creating a `HiliteSet` or retrieving it for _current_ selection in a `SelectionStorage`:
109
-
110
- ```ts
111
- // Components may want to get a hilite set for arbitrary set of Selectables - use `createHiliteSetProvider` for that.
112
- import { IModelConnection } from "@itwin/core-frontend";
113
- import { createECSqlQueryExecutor, createECSchemaProvider } from "@itwin/presentation-core-interop";
114
- import { createHiliteSetProvider } from "@itwin/unified-selection";
115
-
116
- const imodel: IModelConnection; // initialized elsewhere
117
- const hiliteProvider = createHiliteSetProvider({
118
- imodelAccess: {
119
- ...createECSchemaProvider(imodel),
120
- ...createECSqlQueryExecutor(imodel),
121
- },
122
- });
123
- const hiliteSet = await hiliteProvider.getHiliteSet({ selectables });
124
-
125
- // Some others may want to get a hilite set for _current_ selection for specific iModel in storage - use `createCachingHiliteSetProvider`
126
- // for that. It's recommended to keep a single instance of this provider per application as it caches hilite sets per each iModel's selection.
127
- import { createCachingHiliteSetProvider } from "@itwin/unified-selection";
128
- import { createIModelKey } from "@itwin/presentation-core-interop";
129
-
130
- // Note the use of `using` keyword here. The caching provider registers a selection change listener and should be disposed, in case
131
- // its lifetime is shorter than that of `SelectionStorage`, to unregister the listener. The `using` keyword ensures that the provider
132
- // is disposed when it goes out of scope.
133
- using selectionHiliteProvider = createCachingHiliteSetProvider({
134
- selectionStorage,
135
- // this is called to get iModel access based on the iModel key, used to get hilite set for that iModel (see below)
136
- imodelProvider: (imodelKey) => getIModelByKey(imodelKey),
137
- });
138
- const selectionHiliteSet = await selectionHiliteProvider.getHiliteSet({ imodelKey: createIModelKey(imodel) });
139
- ```
140
-
141
- ### Selection scopes
142
-
143
- Selection scopes allow decoupling of what gets picked and what gets selected. Without selection scopes, whenever a user picks an element in the viewport, its ID goes straight into unified selection storage. With selection scopes we can modify that and add something different. The input to the selection scopes' processor is a query executor, element IDs, and the scope to apply, and the output is an iterator of `SelectableInstanceKey`. We get the input when the user picks some elements in the viewport, run that through the selection scope processor and put the output into unified selection storage.
144
-
145
- Here are the scopes we support at the moment:
146
-
147
- - `element` - return key of selected element.
148
- - `category` - return key of geometric element's category.
149
- - `model` - return key of element's model.
150
- - `functional` - return key of element's related functional element. For `BisCore.GeometricElement3d` the related functional element is found using the `Functional.PhysicalElementFulfillsFunction` relationship. For `BisCore.GeometricElement2d` the nearest functional element is searched for using the `Functional.DrawingGraphicRepresentsFunctionalElement` relationship - if the given element has a related functional element, it will be returned, otherwise the element's parent will be checked and if it also does not have a related functional, then the parent of the parent will be checked until no more ancestors can be traversed or a functional element is found. Regardless whether it is an `BisCore.GeometricElement2d` or `BisCore.GeometricElement3d` if no functional element is found then the element itself will be returned.
151
-
152
- The `@itwin/unified-selection` package delivers a `computeSelection` function for computing which elements should be added into unified selection storage based on the given element ID's and a specified selection scope:
153
-
154
- ```ts
155
- import { computeSelection } from "@itwin/unified-selection";
156
- import { IModelConnection } from "@itwin/core-frontend";
157
- import { createECSqlQueryExecutor } from "@itwin/presentation-core-interop";
158
- const queryExecutor = createECSqlQueryExecutor(imodel);
159
- const selection = computeSelection({ queryExecutor, elementIds, scope: "element" });
160
- ```
161
-
162
- `element` and `functional` scopes additionally allow selecting assembly elements by specifying the `ancestorLevel` property in the selection scope argument of `computeSelection` function. The `ancestorLevel` property specifies how far "up" we should walk to find the target element. When not specified or `0`, the target element matches the request element. When set to `1`, the target element matches the direct parent element. When `2`, the target element is the parent of the parent element, and so on. In all situations when this is `> 0`, we're not walking further than the last existing element, for example, when `ancestorLevel = 1` (direct parent element is requested), but the request element doesn't have a parent, the request element is returned as the result. A negative value would result in the top-most element to be returned.
163
-
164
- For the `functional` scope, the `ancestorLevel` property is used as follows: if an element is a `BisCore.GeometricElement3d` element, its ancestor is selected based on the given `ancestorLevel` the same as with non-functional elements, and then the resulting element's related functional element will be returned (using the `Functional.PhysicalElementFulfillsFunction` relationship), or if it does not have one, then the resulting element will be returned. For `BisCore.GeometricElement2d` elements, the nearest related functional element is found in the same way it is done when the `ancestorLevel` property is not provided, and then the ancestor of that element is returned (based on the provided value of `ancestorLevel`).
165
-
166
- ```ts
167
- import { computeSelection } from "@itwin/unified-selection";
168
- import { IModelConnection } from "@itwin/core-frontend";
169
- import { createECSqlQueryExecutor } from "@itwin/presentation-core-interop";
170
- const queryExecutor = createECSqlQueryExecutor(imodel);
171
- // Returns the parent element, or the element itself if it does not have a parent, for each element specified in `elementIds` argument.
172
- const selection = computeSelection({ queryExecutor, elementIds, scope: { id: "element", ancestorLevel: 1 } });
173
- ```
174
-
175
- ## iModel selection synchronization with unified selection
176
-
177
- The `@itwin/unified-selection` package delivers a `enableUnifiedSelectionSyncWithIModel` function to enable selection synchronization between an iModel and a `SelectionStorage`. When called, it returns a cleanup function that should be used to disable the synchronization. There should only be one active synchronization between a single iModel and a `SelectionStorage` at a given time. For example, this function could be used inside a `useEffect` hook in a component that holds an iModel:
178
-
179
- ```ts
180
- import { createECSqlQueryExecutor, createECSchemaProvider, createIModelKey } from "@itwin/presentation-core-interop";
181
- useEffect(() => {
182
- return enableUnifiedSelectionSyncWithIModel({
183
- imodelAccess: {
184
- ...createECSqlQueryExecutor(imodel),
185
- ...createECSchemaProvider(imodel),
186
- key: createIModelKey(imodel),
187
- hiliteSet: imodel.hilited,
188
- selectionSet: imodel.selectionSet,
189
- },
190
- selectionStorage,
191
- activeScopeProvider: () => "element",
192
- });
193
- }, [imodel]);
194
- ```
86
+ Do you think something is missing in the above list? Let us know by [creating an issue](https://github.com/iTwin/presentation/issues/new?assignees=&labels=documentation%2C+presentation&projects=&template=learning-material-request.md&title=)!
@@ -1,6 +1,6 @@
1
1
  import "./DisposePolyfill.js";
2
2
  import { ECClassHierarchyInspector, ECSqlQueryExecutor } from "@itwin/presentation-shared";
3
- import { HiliteSet } from "./HiliteSetProvider.js";
3
+ import { createHiliteSetProvider, HiliteSet } from "./HiliteSetProvider.js";
4
4
  import { SelectionStorage } from "./SelectionStorage.js";
5
5
  /**
6
6
  * Props for creating a `CachingHiliteSetProvider` instance.
@@ -11,6 +11,8 @@ export interface CachingHiliteSetProviderProps {
11
11
  selectionStorage: SelectionStorage;
12
12
  /** A callback that should return iModel access by iModel key. */
13
13
  imodelProvider: (imodelKey: string) => ECClassHierarchyInspector & ECSqlQueryExecutor;
14
+ /** An optional hilite set provider factory. If not provided, defaults to `createHiliteSetProvider` from this package. */
15
+ createHiliteSetProvider?: typeof createHiliteSetProvider;
14
16
  }
15
17
  /**
16
18
  * Defines return value of `createCachingHiliteSetProvider`.
@@ -1 +1 @@
1
- {"version":3,"file":"CachingHiliteSetProvider.d.ts","sourceRoot":"","sources":["../../../src/unified-selection/CachingHiliteSetProvider.ts"],"names":[],"mappings":"AAKA,OAAO,sBAAsB,CAAC;AAG9B,OAAO,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAC3F,OAAO,EAA2B,SAAS,EAAqB,MAAM,wBAAwB,CAAC;AAE/F,OAAO,EAAuC,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE9F;;;GAGG;AACH,MAAM,WAAW,6BAA6B;IAC5C,8DAA8D;IAC9D,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,iEAAiE;IACjE,cAAc,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,yBAAyB,GAAG,kBAAkB,CAAC;CACvF;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,wBAAwB;IACvC,mEAAmE;IACnE,YAAY,CAAC,KAAK,EAAE;QAClB,mCAAmC;QACnC,SAAS,EAAE,MAAM,CAAC;KACnB,GAAG,qBAAqB,CAAC,SAAS,CAAC,CAAC;IAErC;;;;;OAKG;IACH,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,MAAM,IAAI,CAAC;IAE9B;;;OAGG;IACH,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,6BAA6B,GAAG,wBAAwB,GAAG;IAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CAAE,CAEhJ"}
1
+ {"version":3,"file":"CachingHiliteSetProvider.d.ts","sourceRoot":"","sources":["../../../src/unified-selection/CachingHiliteSetProvider.ts"],"names":[],"mappings":"AAKA,OAAO,sBAAsB,CAAC;AAG9B,OAAO,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAC3F,OAAO,EAAE,uBAAuB,EAAE,SAAS,EAAqB,MAAM,wBAAwB,CAAC;AAE/F,OAAO,EAAuC,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE9F;;;GAGG;AACH,MAAM,WAAW,6BAA6B;IAC5C,8DAA8D;IAC9D,gBAAgB,EAAE,gBAAgB,CAAC;IAEnC,iEAAiE;IACjE,cAAc,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,yBAAyB,GAAG,kBAAkB,CAAC;IAEtF,yHAAyH;IACzH,uBAAuB,CAAC,EAAE,OAAO,uBAAuB,CAAC;CAC1D;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,wBAAwB;IACvC,mEAAmE;IACnE,YAAY,CAAC,KAAK,EAAE;QAClB,mCAAmC;QACnC,SAAS,EAAE,MAAM,CAAC;KACnB,GAAG,qBAAqB,CAAC,SAAS,CAAC,CAAC;IAErC;;;;;OAKG;IACH,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,MAAM,IAAI,CAAC;IAE9B;;;OAGG;IACH,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,6BAA6B,GAAG,wBAAwB,GAAG;IAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CAAE,CAEhJ"}
@@ -24,6 +24,7 @@ class CachingHiliteSetProviderImpl {
24
24
  _cache = new Map();
25
25
  _removeListener;
26
26
  _imodelProvider;
27
+ _createHiliteSetProvider;
27
28
  constructor(props) {
28
29
  this._selectionStorage = props.selectionStorage;
29
30
  this._imodelProvider = props.imodelProvider;
@@ -33,6 +34,7 @@ class CachingHiliteSetProviderImpl {
33
34
  this._hiliteSetProviders.delete(args.imodelKey);
34
35
  }
35
36
  });
37
+ this._createHiliteSetProvider = props.createHiliteSetProvider ?? /* c8 ignore next */ HiliteSetProvider_js_1.createHiliteSetProvider;
36
38
  }
37
39
  getHiliteSet({ imodelKey }) {
38
40
  const imodelAccess = this._imodelProvider(imodelKey);
@@ -57,7 +59,7 @@ class CachingHiliteSetProviderImpl {
57
59
  getHiliteSetProvider(imodelKey, imodelAccess) {
58
60
  let provider = this._hiliteSetProviders.get(imodelKey);
59
61
  if (!provider) {
60
- provider = (0, HiliteSetProvider_js_1.createHiliteSetProvider)({ imodelAccess });
62
+ provider = this._createHiliteSetProvider({ imodelAccess });
61
63
  this._hiliteSetProviders.set(imodelKey, provider);
62
64
  }
63
65
  return provider;
@@ -1 +1 @@
1
- {"version":3,"file":"CachingHiliteSetProvider.js","sourceRoot":"","sources":["../../../src/unified-selection/CachingHiliteSetProvider.ts"],"names":[],"mappings":";AAAA;;;gGAGgG;;AAyDhG,wEAEC;AAzDD,gCAA8B;AAC9B,+BAAqD;AACrD,mDAA+C;AAE/C,iEAA+F;AAE/F,+DAA8F;AA4C9F;;;;GAIG;AACH,SAAgB,8BAA8B,CAAC,KAAoC;IACjF,OAAO,IAAI,4BAA4B,CAAC,KAAK,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,4BAA4B;IACxB,iBAAiB,CAAmB;IACpC,mBAAmB,GAAG,IAAI,GAAG,EAA6B,CAAC;IAC3D,MAAM,GAAG,IAAI,GAAG,EAAiC,CAAC;IAClD,eAAe,CAAa;IAC5B,eAAe,CAAwE;IAE/F,YAAY,KAAoC;QAC9C,IAAI,CAAC,iBAAiB,GAAG,KAAK,CAAC,gBAAgB,CAAC;QAChD,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC,cAAc,CAAC;QAC5C,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,iBAAiB,CAAC,oBAAoB,CAAC,WAAW,CAAC,CAAC,IAAqC,EAAE,EAAE;YACvH,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACnC,IAAI,IAAI,CAAC,UAAU,KAAK,OAAO,IAAI,IAAI,CAAC,MAAM,KAAK,yDAAmC,EAAE,CAAC;gBACvF,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAClD,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAEM,YAAY,CAAC,EAAE,SAAS,EAAyB;QACtD,MAAM,YAAY,GAAG,IAAI,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;QACrD,MAAM,QAAQ,GAAG,IAAI,CAAC,oBAAoB,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;QACpE,IAAI,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAE3C,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,WAAW,GAAG,IAAI,CAAC,iBAAiB,CAAC,YAAY,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC;YACvE,SAAS,GAAG,IAAA,WAAI,EAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAA,kBAAW,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;YAC/F,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QACxC,CAAC;QAED,OAAO,IAAA,8BAAa,EAAC,SAAS,CAAC,CAAC;IAClC,CAAC;IAEM,CAAC,MAAM,CAAC,OAAO,CAAC;QACrB,IAAI,CAAC,eAAe,EAAE,CAAC;QACvB,IAAI,CAAC,mBAAmB,GAAG,IAAI,GAAG,EAAE,CAAC;QACrC,IAAI,CAAC,MAAM,GAAG,IAAI,GAAG,EAAE,CAAC;IAC1B,CAAC;IAED,sBAAsB;IACf,OAAO;QACZ,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;IACzB,CAAC;IAEO,oBAAoB,CAAC,SAAiB,EAAE,YAA4D;QAC1G,IAAI,QAAQ,GAAG,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACvD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,QAAQ,GAAG,IAAA,8CAAuB,EAAC,EAAE,YAAY,EAAE,CAAC,CAAC;YACrD,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QACpD,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF","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 \"./DisposePolyfill.js\";\nimport { from, Observable, shareReplay } from \"rxjs\";\nimport { eachValueFrom } from \"rxjs-for-await\";\nimport { ECClassHierarchyInspector, ECSqlQueryExecutor } from \"@itwin/presentation-shared\";\nimport { createHiliteSetProvider, HiliteSet, HiliteSetProvider } from \"./HiliteSetProvider.js\";\nimport { StorageSelectionChangeEventArgs } from \"./SelectionChangeEvent.js\";\nimport { IMODEL_CLOSE_SELECTION_CLEAR_SOURCE, SelectionStorage } from \"./SelectionStorage.js\";\n\n/**\n * Props for creating a `CachingHiliteSetProvider` instance.\n * @public\n */\nexport interface CachingHiliteSetProviderProps {\n /** Selection storage to use for retrieving the hilite set. */\n selectionStorage: SelectionStorage;\n /** A callback that should return iModel access by iModel key. */\n imodelProvider: (imodelKey: string) => ECClassHierarchyInspector & ECSqlQueryExecutor;\n}\n\n/**\n * Defines return value of `createCachingHiliteSetProvider`.\n *\n * **Warning:** Used in public API as a return value. Not expected to be created / extended by package\n * consumers, may be supplemented with required attributes any time.\n *\n * @see `createCachingHiliteSetProvider`\n * @public\n */\nexport interface CachingHiliteSetProvider {\n /** Get the current hilite set iterator for the specified imodel */\n getHiliteSet(props: {\n /** iModel to get hilite set for */\n imodelKey: string;\n }): AsyncIterableIterator<HiliteSet>;\n\n /**\n * Disposes the cache.\n *\n * Optional to avoid breaking the API. Will be made required when the deprecated\n * `dispose` is removed.\n */\n [Symbol.dispose]?: () => void;\n\n /**\n * Disposes the cache.\n * @deprecated in 1.2. Use `[Symbol.dispose]` instead.\n */\n dispose(): void;\n}\n\n/**\n * Creates a hilite set provider that caches hilite set for current selection for given iModel so any subsequent\n * hilite set requests for the same iModel don't cost until selection in given selection storage changes.\n * @public\n */\nexport function createCachingHiliteSetProvider(props: CachingHiliteSetProviderProps): CachingHiliteSetProvider & { [Symbol.dispose]: () => void } {\n return new CachingHiliteSetProviderImpl(props);\n}\n\nclass CachingHiliteSetProviderImpl implements CachingHiliteSetProvider {\n private _selectionStorage: SelectionStorage;\n private _hiliteSetProviders = new Map<string, HiliteSetProvider>();\n private _cache = new Map<string, Observable<HiliteSet>>();\n private _removeListener: () => void;\n private _imodelProvider: (imodelKey: string) => ECClassHierarchyInspector & ECSqlQueryExecutor;\n\n constructor(props: CachingHiliteSetProviderProps) {\n this._selectionStorage = props.selectionStorage;\n this._imodelProvider = props.imodelProvider;\n this._removeListener = this._selectionStorage.selectionChangeEvent.addListener((args: StorageSelectionChangeEventArgs) => {\n this._cache.delete(args.imodelKey);\n if (args.changeType === \"clear\" && args.source === IMODEL_CLOSE_SELECTION_CLEAR_SOURCE) {\n this._hiliteSetProviders.delete(args.imodelKey);\n }\n });\n }\n\n public getHiliteSet({ imodelKey }: { imodelKey: string }): AsyncIterableIterator<HiliteSet> {\n const imodelAccess = this._imodelProvider(imodelKey);\n const provider = this.getHiliteSetProvider(imodelKey, imodelAccess);\n let hiliteSet = this._cache.get(imodelKey);\n\n if (!hiliteSet) {\n const selectables = this._selectionStorage.getSelection({ imodelKey });\n hiliteSet = from(provider.getHiliteSet({ selectables })).pipe(shareReplay({ refCount: true }));\n this._cache.set(imodelKey, hiliteSet);\n }\n\n return eachValueFrom(hiliteSet);\n }\n\n public [Symbol.dispose](): void {\n this._removeListener();\n this._hiliteSetProviders = new Map();\n this._cache = new Map();\n }\n\n /* c8 ignore next 3 */\n public dispose(): void {\n this[Symbol.dispose]();\n }\n\n private getHiliteSetProvider(imodelKey: string, imodelAccess: ECClassHierarchyInspector & ECSqlQueryExecutor) {\n let provider = this._hiliteSetProviders.get(imodelKey);\n if (!provider) {\n provider = createHiliteSetProvider({ imodelAccess });\n this._hiliteSetProviders.set(imodelKey, provider);\n }\n return provider;\n }\n}\n"]}
1
+ {"version":3,"file":"CachingHiliteSetProvider.js","sourceRoot":"","sources":["../../../src/unified-selection/CachingHiliteSetProvider.ts"],"names":[],"mappings":";AAAA;;;gGAGgG;;AA6DhG,wEAEC;AA7DD,gCAA8B;AAC9B,+BAAqD;AACrD,mDAA+C;AAE/C,iEAA+F;AAE/F,+DAA8F;AAgD9F;;;;GAIG;AACH,SAAgB,8BAA8B,CAAC,KAAoC;IACjF,OAAO,IAAI,4BAA4B,CAAC,KAAK,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,4BAA4B;IACxB,iBAAiB,CAAmB;IACpC,mBAAmB,GAAG,IAAI,GAAG,EAA6B,CAAC;IAC3D,MAAM,GAAG,IAAI,GAAG,EAAiC,CAAC;IAClD,eAAe,CAAa;IAC5B,eAAe,CAAwE;IACvF,wBAAwB,CAAiC;IAEjE,YAAY,KAAoC;QAC9C,IAAI,CAAC,iBAAiB,GAAG,KAAK,CAAC,gBAAgB,CAAC;QAChD,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC,cAAc,CAAC;QAC5C,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,iBAAiB,CAAC,oBAAoB,CAAC,WAAW,CAAC,CAAC,IAAqC,EAAE,EAAE;YACvH,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACnC,IAAI,IAAI,CAAC,UAAU,KAAK,OAAO,IAAI,IAAI,CAAC,MAAM,KAAK,yDAAmC,EAAE,CAAC;gBACvF,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAClD,CAAC;QACH,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,wBAAwB,GAAG,KAAK,CAAC,uBAAuB,IAAI,oBAAoB,CAAC,8CAAuB,CAAC;IAChH,CAAC;IAEM,YAAY,CAAC,EAAE,SAAS,EAAyB;QACtD,MAAM,YAAY,GAAG,IAAI,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;QACrD,MAAM,QAAQ,GAAG,IAAI,CAAC,oBAAoB,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;QACpE,IAAI,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAE3C,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,WAAW,GAAG,IAAI,CAAC,iBAAiB,CAAC,YAAY,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC;YACvE,SAAS,GAAG,IAAA,WAAI,EAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAA,kBAAW,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;YAC/F,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QACxC,CAAC;QAED,OAAO,IAAA,8BAAa,EAAC,SAAS,CAAC,CAAC;IAClC,CAAC;IAEM,CAAC,MAAM,CAAC,OAAO,CAAC;QACrB,IAAI,CAAC,eAAe,EAAE,CAAC;QACvB,IAAI,CAAC,mBAAmB,GAAG,IAAI,GAAG,EAAE,CAAC;QACrC,IAAI,CAAC,MAAM,GAAG,IAAI,GAAG,EAAE,CAAC;IAC1B,CAAC;IAED,sBAAsB;IACf,OAAO;QACZ,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;IACzB,CAAC;IAEO,oBAAoB,CAAC,SAAiB,EAAE,YAA4D;QAC1G,IAAI,QAAQ,GAAG,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACvD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,QAAQ,GAAG,IAAI,CAAC,wBAAwB,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC;YAC3D,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QACpD,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF","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 \"./DisposePolyfill.js\";\nimport { from, Observable, shareReplay } from \"rxjs\";\nimport { eachValueFrom } from \"rxjs-for-await\";\nimport { ECClassHierarchyInspector, ECSqlQueryExecutor } from \"@itwin/presentation-shared\";\nimport { createHiliteSetProvider, HiliteSet, HiliteSetProvider } from \"./HiliteSetProvider.js\";\nimport { StorageSelectionChangeEventArgs } from \"./SelectionChangeEvent.js\";\nimport { IMODEL_CLOSE_SELECTION_CLEAR_SOURCE, SelectionStorage } from \"./SelectionStorage.js\";\n\n/**\n * Props for creating a `CachingHiliteSetProvider` instance.\n * @public\n */\nexport interface CachingHiliteSetProviderProps {\n /** Selection storage to use for retrieving the hilite set. */\n selectionStorage: SelectionStorage;\n\n /** A callback that should return iModel access by iModel key. */\n imodelProvider: (imodelKey: string) => ECClassHierarchyInspector & ECSqlQueryExecutor;\n\n /** An optional hilite set provider factory. If not provided, defaults to `createHiliteSetProvider` from this package. */\n createHiliteSetProvider?: typeof createHiliteSetProvider;\n}\n\n/**\n * Defines return value of `createCachingHiliteSetProvider`.\n *\n * **Warning:** Used in public API as a return value. Not expected to be created / extended by package\n * consumers, may be supplemented with required attributes any time.\n *\n * @see `createCachingHiliteSetProvider`\n * @public\n */\nexport interface CachingHiliteSetProvider {\n /** Get the current hilite set iterator for the specified imodel */\n getHiliteSet(props: {\n /** iModel to get hilite set for */\n imodelKey: string;\n }): AsyncIterableIterator<HiliteSet>;\n\n /**\n * Disposes the cache.\n *\n * Optional to avoid breaking the API. Will be made required when the deprecated\n * `dispose` is removed.\n */\n [Symbol.dispose]?: () => void;\n\n /**\n * Disposes the cache.\n * @deprecated in 1.2. Use `[Symbol.dispose]` instead.\n */\n dispose(): void;\n}\n\n/**\n * Creates a hilite set provider that caches hilite set for current selection for given iModel so any subsequent\n * hilite set requests for the same iModel don't cost until selection in given selection storage changes.\n * @public\n */\nexport function createCachingHiliteSetProvider(props: CachingHiliteSetProviderProps): CachingHiliteSetProvider & { [Symbol.dispose]: () => void } {\n return new CachingHiliteSetProviderImpl(props);\n}\n\nclass CachingHiliteSetProviderImpl implements CachingHiliteSetProvider {\n private _selectionStorage: SelectionStorage;\n private _hiliteSetProviders = new Map<string, HiliteSetProvider>();\n private _cache = new Map<string, Observable<HiliteSet>>();\n private _removeListener: () => void;\n private _imodelProvider: (imodelKey: string) => ECClassHierarchyInspector & ECSqlQueryExecutor;\n private _createHiliteSetProvider: typeof createHiliteSetProvider;\n\n constructor(props: CachingHiliteSetProviderProps) {\n this._selectionStorage = props.selectionStorage;\n this._imodelProvider = props.imodelProvider;\n this._removeListener = this._selectionStorage.selectionChangeEvent.addListener((args: StorageSelectionChangeEventArgs) => {\n this._cache.delete(args.imodelKey);\n if (args.changeType === \"clear\" && args.source === IMODEL_CLOSE_SELECTION_CLEAR_SOURCE) {\n this._hiliteSetProviders.delete(args.imodelKey);\n }\n });\n this._createHiliteSetProvider = props.createHiliteSetProvider ?? /* c8 ignore next */ createHiliteSetProvider;\n }\n\n public getHiliteSet({ imodelKey }: { imodelKey: string }): AsyncIterableIterator<HiliteSet> {\n const imodelAccess = this._imodelProvider(imodelKey);\n const provider = this.getHiliteSetProvider(imodelKey, imodelAccess);\n let hiliteSet = this._cache.get(imodelKey);\n\n if (!hiliteSet) {\n const selectables = this._selectionStorage.getSelection({ imodelKey });\n hiliteSet = from(provider.getHiliteSet({ selectables })).pipe(shareReplay({ refCount: true }));\n this._cache.set(imodelKey, hiliteSet);\n }\n\n return eachValueFrom(hiliteSet);\n }\n\n public [Symbol.dispose](): void {\n this._removeListener();\n this._hiliteSetProviders = new Map();\n this._cache = new Map();\n }\n\n /* c8 ignore next 3 */\n public dispose(): void {\n this[Symbol.dispose]();\n }\n\n private getHiliteSetProvider(imodelKey: string, imodelAccess: ECClassHierarchyInspector & ECSqlQueryExecutor) {\n let provider = this._hiliteSetProviders.get(imodelKey);\n if (!provider) {\n provider = this._createHiliteSetProvider({ imodelAccess });\n this._hiliteSetProviders.set(imodelKey, provider);\n }\n return provider;\n }\n}\n"]}
@@ -1,7 +1,8 @@
1
1
  import "./DisposePolyfill.js";
2
2
  import { ECClassHierarchyInspector, ECSqlQueryExecutor } from "@itwin/presentation-shared";
3
3
  import { CachingHiliteSetProvider } from "./CachingHiliteSetProvider.js";
4
- import { ComputeSelectionProps } from "./SelectionScope.js";
4
+ import { HiliteSetProvider } from "./HiliteSetProvider.js";
5
+ import { SelectionScope } from "./SelectionScope.js";
5
6
  import { SelectionStorage } from "./SelectionStorage.js";
6
7
  import { CoreIModelHiliteSet, CoreIModelSelectionSet } from "./types/IModel.js";
7
8
  /**
@@ -11,8 +12,9 @@ import { CoreIModelHiliteSet, CoreIModelSelectionSet } from "./types/IModel.js";
11
12
  export interface EnableUnifiedSelectionSyncWithIModelProps {
12
13
  /**
13
14
  * Provides access to different iModel's features: query executing, class hierarchy, selection and hilite sets.
14
- * It's recommended to use `@itwin/presentation-core-interop` to create `ECSqlQueryExecutor` and `ECSchemaProvider` from
15
- * [IModelConnection](https://www.itwinjs.org/reference/core-frontend/imodelconnection/imodelconnection/) and map its `key`,
15
+ *
16
+ * It's recommended to use `@itwin/presentation-core-interop` to create `key`, `ECSqlQueryExecutor` and `ECSchemaProvider` from
17
+ * [IModelConnection](https://www.itwinjs.org/reference/core-frontend/imodelconnection/imodelconnection/), and map its
16
18
  * `hilited` and `selectionSet` attributes like this:
17
19
  *
18
20
  * ```ts
@@ -28,7 +30,7 @@ export interface EnableUnifiedSelectionSyncWithIModelProps {
28
30
  * hiliteSet: imodel.hilited,
29
31
  * selectionSet: imodel.selectionSet,
30
32
  * };
31
- * ```.
33
+ * ```
32
34
  */
33
35
  imodelAccess: ECSqlQueryExecutor & ECClassHierarchyInspector & {
34
36
  /** Key of the iModel. Generally taken from `IModelConnection.key`. */
@@ -38,10 +40,13 @@ export interface EnableUnifiedSelectionSyncWithIModelProps {
38
40
  /** The set of currently selected elements taken from `IModelConnection.selectionSet`. */
39
41
  readonly selectionSet: CoreIModelSelectionSet;
40
42
  };
41
- /** Selection storage to synchronize IModel's tool selection with. */
43
+ /**
44
+ * Unified selection storage to synchronize IModel's tool selection with. The storage should be shared
45
+ * across all components in the application to ensure unified selection experience.
46
+ */
42
47
  selectionStorage: SelectionStorage;
43
- /** Active scope provider. */
44
- activeScopeProvider: () => ComputeSelectionProps["scope"];
48
+ /** Active selection scope provider. */
49
+ activeScopeProvider: () => SelectionScope;
45
50
  /**
46
51
  * A caching hilite set provider used to retrieve hilite sets for an iModel. If not provided, a new `CachingHiliteSetProvider`
47
52
  * will be created for the given iModel using the provided `imodelAccess`.
@@ -62,8 +67,9 @@ export interface EnableUnifiedSelectionSyncWithIModelProps {
62
67
  */
63
68
  export declare function enableUnifiedSelectionSyncWithIModel(props: EnableUnifiedSelectionSyncWithIModelProps): () => void;
64
69
  /**
65
- * A handler that syncs selection between unified selection storage
66
- * (`SelectionStorage`) and an iModel (`iModel.selectionSet`, `iModel.hilited`).
70
+ * A handler that syncs selection between unified selection storage (`SelectionStorage`) and
71
+ * an iModel (`iModel.selectionSet`, `iModel.hilited`).
72
+ *
67
73
  * @internal
68
74
  */
69
75
  export declare class IModelSelectionHandler {
@@ -78,7 +84,9 @@ export declare class IModelSelectionHandler {
78
84
  private _unregisterUnifiedSelectionListener;
79
85
  private _unregisterIModelSelectionSetListener;
80
86
  private _hasCustomCachingHiliteSetProvider;
81
- constructor(props: EnableUnifiedSelectionSyncWithIModelProps);
87
+ constructor(props: EnableUnifiedSelectionSyncWithIModelProps & {
88
+ hiliteSetProvider?: HiliteSetProvider;
89
+ });
82
90
  [Symbol.dispose](): void;
83
91
  /** Temporarily suspends tool selection synchronization until the returned disposable object is disposed. */
84
92
  suspendIModelToolSelectionSync(): {
@@ -1 +1 @@
1
- {"version":3,"file":"EnableUnifiedSelectionSyncWithIModel.d.ts","sourceRoot":"","sources":["../../../src/unified-selection/EnableUnifiedSelectionSyncWithIModel.ts"],"names":[],"mappings":"AAKA,OAAO,sBAAsB,CAAC;AAE9B,OAAO,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAC3F,OAAO,EAAE,wBAAwB,EAAkC,MAAM,+BAA+B,CAAC;AAIzG,OAAO,EAAoB,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC9E,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAA6E,MAAM,mBAAmB,CAAC;AAG3J;;;GAGG;AACH,MAAM,WAAW,yCAAyC;IACxD;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,YAAY,EAAE,kBAAkB,GAC9B,yBAAyB,GAAG;QAC1B,sEAAsE;QACtE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QACrB,mFAAmF;QACnF,QAAQ,CAAC,SAAS,EAAE,mBAAmB,CAAC;QACxC,yFAAyF;QACzF,QAAQ,CAAC,YAAY,EAAE,sBAAsB,CAAC;KAC/C,CAAC;IAEJ,qEAAqE;IACrE,gBAAgB,EAAE,gBAAgB,CAAC;IAEnC,6BAA6B;IAC7B,mBAAmB,EAAE,MAAM,qBAAqB,CAAC,OAAO,CAAC,CAAC;IAE1D;;;;;;;;OAQG;IACH,wBAAwB,CAAC,EAAE,wBAAwB,GAAG,CAAC,IAAI,CAAC,wBAAwB,EAAE,SAAS,CAAC,GAAG;QAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC,CAAC;CACtI;AAED;;;;GAIG;AACH,wBAAgB,oCAAoC,CAAC,KAAK,EAAE,yCAAyC,GAAG,MAAM,IAAI,CAGjH;AAED;;;;GAIG;AACH,qBAAa,sBAAsB;IACjC,OAAO,CAAC,oBAAoB,CAAU;IAEtC,OAAO,CAAC,aAAa,CAA4D;IACjF,OAAO,CAAC,iBAAiB,CAAmB;IAC5C,OAAO,CAAC,kBAAkB,CAAoB;IAC9C,OAAO,CAAC,yBAAyB,CAAqF;IACtH,OAAO,CAAC,oBAAoB,CAAuC;IAEnE,OAAO,CAAC,YAAY,CAAU;IAC9B,OAAO,CAAC,qBAAqB,CAAuB;IACpD,OAAO,CAAC,mCAAmC,CAAa;IACxD,OAAO,CAAC,qCAAqC,CAAa;IAC1D,OAAO,CAAC,kCAAkC,CAAU;gBAEjC,KAAK,EAAE,yCAAyC;IAqB5D,CAAC,MAAM,CAAC,OAAO,CAAC;IASvB,4GAA4G;IACrG,8BAA8B;;;IAUrC,OAAO,CAAC,4BAA4B;IA2BpC,OAAO,CAAC,yBAAyB,CAU/B;IAEF,OAAO,CAAC,qBAAqB;IAgB7B,OAAO,CAAC,YAAY;IAwBpB,OAAO,CAAC,eAAe;IAuBvB,OAAO,CAAC,wBAAwB,CAmB9B;YAEY,2BAA2B;IAiBzC,OAAO,CAAC,wBAAwB;CAcjC"}
1
+ {"version":3,"file":"EnableUnifiedSelectionSyncWithIModel.d.ts","sourceRoot":"","sources":["../../../src/unified-selection/EnableUnifiedSelectionSyncWithIModel.ts"],"names":[],"mappings":"AAKA,OAAO,sBAAsB,CAAC;AAG9B,OAAO,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAC3F,OAAO,EAAE,wBAAwB,EAAkC,MAAM,+BAA+B,CAAC;AACzG,OAAO,EAAsC,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAG/F,OAAO,EAAoB,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAA6E,MAAM,mBAAmB,CAAC;AAG3J;;;GAGG;AACH,MAAM,WAAW,yCAAyC;IACxD;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,YAAY,EAAE,kBAAkB,GAC9B,yBAAyB,GAAG;QAC1B,sEAAsE;QACtE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QACrB,mFAAmF;QACnF,QAAQ,CAAC,SAAS,EAAE,mBAAmB,CAAC;QACxC,yFAAyF;QACzF,QAAQ,CAAC,YAAY,EAAE,sBAAsB,CAAC;KAC/C,CAAC;IAEJ;;;OAGG;IACH,gBAAgB,EAAE,gBAAgB,CAAC;IAEnC,uCAAuC;IACvC,mBAAmB,EAAE,MAAM,cAAc,CAAC;IAE1C;;;;;;;;OAQG;IACH,wBAAwB,CAAC,EAAE,wBAAwB,GAAG,CAAC,IAAI,CAAC,wBAAwB,EAAE,SAAS,CAAC,GAAG;QAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC,CAAC;CACtI;AAED;;;;GAIG;AACH,wBAAgB,oCAAoC,CAAC,KAAK,EAAE,yCAAyC,GAAG,MAAM,IAAI,CAGjH;AAED;;;;;GAKG;AACH,qBAAa,sBAAsB;IACjC,OAAO,CAAC,oBAAoB,CAAU;IAEtC,OAAO,CAAC,aAAa,CAA4D;IACjF,OAAO,CAAC,iBAAiB,CAAmB;IAC5C,OAAO,CAAC,kBAAkB,CAAoB;IAC9C,OAAO,CAAC,yBAAyB,CAAqF;IACtH,OAAO,CAAC,oBAAoB,CAAuB;IAEnD,OAAO,CAAC,YAAY,CAAU;IAC9B,OAAO,CAAC,qBAAqB,CAAuB;IACpD,OAAO,CAAC,mCAAmC,CAAa;IACxD,OAAO,CAAC,qCAAqC,CAAa;IAC1D,OAAO,CAAC,kCAAkC,CAAU;gBAEjC,KAAK,EAAE,yCAAyC,GAAG;QAAE,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;KAAE;IA0BxG,CAAC,MAAM,CAAC,OAAO,CAAC;IAUvB,4GAA4G;IACrG,8BAA8B;;;IAUrC,OAAO,CAAC,4BAA4B;IAsCpC,OAAO,CAAC,yBAAyB,CAU/B;IAEF,OAAO,CAAC,qBAAqB;IAoB7B,OAAO,CAAC,YAAY;IAwBpB,OAAO,CAAC,eAAe;IAuBvB,OAAO,CAAC,wBAAwB,CAmB9B;YAEY,2BAA2B;IAiBzC,OAAO,CAAC,wBAAwB;CAcjC"}
@@ -75,8 +75,9 @@ function enableUnifiedSelectionSyncWithIModel(props) {
75
75
  return () => selectionHandler[Symbol.dispose]();
76
76
  }
77
77
  /**
78
- * A handler that syncs selection between unified selection storage
79
- * (`SelectionStorage`) and an iModel (`iModel.selectionSet`, `iModel.hilited`).
78
+ * A handler that syncs selection between unified selection storage (`SelectionStorage`) and
79
+ * an iModel (`iModel.selectionSet`, `iModel.hilited`).
80
+ *
80
81
  * @internal
81
82
  */
82
83
  class IModelSelectionHandler {
@@ -96,22 +97,28 @@ class IModelSelectionHandler {
96
97
  this._selectionStorage = props.selectionStorage;
97
98
  this._activeScopeProvider = props.activeScopeProvider;
98
99
  this._isSuspended = false;
100
+ this._hiliteSetProvider = props.hiliteSetProvider ?? (0, HiliteSetProvider_js_1.createHiliteSetProvider)({ imodelAccess: this._imodelAccess });
99
101
  this._hasCustomCachingHiliteSetProvider = !!props.cachingHiliteSetProvider;
100
102
  this._cachingHiliteSetProvider =
101
- props.cachingHiliteSetProvider ??
102
- (0, CachingHiliteSetProvider_js_1.createCachingHiliteSetProvider)({
103
+ props.cachingHiliteSetProvider /* c8 ignore next */ ??
104
+ /* c8 ignore next 4 */ (0, CachingHiliteSetProvider_js_1.createCachingHiliteSetProvider)({
103
105
  selectionStorage: this._selectionStorage,
104
106
  imodelProvider: () => this._imodelAccess,
107
+ createHiliteSetProvider: () => this._hiliteSetProvider,
105
108
  });
106
- this._hiliteSetProvider = (0, HiliteSetProvider_js_1.createHiliteSetProvider)({ imodelAccess: this._imodelAccess });
107
109
  this._unregisterIModelSelectionSetListener = this._imodelAccess.selectionSet.onChanged.addListener(this.onIModelSelectionChanged);
108
110
  this._unregisterUnifiedSelectionListener = this._selectionStorage.selectionChangeEvent.addListener(this.onUnifiedSelectionChanged);
109
- this.applyCurrentHiliteSet({ activeSelectionAction: "clear" });
111
+ if (!is5xSelectionSet(this._imodelAccess.selectionSet)) {
112
+ // itwinjs-core@4: stop imodel from syncing tool selection with hilited list - we want to manage that sync ourselves
113
+ this._imodelAccess.hiliteSet.wantSyncWithSelectionSet = false;
114
+ }
115
+ this.applyCurrentHiliteSet({ activeSelectionAction: "clearAll" });
110
116
  }
111
117
  [Symbol.dispose]() {
112
118
  this._cancelOngoingChanges.next();
113
119
  this._unregisterIModelSelectionSetListener();
114
120
  this._unregisterUnifiedSelectionListener();
121
+ /* c8 ignore next 3 */
115
122
  if (!this._hasCustomCachingHiliteSetProvider) {
116
123
  (0, Utils_js_1.safeDispose)(this._cachingHiliteSetProvider);
117
124
  }
@@ -129,8 +136,18 @@ class IModelSelectionHandler {
129
136
  handleUnifiedSelectionChange(changeType, selectables, source) {
130
137
  switch (changeType) {
131
138
  case "clear":
139
+ return this.applyCurrentHiliteSet({ activeSelectionAction: "clearAll" });
132
140
  case "replace":
133
- return this.applyCurrentHiliteSet({ activeSelectionAction: source === "Tool" ? "keep" : "clear" });
141
+ return this.applyCurrentHiliteSet({
142
+ activeSelectionAction: source === this._selectionSourceName
143
+ ? is5xSelectionSet(this._imodelAccess.selectionSet)
144
+ ? // with 5x core we don't need to clear anything when event is triggered by a Tool (hilite and selection sets are in sync already)
145
+ "keep"
146
+ : // with 4x core we need to clear hilite set, because it's not synced with selection set
147
+ "clearHilited"
148
+ : // when event is triggered not by a Tool, we need to clear everything
149
+ "clearAll",
150
+ });
134
151
  case "add":
135
152
  return void (0, rxjs_1.from)(this._hiliteSetProvider.getHiliteSet({ selectables }))
136
153
  .pipe((0, rxjs_1.takeUntil)(this._cancelOngoingChanges))
@@ -163,12 +180,16 @@ class IModelSelectionHandler {
163
180
  this.handleUnifiedSelectionChange(args.changeType, args.selectables, args.source);
164
181
  };
165
182
  applyCurrentHiliteSet({ activeSelectionAction }) {
166
- if (activeSelectionAction === "clear") {
183
+ if (activeSelectionAction !== "keep") {
167
184
  const env_1 = { stack: [], error: void 0, hasError: false };
168
185
  try {
169
186
  const _dispose = __addDisposableResource(env_1, this.suspendIModelToolSelectionSync(), false);
170
- this._imodelAccess.hiliteSet.clear();
171
- this._imodelAccess.selectionSet.emptyAll();
187
+ if (!is5xSelectionSet(this._imodelAccess.selectionSet)) {
188
+ this._imodelAccess.hiliteSet.clear();
189
+ }
190
+ if (activeSelectionAction === "clearAll") {
191
+ this._imodelAccess.selectionSet.emptyAll();
192
+ }
172
193
  }
173
194
  catch (e_1) {
174
195
  env_1.error = e_1;
@@ -190,9 +211,8 @@ class IModelSelectionHandler {
190
211
  const env_2 = { stack: [], error: void 0, hasError: false };
191
212
  try {
192
213
  const _dispose = __addDisposableResource(env_2, this.suspendIModelToolSelectionSync(), false);
193
- if ("active" in this._imodelAccess.selectionSet) {
194
- // the `active` property tells us we're using 5.0 core, which supports models and subcategories
195
- // in selection set - we can simply add the set as a whole
214
+ if (is5xSelectionSet(this._imodelAccess.selectionSet)) {
215
+ // with 5.x core we can simply add the set as a whole
196
216
  this._imodelAccess.selectionSet.add({
197
217
  models: set.models,
198
218
  subcategories: set.subCategories,
@@ -208,6 +228,7 @@ class IModelSelectionHandler {
208
228
  this._imodelAccess.hiliteSet.subcategories.addIds(set.subCategories);
209
229
  }
210
230
  if (set.elements.length) {
231
+ this._imodelAccess.hiliteSet.elements.addIds(set.elements);
211
232
  this._imodelAccess.selectionSet.add(set.elements);
212
233
  }
213
234
  }
@@ -224,9 +245,8 @@ class IModelSelectionHandler {
224
245
  const env_3 = { stack: [], error: void 0, hasError: false };
225
246
  try {
226
247
  const _dispose = __addDisposableResource(env_3, this.suspendIModelToolSelectionSync(), false);
227
- if ("active" in this._imodelAccess.selectionSet) {
228
- // the `active` property tells us we're using 5.0 core, which supports models and subcategories
229
- // in selection set - we can simply remove the set as a whole
248
+ if (is5xSelectionSet(this._imodelAccess.selectionSet)) {
249
+ // with 5.x core we can simply remove the set as a whole
230
250
  this._imodelAccess.selectionSet.remove({
231
251
  models: set.models,
232
252
  subcategories: set.subCategories,
@@ -241,6 +261,7 @@ class IModelSelectionHandler {
241
261
  this._imodelAccess.hiliteSet.subcategories.deleteIds(set.subCategories);
242
262
  }
243
263
  if (set.elements.length) {
264
+ this._imodelAccess.hiliteSet.elements.deleteIds(set.elements);
244
265
  this._imodelAccess.selectionSet.remove(set.elements);
245
266
  }
246
267
  }
@@ -295,4 +316,7 @@ class IModelSelectionHandler {
295
316
  }
296
317
  }
297
318
  exports.IModelSelectionHandler = IModelSelectionHandler;
319
+ function is5xSelectionSet(selectionSet) {
320
+ return "active" in selectionSet;
321
+ }
298
322
  //# sourceMappingURL=EnableUnifiedSelectionSyncWithIModel.js.map