@itwin/unified-selection 0.1.0 → 0.3.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 (82) hide show
  1. package/CHANGELOG.md +129 -0
  2. package/README.md +104 -6
  3. package/lib/cjs/unified-selection/CachingHiliteSetProvider.d.ts +33 -0
  4. package/lib/cjs/unified-selection/CachingHiliteSetProvider.d.ts.map +1 -0
  5. package/lib/cjs/unified-selection/CachingHiliteSetProvider.js +62 -0
  6. package/lib/cjs/unified-selection/CachingHiliteSetProvider.js.map +1 -0
  7. package/lib/cjs/unified-selection/EnableUnifiedSelectionSyncWithIModel.d.ts +90 -0
  8. package/lib/cjs/unified-selection/EnableUnifiedSelectionSyncWithIModel.d.ts.map +1 -0
  9. package/lib/cjs/unified-selection/EnableUnifiedSelectionSyncWithIModel.js +205 -0
  10. package/lib/cjs/unified-selection/EnableUnifiedSelectionSyncWithIModel.js.map +1 -0
  11. package/lib/cjs/unified-selection/HiliteSetProvider.d.ts +37 -0
  12. package/lib/cjs/unified-selection/HiliteSetProvider.d.ts.map +1 -0
  13. package/lib/cjs/unified-selection/HiliteSetProvider.js +344 -0
  14. package/lib/cjs/unified-selection/HiliteSetProvider.js.map +1 -0
  15. package/lib/cjs/unified-selection/Selectable.d.ts +0 -3
  16. package/lib/cjs/unified-selection/Selectable.d.ts.map +1 -1
  17. package/lib/cjs/unified-selection/Selectable.js +2 -2
  18. package/lib/cjs/unified-selection/Selectable.js.map +1 -1
  19. package/lib/cjs/unified-selection/SelectionChangeEvent.d.ts +11 -7
  20. package/lib/cjs/unified-selection/SelectionChangeEvent.d.ts.map +1 -1
  21. package/lib/cjs/unified-selection/SelectionChangeEvent.js +1 -1
  22. package/lib/cjs/unified-selection/SelectionChangeEvent.js.map +1 -1
  23. package/lib/cjs/unified-selection/SelectionScope.d.ts +44 -0
  24. package/lib/cjs/unified-selection/SelectionScope.d.ts.map +1 -0
  25. package/lib/cjs/unified-selection/SelectionScope.js +193 -0
  26. package/lib/cjs/unified-selection/SelectionScope.js.map +1 -0
  27. package/lib/cjs/unified-selection/SelectionStorage.d.ts +34 -29
  28. package/lib/cjs/unified-selection/SelectionStorage.d.ts.map +1 -1
  29. package/lib/cjs/unified-selection/SelectionStorage.js +32 -18
  30. package/lib/cjs/unified-selection/SelectionStorage.js.map +1 -1
  31. package/lib/cjs/unified-selection/Utils.d.ts +7 -0
  32. package/lib/cjs/unified-selection/Utils.d.ts.map +1 -0
  33. package/lib/cjs/unified-selection/Utils.js +24 -0
  34. package/lib/cjs/unified-selection/Utils.js.map +1 -0
  35. package/lib/cjs/unified-selection/types/IModel.d.ts +84 -0
  36. package/lib/cjs/unified-selection/types/IModel.d.ts.map +1 -0
  37. package/lib/cjs/unified-selection/types/IModel.js +24 -0
  38. package/lib/cjs/unified-selection/types/IModel.js.map +1 -0
  39. package/lib/cjs/unified-selection.d.ts +5 -7
  40. package/lib/cjs/unified-selection.d.ts.map +1 -1
  41. package/lib/cjs/unified-selection.js +11 -7
  42. package/lib/cjs/unified-selection.js.map +1 -1
  43. package/lib/esm/unified-selection/CachingHiliteSetProvider.d.ts +33 -0
  44. package/lib/esm/unified-selection/CachingHiliteSetProvider.d.ts.map +1 -0
  45. package/lib/esm/unified-selection/CachingHiliteSetProvider.js +58 -0
  46. package/lib/esm/unified-selection/CachingHiliteSetProvider.js.map +1 -0
  47. package/lib/esm/unified-selection/EnableUnifiedSelectionSyncWithIModel.d.ts +90 -0
  48. package/lib/esm/unified-selection/EnableUnifiedSelectionSyncWithIModel.d.ts.map +1 -0
  49. package/lib/esm/unified-selection/EnableUnifiedSelectionSyncWithIModel.js +200 -0
  50. package/lib/esm/unified-selection/EnableUnifiedSelectionSyncWithIModel.js.map +1 -0
  51. package/lib/esm/unified-selection/HiliteSetProvider.d.ts +37 -0
  52. package/lib/esm/unified-selection/HiliteSetProvider.d.ts.map +1 -0
  53. package/lib/esm/unified-selection/HiliteSetProvider.js +340 -0
  54. package/lib/esm/unified-selection/HiliteSetProvider.js.map +1 -0
  55. package/lib/esm/unified-selection/Selectable.d.ts +0 -3
  56. package/lib/esm/unified-selection/Selectable.d.ts.map +1 -1
  57. package/lib/esm/unified-selection/Selectable.js.map +1 -1
  58. package/lib/esm/unified-selection/SelectionChangeEvent.d.ts +11 -7
  59. package/lib/esm/unified-selection/SelectionChangeEvent.d.ts.map +1 -1
  60. package/lib/esm/unified-selection/SelectionChangeEvent.js +1 -1
  61. package/lib/esm/unified-selection/SelectionChangeEvent.js.map +1 -1
  62. package/lib/esm/unified-selection/SelectionScope.d.ts +44 -0
  63. package/lib/esm/unified-selection/SelectionScope.d.ts.map +1 -0
  64. package/lib/esm/unified-selection/SelectionScope.js +189 -0
  65. package/lib/esm/unified-selection/SelectionScope.js.map +1 -0
  66. package/lib/esm/unified-selection/SelectionStorage.d.ts +34 -29
  67. package/lib/esm/unified-selection/SelectionStorage.d.ts.map +1 -1
  68. package/lib/esm/unified-selection/SelectionStorage.js +31 -17
  69. package/lib/esm/unified-selection/SelectionStorage.js.map +1 -1
  70. package/lib/esm/unified-selection/Utils.d.ts +7 -0
  71. package/lib/esm/unified-selection/Utils.d.ts.map +1 -0
  72. package/lib/esm/unified-selection/Utils.js +20 -0
  73. package/lib/esm/unified-selection/Utils.js.map +1 -0
  74. package/lib/esm/unified-selection/types/IModel.d.ts +84 -0
  75. package/lib/esm/unified-selection/types/IModel.d.ts.map +1 -0
  76. package/lib/esm/unified-selection/types/IModel.js +21 -0
  77. package/lib/esm/unified-selection/types/IModel.js.map +1 -0
  78. package/lib/esm/unified-selection.d.ts +5 -7
  79. package/lib/esm/unified-selection.d.ts.map +1 -1
  80. package/lib/esm/unified-selection.js +5 -7
  81. package/lib/esm/unified-selection.js.map +1 -1
  82. package/package.json +28 -15
