@vcmap/ui 6.3.12 → 6.3.13

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 (74) hide show
  1. package/build/build.js +5 -0
  2. package/build/staging/Dockerfile +2 -0
  3. package/config/base.config.json +207 -404
  4. package/config/clipping.config.json +16 -80
  5. package/config/cluster.config.json +2 -2
  6. package/config/components-show-case.config.json +1 -1
  7. package/config/concepts-show-case.config.json +1 -1
  8. package/config/dev/geojson.config.json +491 -0
  9. package/config/{i3s.config.json → dev/i3s.config.json} +78 -150
  10. package/config/{mapbox.config.json → dev/mapbox.config.json} +24 -58
  11. package/config/dev/vector-tile.config.json +196 -0
  12. package/config/{wms-layers.config.json → dev/wms.config.json} +22 -39
  13. package/config/dev.config.json +91 -887
  14. package/config/geofence.config.json +2 -4
  15. package/config/graph-feature-info.config.json +84 -0
  16. package/config/guided-tour.config.json +2 -2
  17. package/config/hello-world.config.json +1 -1
  18. package/config/projects.config.json +19 -20
  19. package/config/splashscreen.config.json +1 -1
  20. package/config/theming.config.json +1 -1
  21. package/config/www/city-planning.config.json +215 -0
  22. package/config/www/climate-environment.config.json +1244 -0
  23. package/config/www/iot-sensors.config.json +440 -0
  24. package/config/www/soest.config.json +632 -0
  25. package/config/www.config.json +1352 -1722
  26. package/dist/.htaccess +5 -0
  27. package/dist/assets/{cesium-230199a8.js → cesium-d2fefdc2.js} +20646 -20062
  28. package/dist/assets/cesium.js +1 -1
  29. package/dist/assets/{core-b3cc239c.js → core-be181847.js} +1125 -1125
  30. package/dist/assets/core-workers/panoramaImageWorker.js +1 -1
  31. package/dist/assets/core.js +1 -1
  32. package/dist/assets/ol.js +1 -1
  33. package/dist/assets/ui-8f8426e4.css +1 -0
  34. package/dist/assets/{ui-aaaf46c0.js → ui-8f8426e4.js} +13218 -12512
  35. package/dist/assets/ui.js +1 -1
  36. package/dist/assets/vue.js +1 -1
  37. package/dist/assets/{vuetify-a9ccbd51.js → vuetify-8df23ea4.js} +1 -1
  38. package/dist/assets/vuetify.js +1 -1
  39. package/package.json +2 -2
  40. package/plugins/@vcmap-show-case/extent-example/src/ExtentExample.vue +16 -2
  41. package/plugins/@vcmap-show-case/icons-example/src/AllIconsComponent.vue +7 -5
  42. package/plugins/@vcmap-show-case/notifier-tester/src/NotifierTester.vue +5 -6
  43. package/plugins/@vcmap-show-case/project-selector/README.md +18 -7
  44. package/plugins/@vcmap-show-case/project-selector/src/ProjectSelectorComponent.vue +9 -0
  45. package/plugins/@vcmap-show-case/project-selector/src/index.js +87 -27
  46. package/plugins/@vcmap-show-case/simple-graph/src/SimpleGraphComponent.vue +10 -3
  47. package/plugins/@vcmap-show-case/simple-graph/src/index.js +10 -1
  48. package/plugins/@vcmap-show-case/switch-map-callback-example/README.md +1 -1
  49. package/plugins/package.json +2 -1
  50. package/src/application/VcsApp.vue +3 -7
  51. package/src/application/attributionsHelper.d.ts +27 -5
  52. package/src/application/attributionsHelper.js +116 -58
  53. package/src/components/lists/VcsGroupedList.vue +29 -1
  54. package/src/components/lists/VcsList.vue +35 -4
  55. package/src/components/lists/VcsList.vue.d.ts +2 -0
  56. package/src/components/lists/VcsTreeview.vue +63 -31
  57. package/src/components/lists/VcsTreeview.vue.d.ts +9 -0
  58. package/src/contentTree/LayerTree.vue +13 -2
  59. package/src/featureInfo/ClusterFeatureComponent.vue +1 -0
  60. package/src/manager/window/WindowComponent.vue +5 -1
  61. package/src/vcsUiApp.d.ts +19 -7
  62. package/src/vcsUiApp.js +17 -0
  63. package/config/aerowest.config.json +0 -386
  64. package/config/analysis.config.json +0 -17
  65. package/config/dynamic-layer.config.json +0 -33
  66. package/config/graphFeatureInfo.config.json +0 -141
  67. package/config/pano.config.json +0 -726
  68. package/config/solar.config.json +0 -66
  69. package/config/vectorTile.config.json +0 -112
  70. package/dist/assets/ui-aaaf46c0.css +0 -1
  71. /package/dist/assets/core-workers/{panoramaImageWorker.js-495a0b47.js → panoramaImageWorker.js-eecf04e1.js} +0 -0
  72. /package/dist/assets/{ol-2769767e.js → ol-3438e1c5.js} +0 -0
  73. /package/dist/assets/{vue-c9f45cfc.js → vue-dd509a16.js} +0 -0
  74. /package/dist/assets/{vuetify-a9ccbd51.css → vuetify-8df23ea4.css} +0 -0
@@ -1,4 +1,4 @@
1
- import { reactive } from 'vue';
1
+ import { reactive, watch } from 'vue';
2
2
  import { ObliqueMap } from '@vcmap/core';
3
3
 
4
4
  /**
@@ -16,6 +16,14 @@ import { ObliqueMap } from '@vcmap/core';
16
16
  * @property {AttributionOptions|Array<AttributionOptions>} attributions - attributions of a map, layer or oblique collection
17
17
  */
18
18
 
19
+ /**
20
+ * @typedef {Object} Attributions
21
+ * @property {import("vue").UnwrapRef<Array<AttributionEntry>>} entries - reactive array of attribution entries
22
+ * @property {function(import("@vcmap/core").VcsMap, string|import('../pluginHelper.js').vcsAppSymbol): function():void} registerMap - function to register a map and its layer collection for an owner, returns a function to unregister it
23
+ * @property {function(string|import('../pluginHelper.js').vcsAppSymbol):void} removeOwner - unregister all maps registered by an owner
24
+ * @property {function():void} destroy - function to clear all listeners and clean up attributions
25
+ */
26
+
19
27
  /**
20
28
  * merges attribution entries of same providers
21
29
  * @param {Array<AttributionEntry>} entries
@@ -64,17 +72,17 @@ export function mergeAttributions(entries) {
64
72
  * Listens to state changes of maps, layers and oblique collections and synchronizes the entries array correspondingly.
65
73
  * Returns a destroy function to clear listeners.
66
74
  * @param {import("../vcsUiApp.js").default} app
67
- * @returns {{entries: import("vue").UnwrapRef<Array<AttributionEntry>>, destroy: function():void}}
75
+ * @returns {Attributions}
68
76
  */