package/CHANGELOG.md CHANGED
@@ -1,5 +1,134 @@
1
1
  # @itwin/unified-selection
2
2
 
3
+ ## 0.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#530](https://github.com/iTwin/presentation/pull/530): Added `enableUnifiedSelectionSyncWithIModel` for enabling synchronization between iModel's tool selection and unified selection storage.
8
+ - [#544](https://github.com/iTwin/presentation/pull/544): Breaking API changes
9
+
10
+ - The type of ECSQL query executor's `createQueryReader` function was changed from:
11
+
12
+ ```ts
13
+ // createQueryReader(ecsql: string, bindings?: ECSqlBinding[], config?: ECSqlQueryReaderOptions): ECSqlQueryReader;
14
+ // usage:
15
+ const reader = executor.createQueryReader(
16
+ `
17
+ WITH RECURSIVE
18
+ ChildElements(ECInstanceId) AS (
19
+ SELECT ECInstanceId FROM bis.Element WHERE Parent.Id = ?
20
+ UNION ALL
21
+ SELECT c.ECInstanceId FROM bis.Element c JOIN ChildElements p ON c.Parent.Id = p.ECInstanceId
22
+ )
23
+ SELECT * FROM ChildElements
24
+ `,
25
+ [{ type: "id", value: "0x1" }],
26
+ { rowFormat: "Indexes" },
27
+ );
28
+ ```
29
+
30
+ to:
31
+
32
+ ```ts
33
+ // createQueryReader(query: { ctes?: string; ecsql: string; bindings?: ECSqlBinding[] }, config?: ECSqlQueryReaderOptions): ECSqlQueryReader;
34
+ // usage:
35
+ const reader = executor.createQueryReader(
36
+ {
37
+ ctes: [
38
+ `
39
+ ChildElements(ECInstanceId) AS (
40
+ SELECT ECInstanceId FROM bis.Element WHERE Parent.Id = ?
41
+ UNION ALL
42
+ SELECT c.ECInstanceId FROM bis.Element c JOIN ChildElements p ON c.Parent.Id = p.ECInstanceId
43
+ )
44
+ `,
45
+ ],
46
+ ecsql: "SELECT * FROM ChildElements",
47
+ bindings: [{ type: "id", value: "0x1" }],
48
+ },
49
+ { rowFormat: "Indexes" },
50
+ );
51
+ ```
52
+
53
+ This makes the API consistent with other Presentation packages and allows additional manipulation on ECSQL, which was not possible previously when ECSQL contained CTEs.
54
+
55
+ The change affects the following public APIs:
56
+
57
+ - `computeSelection` (`queryExecutor` prop),
58
+ - `createHiliteSetProvider` (previously `queryExecutor` prop, now `imodelAccess` prop),
59
+ - `createCachingHiliteSetProvider` (`iModelProvider` prop).
60
+
61
+ - `createHiliteSetProvider` function props `queryExecutor` and `schemaProvider` were merged into a single `imodelAccess` prop with merged type.
62
+
63
+ Previously:
64
+
65
+ ```ts
66
+ createHiliteSetProvider({
67
+ queryExecutor: createECSqlQueryExecutor(iModel),
68
+ schemaProvider: createECSchemaProvider(iModel),
69
+ });
70
+ ```
71
+
72
+ Now:
73
+
74
+ ```ts
75
+ createHiliteSetProvider({
76
+ imodelAccess: {
77
+ ...createECSqlQueryExecutor(iModel),
78
+ ...createECSchemaProvider(iModel),
79
+ },
80
+ });
81
+ ```
82
+
83
+ - `createCachingHiliteSetProvider` function prop `iModelProvider` was changed to return an object of merged type `ECSchemaProvider & ECSqlQueryExecutor` rather than `{ queryExecutor: ECSqlQueryExecutor; schemaProvider: ECSchemaProvider }`.
84
+
85
+ Previously:
86
+
87
+ ```ts
88
+ createCachingHiliteSetProvider({
89
+ selectionStorage,
90
+ iModelProvider: (key) => ({
91
+ queryExecutor: createECSqlQueryExecutor(iModel),
92
+ schemaProvider: createECSchemaProvider(iModel),
93
+ }),
94
+ });
95
+ ```
96
+
97
+ Now:
98
+
99
+ ```ts
100
+ createCachingHiliteSetProvider({
101
+ selectionStorage,
102
+ iModelProvider: (key) => ({
103
+ ...createECSqlQueryExecutor(iModel),
104
+ ...createECSchemaProvider(iModel),
105
+ }),
106
+ });
107
+ ```
108
+
109
+ - [#551](https://github.com/iTwin/presentation/pull/551): Changed `iModel` in attribute names to `imodel`. The change was made to be consistent with other Presentation packages and affects the following APIs:
110
+
111
+ - `SelectionStorage` methods now accept `imodelKey` prop rather than `iModelKey`. It's `selectionChangeEvent` is also now raised with `imodelKey` prop in `StorageSelectionChangeEventArgs`.
112
+ - `CachingHiliteSetProvider.getHiliteSet` now accepts an `imodelKey` prop rather than `iModelKey`.
113
+ - `createCachingHiliteSetProvider` props now accept `imodelProvider` callback rather than `iModelProvider`.
114
+
115
+ - [#553](https://github.com/iTwin/presentation/pull/553): Expose types from `@itwin/presentation-shared` rather than having our own copies.
116
+
117
+ ### Patch Changes
118
+
119
+ - Updated dependencies:
120
+ - @itwin/presentation-shared@0.1.0
121
+
122
+ ## 0.2.0
123
+
124
+ ### Minor Changes
125
+
126
+ - [#488](https://github.com/iTwin/presentation/pull/488): Added API for getting hilite sets for `Selectables` and active `SelectionStorage` selection.
127
+
128
+ ### Patch Changes
129
+
130
+ - [#495](https://github.com/iTwin/presentation/pull/495): Added license field to `package.json`.
131
+
3
132
  ## 0.1.0
4
133
 
5
134
  ### Minor Changes
package/README.md CHANGED
@@ -32,14 +32,14 @@ const unifiedSelection = createStore();
32
32
 
33
33
  // the store should to be cleaned up when iModels are closed to free up memory, e.g.:
34
34
  import { IModelConnection } from "@itwin/core-frontend";
35
- IModelConnection.onClose.addListener((iModel) => {
36
- unifiedSelection.clearStorage(iModel.key);
35
+ IModelConnection.onClose.addListener((imodel) => {
36
+ unifiedSelection.clearStorage(imodel.key);
37
37
  });
38
38
 
39
39
  // add a demo selection listener
40
40
  import { Selectables } from "@itwin/unified-selection";
41
- unifiedSelection.selectionChangeEvent.addListener(({ iModelKey, source, changeType, selectables }) => {
42
- const suffix = `in ${iModelKey} iModel from ${source} component`;
41
+ unifiedSelection.selectionChangeEvent.addListener(({ imodelKey, source, changeType, selectables }) => {
42
+ const suffix = `in ${imodelKey} iModel from ${source} component`;
43
43
  const numSelectables = Selectables.size(selectables);
44
44
  switch (changeType) {
45
45
  case "add":
@@ -58,8 +58,8 @@ unifiedSelection.selectionChangeEvent.addListener(({ iModelKey, source, changeTy
58
58
  });
59
59
 
60
60
  // in some component
61
- MyComponent.onECInstanceSelected((iModel: IModelConnection, key: { className: string; id: Id64String }) => {
62
- unifiedSelection.addToSelection({ iModelKey: iModel.key, source: "MyComponent", selectables: [key] });
61
+ MyComponent.onECInstanceSelected((imodel: IModelConnection, key: { className: string; id: Id64String }) => {
62
+ unifiedSelection.addToSelection({ imodelKey: imodel.key, source: "MyComponent", selectables: [key] });
63
63
  });
64
64
  ```
65
65
 
@@ -88,3 +88,101 @@ With that in mind, the above components _A_, _B_ and _C_ can be configured as fo
88
88
  - _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.
89
89
  - _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.
90
90
  - _Component C_ reloads its content no matter the selection level.
91
+
92
+ ### Hilite sets
93
+
94
+ > **Note:** hilite = highlight
95
+
96
+ `@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/categories/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:
97
+
98
+ - for `BisCore.Subject` return IDs of all geometric models that are recursively under that Subject,
99
+ - for `BisCore.Model` just return its ID,
100
+ - for `BisCore.PhysicalPartition` just return ID of a model that models it,
101
+ - for `BisCore.Category` return IDs of all its _SubCategories_,
102
+ - for `BisCore.SubCategory` just return its ID,
103
+ - for `BisCore.GeometricElement` return ID of its own and all its child elements recursively.
104
+
105
+ 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.
106
+
107
+ The `@itwin/unified-selection` package delivers APIs for creating a `HiliteSet` or retrieving it for _current_ selection in a `SelectionStorage`:
108
+
109
+ ```ts
110
+ // Components may want to get a hilite set for arbitrary set of Selectables - use `createHiliteSetProvider` for that.
111
+ import { IModelConnection } from "@itwin/core-frontend";
112
+ import { createECSqlQueryExecutor, createECSchemaProvider } from "@itwin/presentation-core-interop";
113
+ import { createHiliteSetProvider } from "@itwin/unified-selection";
114
+ const hiliteProvider = createHiliteSetProvider({
115
+ imodelAccess: {
116
+ ...createECSchemaProvider(imodel),
117
+ ...createECSqlQueryExecutor(imodel),
118
+ },
119
+ });
120
+ const hiliteSet = await hiliteProvider.getHiliteSet({ selectables });
121
+
122
+ // Some others may want to get a hilite set for _current_ selection in storage - use `createCachingHiliteSetProvider` for that. It's
123
+ // recommended to keep a single instance of this provider per application as it caches hilite sets per each iModel's selection.
124
+ import { createCachingHiliteSetProvider } from "@itwin/unified-selection";
125
+ const selectionHiliteProvider = createCachingHiliteSetProvider({
126
+ selectionStorage,
127
+ imodelProvider: (imodelKey: string) => getIModelByKey(imodelKey),
128
+ });
129
+ const selectionHiliteSet = await selectionHiliteProvider.getHiliteSet({ imodel.key });
130
+ // The caching provider registers a selection change listener and should be disposed, in case its lifetime
131
+ // is shorter than that of `SelectionStorage`, to unregister the listener.
132
+ selectionHiliteProvider.dispose();
133
+ ```
134
+
135
+ #### Selection scopes
136
+
137
+ 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.
138
+
139
+ Here are the scopes we support at the moment:
140
+
141
+ - `element` - return key of selected element.
142
+ - `category` - return key of geometric element's category.
143
+ - `model` - return key of element's model.
144
+ - `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.
145
+
146
+ 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:
147
+
148
+ ```ts
149
+ import { computeSelection } from "@itwin/unified-selection";
150
+ import { IModelConnection } from "@itwin/core-frontend";
151
+ import { createECSqlQueryExecutor } from "@itwin/presentation-core-interop";
152
+ const queryExecutor = createECSqlQueryExecutor(imodel);
153
+ const selection = computeSelection({ queryExecutor, elementIds, scope: "element" });
154
+ ```
155
+
156
+ `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.
157
+
158
+ 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`).
159
+
160
+ ```ts
161
+ import { computeSelection } from "@itwin/unified-selection";
162
+ import { IModelConnection } from "@itwin/core-frontend";
163
+ import { createECSqlQueryExecutor } from "@itwin/presentation-core-interop";
164
+ const queryExecutor = createECSqlQueryExecutor(imodel);
165
+ // Returns the parent element, or the element itself if it does not have a parent, for each element specified in `elementIds` argument.
166
+ const selection = computeSelection({ queryExecutor, elementIds, scope: { id: "element", ancestorLevel: 1 } });
167
+ ```
168
+
169
+ ## iModel selection synchronization with unified selection
170
+
171
+ 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:
172
+
173
+ ```ts
174
+ import { createECSqlQueryExecutor, createECSchemaProvider } from "@itwin/presentation-core-interop";
175
+ useEffect(() => {
176
+ return enableUnifiedSelectionSyncWithIModel({
177
+ imodelAccess: {
178
+ ...createECSqlQueryExecutor(imodel),
179
+ ...createECSchemaProvider(imodel),
180
+ key: imodel.key,
181
+ hiliteSet: imodel.hilited,
182
+ selectionSet: imodel.selectionSet,
183
+ },
184
+ selectionStorage,
185
+ activeScopeProvider: () => "element",
186
+ });
187
+ }, [imodel]);
188
+ ```
@@ -0,0 +1,33 @@
1
+ import { ECSchemaProvider, ECSqlQueryExecutor } from "@itwin/presentation-shared";
2
+ import { HiliteSet } from "./HiliteSetProvider";
3
+ import { SelectionStorage } from "./SelectionStorage";
4
+ /**
5
+ * Props for creating a `CachingHiliteSetProvider` instance.
6
+ * @internal Not exported through barrel, but used in public API as an argument. May be supplemented with optional attributes any time.
7
+ */
8
+ export interface CachingHiliteSetProviderProps {
9
+ selectionStorage: SelectionStorage;
10
+ imodelProvider: (imodelKey: string) => ECSchemaProvider & ECSqlQueryExecutor;
11
+ }
12
+ /**
13
+ * Defines return value of `createCachingHiliteSetProvider`.
14
+ *
15
+ * @beta Used in public API as a return value. Not expected to be created / extended by package
16
+ * consumers, may be supplemented with required attributes any time.
17
+ */
18
+ export interface CachingHiliteSetProvider {
19
+ /** Get the current hilite set iterator for the specified imodel */
20
+ getHiliteSet(props: {
21
+ /** iModel to get hilite set for */
22
+ imodelKey: string;
23
+ }): AsyncIterableIterator<HiliteSet>;
24
+ /** Disposes the cache. */
25
+ dispose(): void;
26
+ }
27
+ /**
28
+ * Creates a hilite set provider that caches hilite set for current selection for given iModel so any subsequent
29
+ * hilite set requests for the same iModel don't cost until selection in given selection storage changes.
30
+ * @beta
31
+ */
32
+ export declare function createCachingHiliteSetProvider(props: CachingHiliteSetProviderProps): CachingHiliteSetProvider;
33
+ //# sourceMappingURL=CachingHiliteSetProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CachingHiliteSetProvider.d.ts","sourceRoot":"","sources":["../../../src/unified-selection/CachingHiliteSetProvider.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAClF,OAAO,EAA2B,SAAS,EAAqB,MAAM,qBAAqB,CAAC;AAE5F,OAAO,EAAuC,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3F;;;GAGG;AACH,MAAM,WAAW,6BAA6B;IAC5C,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,cAAc,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,gBAAgB,GAAG,kBAAkB,CAAC;CAC9E;AAED;;;;;GAKG;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,0BAA0B;IAC1B,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,6BAA6B,GAAG,wBAAwB,CAE7G"}
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ /*---------------------------------------------------------------------------------------------
3
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
4
+ * See LICENSE.md in the project root for license terms and full copyright notice.
5
+ *--------------------------------------------------------------------------------------------*/
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.createCachingHiliteSetProvider = void 0;
8
+ const rxjs_1 = require("rxjs");
9
+ const rxjs_for_await_1 = require("rxjs-for-await");
10
+ const HiliteSetProvider_1 = require("./HiliteSetProvider");
11
+ const SelectionStorage_1 = require("./SelectionStorage");
12
+ /**
13
+ * Creates a hilite set provider that caches hilite set for current selection for given iModel so any subsequent
14
+ * hilite set requests for the same iModel don't cost until selection in given selection storage changes.
15
+ * @beta
16
+ */
17
+ function createCachingHiliteSetProvider(props) {
18
+ return new CachingHiliteSetProviderImpl(props);
19
+ }
20
+ exports.createCachingHiliteSetProvider = createCachingHiliteSetProvider;
21
+ class CachingHiliteSetProviderImpl {
22
+ _selectionStorage;
23
+ _hiliteSetProviders = new Map();
24
+ _cache = new Map();
25
+ _removeListener;
26
+ _imodelProvider;
27
+ constructor(props) {
28
+ this._selectionStorage = props.selectionStorage;
29
+ this._imodelProvider = props.imodelProvider;
30
+ this._removeListener = this._selectionStorage.selectionChangeEvent.addListener((args) => {
31
+ this._cache.delete(args.imodelKey);
32
+ if (args.changeType === "clear" && args.source === SelectionStorage_1.IMODEL_CLOSE_SELECTION_CLEAR_SOURCE) {
33
+ this._hiliteSetProviders.delete(args.imodelKey);
34
+ }
35
+ });
36
+ }
37
+ getHiliteSet({ imodelKey }) {
38
+ const imodelAccess = this._imodelProvider(imodelKey);
39
+ const provider = this.getHiliteSetProvider(imodelKey, imodelAccess);
40
+ let hiliteSet = this._cache.get(imodelKey);
41
+ if (!hiliteSet) {
42
+ const selectables = this._selectionStorage.getSelection({ imodelKey });
43
+ hiliteSet = (0, rxjs_1.from)(provider.getHiliteSet({ selectables })).pipe((0, rxjs_1.shareReplay)({ refCount: true }));
44
+ this._cache.set(imodelKey, hiliteSet);
45
+ }
46
+ return (0, rxjs_for_await_1.eachValueFrom)(hiliteSet);
47
+ }
48
+ dispose() {
49
+ this._removeListener();
50
+ this._hiliteSetProviders = new Map();
51
+ this._cache = new Map();
52
+ }
53
+ getHiliteSetProvider(imodelKey, imodelAccess) {
54
+ let provider = this._hiliteSetProviders.get(imodelKey);
55
+ if (!provider) {
56
+ provider = (0, HiliteSetProvider_1.createHiliteSetProvider)({ imodelAccess });
57
+ this._hiliteSetProviders.set(imodelKey, provider);
58
+ }
59
+ return provider;
60
+ }
61
+ }
62
+ //# sourceMappingURL=CachingHiliteSetProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CachingHiliteSetProvider.js","sourceRoot":"","sources":["../../../src/unified-selection/CachingHiliteSetProvider.ts"],"names":[],"mappings":";AAAA;;;gGAGgG;;;AAEhG,+BAAqD;AACrD,mDAA+C;AAE/C,2DAA4F;AAE5F,yDAA2F;AA4B3F;;;;GAIG;AACH,SAAgB,8BAA8B,CAAC,KAAoC;IACjF,OAAO,IAAI,4BAA4B,CAAC,KAAK,CAAC,CAAC;AACjD,CAAC;AAFD,wEAEC;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,CAA+D;IAEtF,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,sDAAmC,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,OAAO;QACZ,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;IAEO,oBAAoB,CAAC,SAAiB,EAAE,YAAmD;QACjG,IAAI,QAAQ,GAAG,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACvD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,QAAQ,GAAG,IAAA,2CAAuB,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 { from, Observable, shareReplay } from \"rxjs\";\nimport { eachValueFrom } from \"rxjs-for-await\";\nimport { ECSchemaProvider, ECSqlQueryExecutor } from \"@itwin/presentation-shared\";\nimport { createHiliteSetProvider, HiliteSet, HiliteSetProvider } from \"./HiliteSetProvider\";\nimport { StorageSelectionChangeEventArgs } from \"./SelectionChangeEvent\";\nimport { IMODEL_CLOSE_SELECTION_CLEAR_SOURCE, SelectionStorage } from \"./SelectionStorage\";\n\n/**\n * Props for creating a `CachingHiliteSetProvider` instance.\n * @internal Not exported through barrel, but used in public API as an argument. May be supplemented with optional attributes any time.\n */\nexport interface CachingHiliteSetProviderProps {\n selectionStorage: SelectionStorage;\n imodelProvider: (imodelKey: string) => ECSchemaProvider & ECSqlQueryExecutor;\n}\n\n/**\n * Defines return value of `createCachingHiliteSetProvider`.\n *\n * @beta 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 */\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 /** Disposes the cache. */\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 * @beta\n */\nexport function createCachingHiliteSetProvider(props: CachingHiliteSetProviderProps): CachingHiliteSetProvider {\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) => ECSchemaProvider & 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 dispose(): void {\n this._removeListener();\n this._hiliteSetProviders = new Map();\n this._cache = new Map();\n }\n\n private getHiliteSetProvider(imodelKey: string, imodelAccess: ECSchemaProvider & 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"]}
@@ -0,0 +1,90 @@
1
+ import { ECSchemaProvider, ECSqlQueryExecutor } from "@itwin/presentation-shared";
2
+ import { CachingHiliteSetProvider } from "./CachingHiliteSetProvider";
3
+ import { ComputeSelectionProps } from "./SelectionScope";
4
+ import { SelectionStorage } from "./SelectionStorage";
5
+ import { CoreIModelHiliteSet, CoreIModelSelectionSet } from "./types/IModel";
6
+ /**
7
+ * Props for `enableUnifiedSelectionSyncWithIModel`.
8
+ * @internal Not exported through barrel, but used in public API as an argument. May be supplemented with optional attributes any time.
9
+ */
10
+ export interface EnableUnifiedSelectionSyncWithIModelProps {
11
+ /**
12
+ * Provides access to different iModel's features: query executing, metadata access, selection and hilite sets.
13
+ * It's recommended to use `@itwin/presentation-core-interop` to create `ECSqlQueryExecutor` and `ECSchemaProvider` from
14
+ * [IModelConnection](https://www.itwinjs.org/reference/core-frontend/imodelconnection/imodelconnection/) and map its `key`,
15
+ * `hilited` and `selectionSet` attributes like this:
16
+ *
17
+ * ```ts
18
+ * import { createECSqlQueryExecutor, createECSchemaProvider } from "@itwin/presentation-core-interop";
19
+ * import { IModelConnection } from "@itwin/core-frontend";
20
+ *
21
+ * const imodel: IModelConnection = ...
22
+ * const imodelAccess = {
23
+ * ...createECSqlQueryExecutor(imodel),
24
+ * ...createECSchemaProvider(MyAppFrontend.getSchemaContext(imodel)),
25
+ * key: imodel.key,
26
+ * hiliteSet: imodel.hilited,
27
+ * selectionSet: imodel.selectionSet,
28
+ * };
29
+ * ```.
30
+ */
31
+ imodelAccess: ECSqlQueryExecutor & ECSchemaProvider & {
32
+ /** Key of the iModel. Generally taken from `IModelConnection.key`. */
33
+ readonly key: string;
34
+ /** The set of currently hilited elements taken from `IModelConnection.hilited`. */
35
+ readonly hiliteSet: CoreIModelHiliteSet;
36
+ /** The set of currently selected elements taken from `IModelConnection.selectionSet`. */
37
+ readonly selectionSet: CoreIModelSelectionSet;
38
+ };
39
+ /** Selection storage to synchronize IModel's tool selection with. */
40
+ selectionStorage: SelectionStorage;
41
+ /** Active scope provider. */
42
+ activeScopeProvider: () => ComputeSelectionProps["scope"];
43
+ /**
44
+ * A caching hilite set provider used to retrieve hilite sets for an iModel. If not provided, a new `CachingHiliteSetProvider`
45
+ * will be created for the given iModel using the provided `imodelAccess`.
46
+ * If the consuming application already has a `CachingHiliteSetProvider` defined, it should be provided instead
47
+ * to reuse the cache and avoid creating new providers for each iModel.
48
+ */
49
+ cachingHiliteSetProvider?: CachingHiliteSetProvider;
50
+ }
51
+ /**
52
+ * Enables synchronization between iModel selection and unified selection.
53
+ * @returns function for disposing the synchronization.
54
+ * @beta
55
+ */
56
+ export declare function enableUnifiedSelectionSyncWithIModel(props: EnableUnifiedSelectionSyncWithIModelProps): () => void;
57
+ /**
58
+ * A handler that syncs selection between unified selection storage
59
+ * (`SelectionStorage`) and an iModel (`iModel.selectionSet`, `iModel.hilited`).
60
+ * @internal
61
+ */
62
+ export declare class IModelSelectionHandler {
63
+ private _selectionSourceName;
64
+ private _imodelAccess;
65
+ private _selectionStorage;
66
+ private _hiliteSetProvider;
67
+ private _cachingHiliteSetProvider;
68
+ private _activeScopeProvider;
69
+ private _isSuspended;
70
+ private _cancelOngoingChanges;
71
+ private _unifiedSelectionListenerDisposeFunc;
72
+ private _imodelListenerDisposeFunc;
73
+ private _hasCustomCachingHiliteSetProvider;
74
+ constructor(props: EnableUnifiedSelectionSyncWithIModelProps);
75
+ dispose(): void;
76
+ /** Temporarily suspends tool selection synchronization until the returned `IDisposable` is disposed. */
77
+ suspendIModelToolSelectionSync(): {
78
+ dispose: () => boolean;
79
+ };
80
+ private handleUnifiedSelectionChange;
81
+ private onUnifiedSelectionChanged;
82
+ private applyCurrentHiliteSet;
83
+ private addHiliteSet;
84
+ private removeHiliteSet;
85
+ private onIModelSelectionChanged;
86
+ private handleIModelSelectionChange;
87
+ private getSelectionSetChangeIds;
88
+ private idArgToIds;
89
+ }
90
+ //# sourceMappingURL=EnableUnifiedSelectionSyncWithIModel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EnableUnifiedSelectionSyncWithIModel.d.ts","sourceRoot":"","sources":["../../../src/unified-selection/EnableUnifiedSelectionSyncWithIModel.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAClF,OAAO,EAAE,wBAAwB,EAAkC,MAAM,4BAA4B,CAAC;AAItG,OAAO,EAAoB,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAC3E,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAA0D,MAAM,gBAAgB,CAAC;AAErI;;;GAGG;AACH,MAAM,WAAW,yCAAyC;IACxD;;;;;;;;;;;;;;;;;;;OAmBG;IACH,YAAY,EAAE,kBAAkB,GAC9B,gBAAgB,GAAG;QACjB,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;;;;;OAKG;IACH,wBAAwB,CAAC,EAAE,wBAAwB,CAAC;CACrD;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,CAA2B;IAC5D,OAAO,CAAC,oBAAoB,CAAuC;IAEnE,OAAO,CAAC,YAAY,CAAU;IAC9B,OAAO,CAAC,qBAAqB,CAAuB;IACpD,OAAO,CAAC,oCAAoC,CAAa;IACzD,OAAO,CAAC,0BAA0B,CAAa;IAC/C,OAAO,CAAC,kCAAkC,CAAU;gBAEjC,KAAK,EAAE,yCAAyC;IAuB5D,OAAO;IASd,wGAAwG;IACjG,8BAA8B;;;IAQrC,OAAO,CAAC,4BAA4B;IA6BpC,OAAO,CAAC,yBAAyB,CAU/B;IAEF,OAAO,CAAC,qBAAqB;IAmB7B,OAAO,CAAC,YAAY;IAepB,OAAO,CAAC,eAAe;IAevB,OAAO,CAAC,wBAAwB,CAa9B;YAEY,2BAA2B;IAiBzC,OAAO,CAAC,wBAAwB;IAYhC,OAAO,CAAC,UAAU;CASnB"}