69
77
  export function getAttributions(app) {
70
78
  /**
71
79
  * @type {import("vue").UnwrapRef<Array<AttributionEntry>>}
72
80
  */
73
81
  const entries = reactive([]);
74
- /**
75
- * @type {function():void}
76
- */
77
- let obliqueListener = () => {};
82
+ /** @type {Map<import("@vcmap/core").VcsMap, { collection: import("@vcmap/core").LayerCollection, registrations: Map<function():void, string|import('../pluginHelper.js').vcsAppSymbol>, removeListeners: Array<function():void> }>} */
83
+ const registeredMaps = new Map();
84
+ /** @type {Map<import("@vcmap/core").ObliqueMap, function():void>} */
85
+ const obliqueListeners = new Map();
78
86
 
79
87
  /**
80
88
  * Adds an entry for an object using a combination of the object's className and name as key.
@@ -99,73 +107,123 @@ export function getAttributions(app) {
99
107
  }
100
108
  }
101
109
 
102
- /**
103
- * @param {import("@vcmap/core").VcsMap|import("@vcmap/core").Layer|import("@vcmap/core").ObliqueCollection} object
104
- */
105
- function removeAttributions(object) {
106
- const idx = entries.findIndex(
107
- (e) => e.key === `${object.className}_${object.name}`,
108
- );
109
- if (idx >= 0) {
110
- entries.splice(idx, 1);
110
+ function updateAttributions() {
111
+ entries.splice(0);
112
+ /** @type {Map<import("@vcmap/core").VcsMap, import("@vcmap/core").LayerCollection>} */
113
+ const visibleMaps = new Map();
114
+ if (app.maps.activeMap) {
115
+ visibleMaps.set(app.maps.activeMap, app.maps.activeMap.layerCollection);
111
116
  }
117
+ if (app.overviewMap.active) {
118
+ const overviewMap = app.overviewMap.map;
119
+ visibleMaps.set(overviewMap, overviewMap.layerCollection);
120
+ }
121
+ registeredMaps.forEach(({ collection }, map) => {
122
+ if (map.active) {
123
+ visibleMaps.set(map, collection);
124
+ }
125
+ });
126
+ obliqueListeners.forEach((removeListener, map) => {
127
+ if (!visibleMaps.has(map)) {
128
+ removeListener();
129
+ obliqueListeners.delete(map);
130
+ }
131
+ });
132
+ visibleMaps.forEach((collection, map) => {
133
+ if (map.active) {
134
+ addAttributions(map);
135
+ }
136
+ [...collection].forEach((layer) => {
137
+ if (layer.active && layer.isSupported(map)) {
138
+ addAttributions(layer);
139
+ }
140
+ });
141
+ if (map instanceof ObliqueMap) {
142
+ if (map.collection) {
143
+ addAttributions(map.collection);
144
+ }
145
+ if (!obliqueListeners.has(map)) {
146
+ obliqueListeners.set(
147
+ map,
148
+ map.collectionChanged.addEventListener(updateAttributions),
149
+ );
150
+ }
151
+ }
152
+ });
112
153
  }
113
154
 
155
+ const listeners = [
156
+ app.maps.mapActivated.addEventListener(updateAttributions),
157
+ app.layers.stateChanged.addEventListener(updateAttributions),
158
+ app.layers.added.addEventListener(updateAttributions),
159
+ app.layers.removed.addEventListener(updateAttributions),
160
+ app.maps.removed.addEventListener(updateAttributions),
161
+ watch(app.overviewMap.currentState, updateAttributions),
162
+ ];
163
+
164
+ updateAttributions();
165
+
114
166
  /**
115
- * adds or removes a AttributionEntry for layers or maps
116
- * @param {import("@vcmap/core").VcsMap|import("@vcmap/core").Layer} object
167
+ * @param {import("@vcmap/core").VcsMap} map
168
+ * @param {string|import('../pluginHelper.js').vcsAppSymbol} owner
169
+ * @returns {function():void}
117
170
  */
118
- function syncAttributions(object) {
119
- if (object?.properties?.attributions === undefined) {
120
- return;
121
- }
122
- if (object.active) {
123
- addAttributions(object);
124
- } else {
125
- removeAttributions(object);
171
+ function registerMap(map, owner) {
172
+ if (!registeredMaps.has(map)) {
173
+ registeredMaps.set(map, {
174
+ collection: map.layerCollection,
175
+ registrations: new Map(),
176
+ removeListeners: [
177
+ map.stateChanged.addEventListener(updateAttributions),
178
+ map.layerCollection.added.addEventListener(updateAttributions),
179
+ map.layerCollection.removed.addEventListener(updateAttributions),
180
+ ],
181
+ });
126
182
  }
183
+ const unregister = () => {
184
+ const current = registeredMaps.get(map);
185
+ if (!current?.registrations.delete(unregister)) {
186
+ return;
187
+ }
188
+ if (current.registrations.size === 0) {
189
+ current.removeListeners.forEach((removeListener) => {
190
+ removeListener();
191
+ });
192
+ registeredMaps.delete(map);
193
+ }
194
+ updateAttributions();
195
+ };
196
+ registeredMaps.get(map).registrations.set(unregister, owner);
197
+ updateAttributions();
198
+ return unregister;
127
199
  }
128
200
 
129
201
  /**
130
- *
131
- * @param {import("@vcmap/core").VcsMap} map
202
+ * @param {string|import('../pluginHelper.js').vcsAppSymbol} owner
132
203
  */
133
- function initAttributions(map) {
134
- if (!map) {
135
- return;
136
- }
137
- obliqueListener();
138
- entries.splice(0);
139
- syncAttributions(map);
140
- [...map.layerCollection].forEach((layer) => {
141
- if (layer.isSupported(map)) {
142
- syncAttributions(layer);
143
- }
204
+ function removeOwner(owner) {
205
+ registeredMaps.forEach(({ registrations }) => {
206
+ registrations.forEach((registrationOwner, unregister) => {
207
+ if (registrationOwner === owner) {
208
+ unregister();
209
+ }
210
+ });
144
211
  });
145
- if (map instanceof ObliqueMap) {
146
- addAttributions(map.collection);
147
- obliqueListener = map.collectionChanged.addEventListener(
148
- (obliqueCollection) => {
149
- [...app.obliqueCollections].forEach(removeAttributions);
150
- addAttributions(obliqueCollection);
151
- },
152
- );
153
- }
154
212
  }
155
213
 
156
- const listeners = [
157
- app.maps.mapActivated.addEventListener(initAttributions),
158
- app.layers.stateChanged.addEventListener(syncAttributions),
159
- app.layers.removed.addEventListener(removeAttributions),
160
- app.maps.removed.addEventListener(removeAttributions),
161
- ];
162
-
163
- initAttributions(app.maps.activeMap);
164
-
165
214
  const destroy = () => {
166
215
  listeners.forEach((cb) => cb());
167
- obliqueListener();
216
+ obliqueListeners.forEach((removeListener) => {
217
+ removeListener();
218
+ });
219
+ obliqueListeners.clear();
220
+ registeredMaps.forEach(({ removeListeners }) => {
221
+ removeListeners.forEach((removeListener) => {
222
+ removeListener();
223
+ });
224
+ });
225
+ registeredMaps.clear();
168
226
  };
169
227
 
170
- return { entries, destroy };
228
+ return { entries, registerMap, removeOwner, destroy };
171
229
  }
@@ -35,6 +35,7 @@
35
35
  * @vue-prop {boolean} [singleSelect=false]
36
36
  * @vue-prop {Array<import("./VcsListItemComponent.vue").VcsListItem>} [modelValue=[]] - the initial items to be selected.
37
37
  * @vue-prop {boolean} [searchable=false] - if this list can have its items searched.
38
+ * @vue-prop {boolean} [stickySearchbar=false] - Keeps the searchbar at the top of the scroll container.
38
39
  * @vue-prop {function(import("./VcsListItemComponent.vue").VcsListItem, string):boolean} [customFilter] - a function to customize filtering when searching.
39
40
  * @vue-prop {string} [searchbarPlaceholder] - placeholder to render inside the search field
40
41
  */
@@ -73,6 +74,10 @@
73
74
  type: Boolean,
74
75
  default: false,
75
76
  },
77
+ stickySearchbar: {
78
+ type: Boolean,
79
+ default: false,
80
+ },
76
81
  searchbarPlaceholder: {
77
82
  type: String,
78
83
  default: undefined,
@@ -142,7 +147,10 @@
142
147
  </script>
143
148
 
144
149
  <template>
145
- <div class="vcs-grouped-list">
150
+ <div
151
+ class="vcs-grouped-list"
152
+ :class="{ 'sticky-searchbar': stickySearchbar && searchable }"
153
+ >
146
154
  <VcsTreeviewSearchbar
147
155
  v-if="searchable"
148
156
  :placeholder="searchbarPlaceholder"
@@ -178,6 +186,26 @@
178
186
  </template>
179
187
 
180
188
  <style scoped lang="scss">
189
+ .vcs-grouped-list {
190
+ display: block;
191
+ flex: 1 1 auto;
192
+ min-height: 0;
193
+ overflow: auto;
194
+ scrollbar-gutter: stable;
195
+ }
196
+
197
+ .vcs-grouped-list.sticky-searchbar {
198
+ --searchbar-height: calc(var(--v-vcs-font-size) * 2 + 18px);
199
+ margin-top: var(--searchbar-height);
200
+
201
+ > .vcs-treeview-searchbar {
202
+ width: 100%;
203
+ position: absolute !important;
204
+ margin-top: calc(var(--searchbar-height) * -1);
205
+ z-index: 2;
206
+ }
207
+ }
208
+
181
209
  .panels .vcs-expansion-panel:not(:last-child) {
182
210
  border-bottom: 1px solid rgb(var(--v-theme-base-lighten-2));
183
211
  }
@@ -1,5 +1,10 @@
1
1
  <template>
2
- <div class="d-contents vcs-list">
2
+ <div
3
+ class="vcs-list"
4
+ :class="{
5
+ 'sticky-searchbar': stickySearchbar && searchable,
6
+ }"
7
+ >
3
8
  <vcs-treeview-searchbar
4
9
  v-if="searchable"
5
10
  :placeholder="searchbarPlaceholder"
@@ -113,6 +118,7 @@
113
118
  * @vue-prop {boolean} [singleSelect=false]
114
119
  * @vue-prop {Array<import("./VcsListItemComponent.vue").VcsListItem>} [modelValue=[]] - the initial items to be selected.
115
120
  * @vue-prop {boolean} [searchable=false] - if this list can have its items searched.
121
+ * @vue-prop {boolean} [stickySearchbar=false] - Keeps the searchbar at the top of the scroll container.
116
122
  * @vue-prop {function(import("./VcsListItemComponent.vue").VcsListItem, string):boolean} [customFilter] - a function to customize filtering when searching.
117
123
  * @vue-prop {string} [searchbarPlaceholder] - placeholder to render inside the search field
118
124
  * @vue-prop {boolean} [showTitle=true] - show the title component
@@ -162,6 +168,10 @@
162
168
  type: Boolean,
163
169
  default: false,
164
170
  },
171
+ stickySearchbar: {
172
+ type: Boolean,
173
+ default: false,
174
+ },
165
175
  customFilter: {
166
176
  type: Function,
167
177
  default: undefined,
@@ -282,6 +292,30 @@
282
292
  </script>
283
293
 
284
294
  <style lang="scss" scoped>
295
+ .vcs-list {
296
+ display: block;
297
+ flex: 1 1 auto;
298
+ min-height: 0;
299
+ overflow: auto;
300
+ scrollbar-gutter: stable;
301
+ }
302
+
303
+ .vcs-list > .v-list {
304
+ overflow: visible;
305
+ }
306
+
307
+ .vcs-list.sticky-searchbar {
308
+ --searchbar-height: calc(var(--v-vcs-font-size) * 2 + 18px);
309
+ margin-top: var(--searchbar-height);
310
+
311
+ > .vcs-treeview-searchbar {
312
+ width: 100%;
313
+ position: absolute !important;
314
+ margin-top: calc(var(--searchbar-height) * -1);
315
+ z-index: 2;
316
+ }
317
+ }
318
+
285
319
  :deep(.v-list) {
286
320
  .v-list-item__lighten_even:nth-child(even) {
287
321
  background-color: rgb(var(--v-theme-base-lighten-4));
@@ -339,7 +373,4 @@
339
373
  }
340
374
  }
341
375
  }
342
- .d-contents {
343
- display: contents;
344
- }
345
376
  </style>
@@ -7,6 +7,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<{}
7
7
  items: unknown[];
8
8
  selectable: boolean;
9
9
  actions: unknown[];
10
+ stickySearchbar: boolean;
10
11
  singleSelect: boolean;
11
12
  searchable: boolean;
12
13
  showTitle: boolean;
@@ -24,6 +25,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<{}
24
25
  readonly items?: unknown[] | undefined;
25
26
  readonly selectable?: boolean | undefined;
26
27
  readonly actions?: unknown[] | undefined;
28
+ readonly stickySearchbar?: boolean | undefined;
27
29
  readonly singleSelect?: boolean | undefined;
28
30
  readonly searchable?: boolean | undefined;
29
31
  readonly showTitle?: boolean | undefined;
@@ -1,5 +1,8 @@
1
1
  <template>
2
- <div class="vcs-treeview">
2
+ <div
3
+ class="vcs-treeview"
4
+ :class="{ 'sticky-searchbar': stickySearchbar && showSearchbar }"
5
+ >
3
6
  <VcsTreeviewSearchbar
4
7
  v-if="showSearchbar"
5
8
  :placeholder="searchbarPlaceholder"
@@ -12,37 +15,39 @@
12
15
  <slot name="search-append" v-bind="searchAppend" />
13
16
  </template>
14
17
  </VcsTreeviewSearchbar>
15
- <div
16
- v-for="(item, index) in items"
17
- :key="item.name"
18
- class="vcs-treeitem"
19
- :class="{ 'mobile-spacing': xs }"
20
- >
21
- <VcsTreeNode
22
- class="root-node"
23
- :class="{
24
- 'vcs-draggable-item': isDraggable,
25
- }"
26
- :item="item"
27
- :path="[index]"
28
- :search="localSearchValue"
29
- v-model:opened="localOpenedItems"
30
- :custom-filter="customFilter"
31
- :open-on-click="openOnClick"
32
- :item-children="itemChildren"
33
- :draggable="isDraggable"
34
- @mousedown.shift="$event.preventDefault()"
35
- @dragstart="dragStart"
36
- @dragover="dragOver"
37
- @dragend="dragEnd"
38
- @drop="drop"
39
- @item-toggled="itemToggled"
40
- @click="itemClicked"
18
+ <div class="treeview-items">
19
+ <div
20
+ v-for="(item, index) in items"
21
+ :key="item.name"
22
+ class="vcs-treeitem"
23
+ :class="{ 'mobile-spacing': xs }"
41
24
  >
42
- <template v-for="slot of forwardSlots" #[slot]="scope">
43
- <slot :name="slot" v-bind="scope ?? {}" />
44
- </template>
45
- </VcsTreeNode>
25
+ <VcsTreeNode
26
+ class="root-node"
27
+ :class="{
28
+ 'vcs-draggable-item': isDraggable,
29
+ }"
30
+ :item="item"
31
+ :path="[index]"
32
+ :search="localSearchValue"
33
+ v-model:opened="localOpenedItems"
34
+ :custom-filter="customFilter"
35
+ :open-on-click="openOnClick"
36
+ :item-children="itemChildren"
37
+ :draggable="isDraggable"
38
+ @mousedown.shift="$event.preventDefault()"
39
+ @dragstart="dragStart"
40
+ @dragover="dragOver"
41
+ @dragend="dragEnd"
42
+ @drop="drop"
43
+ @item-toggled="itemToggled"
44
+ @click="itemClicked"
45
+ >
46
+ <template v-for="slot of forwardSlots" #[slot]="scope">
47
+ <slot :name="slot" v-bind="scope ?? {}" />
48
+ </template>
49
+ </VcsTreeNode>
50
+ </div>
46
51
  </div>
47
52
  </div>
48
53
  </template>
@@ -73,6 +78,7 @@
73
78
  * @vue-prop {boolean} [openOnClick=false] - Whether to open items on title click.
74
79
  * @vue-prop {string} [search=''] - The value used to filter the items.
75
80
  * @vue-prop {boolean} [showSearchbar=false] - Whether there is a searchbar for this treeview.
81
+ * @vue-prop {boolean} [stickySearchbar=false] - Keeps the searchbar at the top of the scroll container.
76
82
  * @vue-prop {string} [searchbarPlaceholder] - Placeholder text for the searchbar, will be translated.
77
83
  * @vue-prop {function(arg0: import("./VcsTreeNode.vue").VcsTreeNodeItem, arg1: string|undefined):boolean} [customFilter] - a function to customize filtering when searching.
78
84
  * @vue-prop {import("./dragHelper.js").DropTargetZonesFunction} [dropTargetZones] - a function to define allowed drop target zones per item.
@@ -116,6 +122,10 @@
116
122
  type: Boolean,
117
123
  default: false,
118
124
  },
125
+ stickySearchbar: {
126
+ type: Boolean,
127
+ default: false,
128
+ },
119
129
  searchbarPlaceholder: {
120
130
  type: String,
121
131
  default: undefined,
@@ -203,6 +213,28 @@
203
213
  </script>
204
214
 
205
215
  <style lang="scss" scoped>
216
+ .vcs-treeview {
217
+ display: block;
218
+ flex: 1 1 auto;
219
+ min-height: 0;
220
+ overflow: auto;
221
+ scrollbar-gutter: stable;
222
+ }
223
+
224
+ .treeview-items {
225
+ display: block;
226
+ }
227
+ .vcs-treeview.sticky-searchbar {
228
+ --searchbar-height: calc(var(--v-vcs-font-size) * 2 + 18px);
229
+ margin-top: var(--searchbar-height);
230
+
231
+ > .vcs-treeview-searchbar {
232
+ width: 100%;
233
+ position: absolute !important;
234
+ margin-top: calc(var(--searchbar-height) * -1);
235
+ z-index: 2;
236
+ }
237
+ }
206
238
  // Hide node component when not rendered (e.g. filtered by search)
207
239
  .vcs-treeitem:not(:has(.vcs-tree-node)) {
208
240
  display: none;
@@ -31,6 +31,10 @@ declare const _default: import("vue").DefineComponent<{
31
31
  type: BooleanConstructor;
32
32
  default: boolean;
33
33
  };
34
+ stickySearchbar: {
35
+ type: BooleanConstructor;
36
+ default: boolean;
37
+ };
34
38
  searchbarPlaceholder: {
35
39
  type: StringConstructor;
36
40
  default: undefined;
@@ -92,6 +96,10 @@ declare const _default: import("vue").DefineComponent<{
92
96
  type: BooleanConstructor;
93
97
  default: boolean;
94
98
  };
99
+ stickySearchbar: {
100
+ type: BooleanConstructor;
101
+ default: boolean;
102
+ };
95
103
  searchbarPlaceholder: {
96
104
  type: StringConstructor;
97
105
  default: undefined;
@@ -122,6 +130,7 @@ declare const _default: import("vue").DefineComponent<{
122
130
  customFilter: Function;
123
131
  openAll: boolean;
124
132
  showSearchbar: boolean;
133
+ stickySearchbar: boolean;
125
134
  searchbarPlaceholder: string;
126
135
  dropTargetZones: Function;
127
136
  }, {}>;
@@ -3,9 +3,10 @@
3
3
  <VcsTreeview
4
4
  v-if="tree && tree.length"
5
5
  :items="tree"
6
- :show-searchbar="true"
7
- v-model:opened="open"
6
+ show-searchbar
7
+ sticky-searchbar
8
8
  open-on-click
9
+ v-model:opened="open"
9
10
  :searchbar-placeholder="'content.search.placeholder'"
10
11
  item-children="visibleChildren"
11
12
  >
@@ -103,3 +104,13 @@
103
104
  },
104
105
  };
105
106
  </script>
107
+
108
+ <style lang="scss" scoped>
109
+ .layer-tree {
110
+ display: flex;
111
+ flex-direction: column;
112
+ flex: 1 1 auto;
113
+ min-height: 0;
114
+ overflow: hidden;
115
+ }
116
+ </style>
@@ -83,6 +83,7 @@
83
83
  v-model="selected"
84
84
  selectable
85
85
  single-select
86
+ sticky-searchbar
86
87
  searchable
87
88
  open-all
88
89
  />
@@ -28,7 +28,7 @@
28
28
  </div>
29
29
  <v-divider v-if="!windowState.hideHeader" />
30
30
  <div
31
- class="overflow-x-hidden overflow-y-auto mb-1 d-flex flex-grow-1 flex-column"
31
+ class="window-content overflow-x-hidden overflow-y-auto mb-1 d-flex flex-grow-1 flex-column"
32
32
  :class="{
33
33
  rounded: !isDocked,
34
34
  }"
@@ -169,6 +169,10 @@
169
169
  </script>
170
170
 
171
171
  <style scoped>
172
+ .window-content > :deep(:has(> .sticky-searchbar:only-child)) {
173
+ display: contents;
174
+ }
175
+
172
176
  .marginToTop {
173
177
  margin-top: 2px;
174
178
  }
package/src/vcsUiApp.d.ts CHANGED
@@ -168,6 +168,11 @@ declare class VcsUiApp extends VcsApp {
168
168
  * @private
169
169
  */
170
170
  private _overviewMap;
171
+ /**
172
+ * @type {import("./application/attributionsHelper.js").Attributions}
173
+ * @private
174
+ */
175
+ private _attributions;
171
176
  /**
172
177
  * @type {CategoryManager}
173
178
  * @private
@@ -240,6 +245,10 @@ declare class VcsUiApp extends VcsApp {
240
245
  * @type {OverviewMap}
241
246
  */
242
247
  get overviewMap(): OverviewMap;
248
+ /**
249
+ * @type {import("./application/attributionsHelper.js").Attributions}
250
+ */
251
+ get attributions(): import("./application/attributionsHelper.js").Attributions;
243
252
  /**
244
253
  * @type {I18nCollection}
245
254
  */
@@ -256,10 +265,7 @@ declare class VcsUiApp extends VcsApp {
256
265
  defaults: import("vue").Ref<import("vuetify").DefaultsInstance>;
257
266
  display: import("vuetify").DisplayInstance;
258
267
  theme: import("vuetify").ThemeInstance & {
259
- install: (app: import("vue").App<any>) => void; /**
260
- * @type {WindowManager}
261
- * @private
262
- */
268
+ install: (app: import("vue").App<any>) => void;
263
269
  };
264
270
  icons: {
265
271
  defaultSet: string;
@@ -270,6 +276,10 @@ declare class VcsUiApp extends VcsApp {
270
276
  isRtl: import("vue").Ref<boolean>;
271
277
  rtl: import("vue").Ref<Record<string, boolean>>;
272
278
  rtlClasses: import("vue").Ref<string>;
279
+ /**
280
+ * @type {WindowManager}
281
+ * @private
282
+ */
273
283
  name: string;
274
284
  messages: import("vue").Ref<import("vuetify").LocaleMessages>;
275
285
  current: import("vue").Ref<string>;
@@ -306,6 +316,10 @@ declare class VcsUiApp extends VcsApp {
306
316
  isAfterDay: (value: unknown, comparing: unknown) => boolean;
307
317
  isSameDay: (date: unknown, comparing: unknown) => boolean;
308
318
  isSameMonth: (date: unknown, comparing: unknown) => boolean;
319
+ /**
320
+ * @type {ContextMenuManager}
321
+ * @private
322
+ */
309
323
  isSameYear: (value: unknown, comparing: unknown) => boolean;
310
324
  isBefore: (date: unknown, comparing: unknown) => boolean;
311
325
  isEqual: (date: unknown, comparing: unknown) => boolean;
@@ -329,9 +343,7 @@ declare class VcsUiApp extends VcsApp {
329
343
  getPreviousMonth: (date: unknown) => unknown;
330
344
  getHours: (date: unknown) => number;
331
345
  setHours: (date: unknown, hours: number) => unknown;
332
- getMinutes: (date: unknown) => number; /**
333
- * @returns {PanelManager}
334
- */
346
+ getMinutes: (date: unknown) => number;
335
347
  setMinutes: (date: unknown, minutes: number) => unknown;
336
348
  };
337
349
  };