@vcmap/ui 5.0.0-rc.17 → 5.0.0-rc.18

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 (34) hide show
  1. package/config/www.config.json +748 -123
  2. package/dist/assets/{cesium.41de56.js → cesium.2f992f.js} +0 -0
  3. package/dist/assets/cesium.js +1 -1
  4. package/dist/assets/{core.af84e3.js → core.cb0408.js} +2 -2
  5. package/dist/assets/core.js +1 -1
  6. package/dist/assets/{index.5b773cad.js → index.bccdf969.js} +1 -1
  7. package/dist/assets/{ol.5c7490.js → ol.5e3fd0.js} +0 -0
  8. package/dist/assets/ol.js +1 -1
  9. package/dist/assets/ui.08c48f.css +1 -0
  10. package/dist/assets/{ui.dffe32.js → ui.08c48f.js} +997 -983
  11. package/dist/assets/ui.js +1 -1
  12. package/dist/assets/{vue.25da17.js → vue.228ead.js} +0 -0
  13. package/dist/assets/vue.js +2 -2
  14. package/dist/assets/{vuetify.e4ece7.css → vuetify.0b5039.css} +0 -0
  15. package/dist/assets/{vuetify.e4ece7.js → vuetify.0b5039.js} +1 -1
  16. package/dist/assets/vuetify.js +2 -2
  17. package/dist/index.html +1 -1
  18. package/package.json +1 -1
  19. package/plugins/buttonExamples/ButtonExamples.vue +18 -0
  20. package/plugins/package.json +1 -1
  21. package/plugins/test/index.js +3 -1
  22. package/plugins/test/toolbox-data.js +168 -111
  23. package/src/actions/actionHelper.js +3 -1
  24. package/src/application/VcsNavbar.vue +1 -1
  25. package/src/components/buttons/VcsButton.vue +14 -3
  26. package/src/components/lists/VcsActionList.vue +2 -0
  27. package/src/contentTree/layerContentTreeItem.js +2 -2
  28. package/src/featureInfo/BalloonComponent.vue +2 -2
  29. package/src/i18n/de.js +6 -2
  30. package/src/i18n/en.js +4 -0
  31. package/src/legend/legendHelper.js +6 -7
  32. package/src/legend/vcsLegend.vue +12 -3
  33. package/src/manager/toolbox/ToolboxManager.vue +1 -0
  34. package/dist/assets/ui.dffe32.css +0 -1
package/dist/assets/ui.js CHANGED
@@ -1 +1 @@
1
- export * from "./ui.dffe32.js";
1
+ export * from "./ui.08c48f.js";
File without changes
@@ -1,5 +1,5 @@
1
- export * from "./vue.25da17.js";
2
- import { default as f } from "./vue.25da17.js";
1
+ export * from "./vue.228ead.js";
2
+ import { default as f } from "./vue.228ead.js";
3
3
  export {
4
4
  f as default
5
5
  };
@@ -13,7 +13,7 @@ function loadCss(href) {
13
13
  elem.onerror = reject;
14
14
  document.head.appendChild(elem);
15
15
  });
16
- } await loadCss('./assets/vuetify.e4ece7.css');import v from "./vue.25da17.js";
16
+ } await loadCss('./assets/vuetify.0b5039.css');import v from "./vue.228ead.js";
17
17
  const Ne = v.extend().extend({
18
18
  name: "themeable",
19
19
  provide() {
@@ -1,5 +1,5 @@
1
- export * from "./vuetify.e4ece7.js";
2
- import { default as f } from "./vuetify.e4ece7.js";
1
+ export * from "./vuetify.0b5039.js";
2
+ import { default as f } from "./vuetify.0b5039.js";
3
3
  export {
4
4
  f as default
5
5
  };
package/dist/index.html CHANGED
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="utf-8" />
5
5
  <meta name="viewport" content="width=device-width,initial-scale=1.0" />
6
- <script type="module" crossorigin src="./assets/index.5b773cad.js"></script>
6
+ <script type="module" crossorigin src="./assets/index.bccdf969.js"></script>
7
7
  </head>
8
8
  <body style="height: 100vH;">
9
9
  <noscript>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vcmap/ui",
3
- "version": "5.0.0-rc.17",
3
+ "version": "5.0.0-rc.18",
4
4
  "author": "Virtual City Systems",
5
5
  "license": "MIT",
6
6
  "scripts": {
@@ -32,6 +32,18 @@
32
32
  <v-switch v-model="active" />
33
33
  </v-list-item-action>
34
34
  </v-list-item>
35
+ <v-divider />
36
+ <v-list-item>
37
+ <v-list-item-content>
38
+ <v-list-item-title class="font-weight-bold">
39
+ ACTIVE BACKGROUND
40
+ </v-list-item-title>
41
+ </v-list-item-content>
42
+ <v-list-item-action>
43
+ <v-switch v-model="background" />
44
+ </v-list-item-action>
45
+ </v-list-item>
46
+ <v-divider />
35
47
  <v-list-item>
36
48
  <v-list-item-content>
37
49
  <v-list-item-title class="font-weight-bold">
@@ -56,6 +68,7 @@
56
68
  <VcsButton
57
69
  @click="toggle"
58
70
  :active="active"
71
+ :background="background"
59
72
  color="primary"
60
73
  :disabled="disabled"
61
74
  :has-update="update"
@@ -74,6 +87,7 @@
74
87
  <VcsButton
75
88
  @click="toggle"
76
89
  :active="active"
90
+ :background="background"
77
91
  :disabled="disabled"
78
92
  :has-update="update"
79
93
  tooltip="SECONDARY BUTTON"
@@ -101,6 +115,7 @@
101
115
  @click="toggle"
102
116
  :active="active"
103
117
  :disabled="disabled"
118
+ :background="background"
104
119
  :has-update="update"
105
120
  :icon="loading ? '$vcsProgress' : '$vcs3d'"
106
121
  tooltip="ButtonClass large"
@@ -141,6 +156,7 @@
141
156
  <VcsButton
142
157
  @click="toggle"
143
158
  :active="active"
159
+ :background="background"
144
160
  :disabled="disabled"
145
161
  :icon="loading ? '$vcsProgress' : '$vcsColorSwatch'"
146
162
  tooltip="ACTION BUTTON"
@@ -205,12 +221,14 @@
205
221
  },
206
222
  setup() {
207
223
  const active = ref(false);
224
+ const background = ref(false);
208
225
  const disabled = ref(false);
209
226
  const update = ref(false);
210
227
  const loading = ref(false);
211
228
 
212
229
  return {
213
230
  active,
231
+ background,
214
232
  disabled,
215
233
  update,
216
234
  loading,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "dependencies": {
3
3
  "@vcmap/hello-world": "^1.0.7",
4
- "@vcmap/print": "^1.0.1"
4
+ "@vcmap/print": "^1.0.2"
5
5
  }
6
6
  }
@@ -3,7 +3,7 @@ import { Feature } from 'ol';
3
3
  import {
4
4
  ButtonLocation, createModalAction, createToggleAction, setStateToUrl, ToolboxType, WindowSlot,
5
5
  } from '@vcmap/ui';
6
- import { toolboxData } from './toolbox-data.js';
6
+ import { getToolboxData } from './toolbox-data.js';
7
7
  import editor from './editor.vue';
8
8
  import windowManagerExample from './windowManagerExample.vue';
9
9
  import AllIconsComponent from './allIconsComponent.vue';
@@ -162,6 +162,7 @@ export default async function () {
162
162
  '@vcmap/test',
163
163
  ButtonLocation.TOOL,
164
164
  );
165
+ const { toolboxData, destroy: destroyToolboxData } = getToolboxData(app);
165
166
  toolboxData.forEach(([{ buttonComponents, ...toolboxComponentOptions }, owner]) => {
166
167
  let group;
167
168
  if (app.toolboxManager.has(toolboxComponentOptions.id)) {
@@ -173,6 +174,7 @@ export default async function () {
173
174
  buttonComponents.forEach(c => group.buttonManager.add(c, owner));
174
175
  }
175
176
  });
177
+ this._destroyActions.push(destroyToolboxData);
176
178
 
177
179
  app.contextMenuManager.addEventHandler(async (event) => {
178
180
  const actions = [{
@@ -1,4 +1,7 @@
1
1
  import { ToolboxType } from '@vcmap/ui';
2
+ import { reactive, shallowRef } from 'vue';
3
+ import { VcsEvent } from '@vcmap/core';
4
+ import VcsContent from './vcsContent.vue';
2
5
 
3
6
  const dummySelectAction = {
4
7
  active: false,
@@ -32,123 +35,177 @@ const dummySelectAction = {
32
35
  },
33
36
  };
34
37
 
38
+ function createDummyTriStateAction(app) {
39
+ const windowComponent = {
40
+ id: 'tri-state-example',
41
+ state: {
42
+ headerTitle: 'Example Session Toggle',
43
+ },
44
+ component: VcsContent,
45
+ };
46
+
47
+ const action = reactive({
48
+ name: 'tri-state-action',
49
+ icon: 'mdi-triangle',
50
+ active: false,
51
+ background: false,
52
+ callback() {
53
+ if (this.active) {
54
+ if (this.background) {
55
+ return app.windowManager.add(windowComponent, '@vcmap/test');
56
+ } else {
57
+ app.windowManager.remove(windowComponent.id);
58
+ this.active = false;
59
+ }
60
+ } else {
61
+ this.active = true;
62
+ return app.windowManager.add(windowComponent, '@vcmap/test');
63
+ }
64
+ return null;
65
+ },
66
+ });
67
+
68
+ const listeners = [
69
+ app.windowManager.added.addEventListener(({ id }) => {
70
+ if (id === windowComponent.id) {
71
+ action.active = true;
72
+ action.background = false;
73
+ }
74
+ }),
75
+ app.windowManager.removed.addEventListener(({ id }) => {
76
+ if (id === windowComponent.id) {
77
+ action.background = true;
78
+ }
79
+ }),
80
+ ];
81
+
82
+ const destroy = () => {
83
+ if (app.windowManager.has(windowComponent.id)) {
84
+ app.windowManager.remove(windowComponent.id);
85
+ }
86
+ listeners.forEach(cb => cb());
87
+ };
88
+
89
+ return { action, destroy };
90
+ }
91
+
35
92
  // eslint-disable-next-line import/prefer-default-export
36
- export const toolboxData = [
37
- [
38
- {
39
- id: 'singleSelect',
40
- type: ToolboxType.SINGLE,
41
- action: {
42
- name: 'select',
43
- title: 'single select',
44
- icon: '$vcsPointSelect',
45
- active: false,
46
- callback() { this.active = !this.active; },
93
+ export function getToolboxData(app) {
94
+ const { action: triStateAction, destroy } = createDummyTriStateAction(app);
95
+
96
+ const toolboxData = [
97
+ [
98
+ {
99
+ id: 'singleSelect',
100
+ type: ToolboxType.SINGLE,
101
+ action: {
102
+ name: 'select',
103
+ title: 'single select',
104
+ icon: '$vcsPointSelect',
105
+ active: false,
106
+ callback() { this.active = !this.active; },
107
+ },
47
108
  },
48
- },
49
- '@vcmap/test',
50
- ],
51
- [
52
- {
53
- id: 'multiSelect',
54
- type: ToolboxType.SELECT,
55
- action: {
56
- name: 'multiSelect',
57
- title: 'multi select',
58
- ...dummySelectAction,
59
- tools: [
60
- {
61
- name: 'pen',
62
- title: 'Item 1',
63
- icon: '$vcsPen',
64
- },
65
- {
66
- name: 'object',
67
- title: 'Item 2',
68
- icon: '$vcsObjectSelect',
69
- },
70
- ],
109
+ '@vcmap/test',
110
+ ],
111
+ [
112
+ {
113
+ id: 'multiSelect',
114
+ type: ToolboxType.SELECT,
115
+ action: {
116
+ name: 'multiSelect',
117
+ title: 'multi select',
118
+ ...dummySelectAction,
119
+ tools: [
120
+ {
121
+ name: 'pen',
122
+ title: 'Item 1',
123
+ icon: '$vcsPen',
124
+ },
125
+ {
126
+ name: 'object',
127
+ title: 'Item 2',
128
+ icon: '$vcsObjectSelect',
129
+ },
130
+ ],
131
+ },
71
132
  },
72
- },
73
- '@vcmap/test',
74
- ],
75
- [
76
- {
77
- id: 'measurement',
78
- type: ToolboxType.SELECT,
79
- action: {
80
- name: 'measurement',
81
- title: 'measurement',
82
- ...dummySelectAction,
83
- tools: [
84
- {
85
- name: 'distance',
86
- title: '2D distance',
87
- icon: '$vcs2dDistance',
88
- },
89
- {
90
- name: 'area',
91
- title: '2D area',
92
- icon: '$vcs2dArea',
93
- },
133
+ '@vcmap/test',
134
+ ],
135
+ [
136
+ {
137
+ id: 'measurement',
138
+ type: ToolboxType.SELECT,
139
+ action: {
140
+ name: 'measurement',
141
+ title: 'measurement',
142
+ ...dummySelectAction,
143
+ tools: [
144
+ {
145
+ name: 'distance',
146
+ title: '2D distance',
147
+ icon: '$vcs2dDistance',
148
+ },
149
+ {
150
+ name: 'area',
151
+ title: '2D area',
152
+ icon: '$vcs2dArea',
153
+ },
154
+ {
155
+ name: 'distance3D',
156
+ title: '3D distance',
157
+ icon: '$vcs3dDistance',
158
+ },
159
+ {
160
+ name: 'area3D',
161
+ title: '3D area',
162
+ icon: '$vcs3dArea',
163
+ },
164
+ ],
165
+ },
166
+ },
167
+ '@vcmap/test',
168
+ ],
169
+ [
170
+ {
171
+ id: 'toggle',
172
+ type: ToolboxType.SINGLE,
173
+ action: triStateAction,
174
+ },
175
+ '@vcmap/test',
176
+ ],
177
+ [
178
+ {
179
+ id: 'flight',
180
+ type: ToolboxType.GROUP,
181
+ icon: '$vcsVideoRecorder',
182
+ title: 'flight',
183
+ buttonComponents: [
94
184
  {
95
- name: 'distance3D',
96
- title: '3D distance',
97
- icon: '$vcs3dDistance',
185
+ id: 'flight',
186
+ action: {
187
+ name: 'flight',
188
+ title: 'add flight',
189
+ icon: 'mdi-camera-plus',
190
+ active: false,
191
+ callback() { this.active = !this.active; },
192
+ },
98
193
  },
99
194
  {
100
- name: 'area3D',
101
- title: '3D area',
102
- icon: '$vcs3dArea',
195
+ id: 'export',
196
+ action: {
197
+ name: 'export',
198
+ title: 'export flight',
199
+ icon: '$vcsExportFlight',
200
+ active: false,
201
+ callback() { this.active = !this.active; },
202
+ },
103
203
  },
104
204
  ],
105
205
  },
106
- },
107
- '@vcmap/test',
108
- ],
109
- [
110
- {
111
- id: 'toggle',
112
- type: ToolboxType.SINGLE,
113
- action: {
114
- name: 'split',
115
- title: 'split view',
116
- icon: '$vcsSplitView',
117
- active: false,
118
- callback() { this.active = !this.active; },
119
- },
120
- },
121
- '@vcmap/test',
122
- ],
123
- [
124
- {
125
- id: 'flight',
126
- type: ToolboxType.GROUP,
127
- icon: '$vcsVideoRecorder',
128
- title: 'flight',
129
- buttonComponents: [
130
- {
131
- id: 'flight',
132
- action: {
133
- name: 'flight',
134
- title: 'add flight',
135
- icon: 'mdi-camera-plus',
136
- active: false,
137
- callback() { this.active = !this.active; },
138
- },
139
- },
140
- {
141
- id: 'export',
142
- action: {
143
- name: 'export',
144
- title: 'export flight',
145
- icon: '$vcsExportFlight',
146
- active: false,
147
- callback() { this.active = !this.active; },
148
- },
149
- },
150
- ],
151
- },
152
- '@vcmap/test',
153
- ],
154
- ];
206
+ '@vcmap/test',
207
+ ],
208
+ ];
209
+
210
+ return { toolboxData, destroy };
211
+ }
@@ -1,6 +1,8 @@
1
1
  import { v4 as uuid } from 'uuid';
2
2
  import { check } from '@vcsuite/check';
3
- import { Collection, Extent, MapCollection, mercatorProjection, Viewpoint } from '@vcmap/core';
3
+ import {
4
+ Collection, Extent, MapCollection, mercatorProjection, Viewpoint,
5
+ } from '@vcmap/core';
4
6
  import { Feature } from 'ol';
5
7
  import { reactive, ref } from 'vue';
6
8
  import { vcsAppSymbol } from '../pluginHelper.js';
@@ -76,7 +76,7 @@
76
76
  v-bind="attrs"
77
77
  v-on="on"
78
78
  large
79
- tooltip="Share current view of the map."
79
+ tooltip="navbar.share.tooltip"
80
80
  icon="$vcsShare"
81
81
  />
82
82
  </template>
@@ -85,8 +85,14 @@
85
85
  padding: 0;
86
86
  position: relative;
87
87
 
88
- &.vcs-button--active-disabled{
88
+ &.vcs-button--active-background {
89
89
  border: 2px solid var(--v-primary-base);
90
+ color: var(--v-secondary-base);
91
+ background-color: var(--v-accent-darken1) !important;
92
+ }
93
+
94
+ &.v-btn--disabled {
95
+ background-color: transparent !important;
90
96
  }
91
97
  }
92
98
  }
@@ -102,6 +108,7 @@
102
108
  * @description a button with tooltip extending {@link https://vuetifyjs.com/en/api/v-btn/|vuetify v-btn} using {@link VcsTooltip}.
103
109
  * @vue-prop {boolean} active - Whether button has background color. Applies vuetify primary color if color property is not set.
104
110
  * @vue-prop {string} color - Passes property to v-btn in case prop active is true.
111
+ * @vue-prop {boolean} background - When applied with active the button shows an active-background state implying that a tool is active, but running in background, e.g. windowComponent closed.
105
112
  * @vue-prop {boolean} hasUpdate - Whether the button shows a badge in the top right.
106
113
  * @vue-prop {string} icon - When given, will display an icon in the button. Replaces vuetify icon property.
107
114
  * @vue-prop {string} tooltip - Text content of a tooltip which appears on hover with default delay.
@@ -135,6 +142,10 @@
135
142
  type: String,
136
143
  default: undefined,
137
144
  },
145
+ background: {
146
+ type: Boolean,
147
+ default: false,
148
+ },
138
149
  hasUpdate: {
139
150
  type: Boolean,
140
151
  default: false,
@@ -175,7 +186,7 @@
175
186
  'font-weight-bold': this.isStandard,
176
187
  'text-capitalize': this.isStandard,
177
188
  'vcs-button--large': this.isLarge,
178
- 'vcs-button--active-disabled': this.active && this.$attrs.disabled,
189
+ 'vcs-button--active-background': this.active && this.background && !this.$attrs.disabled,
179
190
  };
180
191
  },
181
192
  hasDefaultSlot() {
@@ -192,7 +203,7 @@
192
203
  },
193
204
  isOutlined() {
194
205
  if (this.isStandard) {
195
- return this.active || this.$attrs.disabled;
206
+ return this.active || this.background;
196
207
  }
197
208
  return false;
198
209
  },
@@ -52,6 +52,7 @@
52
52
  * @property {string} [icon] - icon rendered on the button. If no icon provided, item is rendered in overflow
53
53
  * @property {Function} callback - callback function is triggered when the button is clicked
54
54
  * @property {boolean} [active=false] - optional state of button. If active, button is rendered in primary color
55
+ * @property {boolean} [background=false] - optional background state. If active and background, button is rendered in primary color outlined
55
56
  */
56
57
 
57
58
  /**
@@ -64,6 +65,7 @@
64
65
  icon: [undefined, String],
65
66
  callback: Function,
66
67
  active: [undefined, Boolean],
68
+ background: [undefined, Boolean],
67
69
  };
68
70
 
69
71
  /**
@@ -139,7 +139,7 @@ class LayerContentTreeItem extends VcsObjectContentTreeItem {
139
139
  * @private
140
140
  */
141
141
  _setLayerExtentAction() {
142
- const name = 'LayerExtentAction';
142
+ const name = 'content.layerExtentAction.name';
143
143
  this.removeAction(name);
144
144
  if (this._layer) {
145
145
  const { extent } = this._layer.toJSON();
@@ -147,7 +147,7 @@ class LayerContentTreeItem extends VcsObjectContentTreeItem {
147
147
  const viewpoint = Viewpoint.createViewpointFromExtent(this._layer.extent);
148
148
  const action = createGoToViewpointAction(
149
149
  {
150
- name: 'LayerExtentAction',
150
+ name,
151
151
  title: 'content.layerExtentAction.title',
152
152
  },
153
153
  viewpoint,
@@ -40,9 +40,9 @@
40
40
  <v-list-item class="px-2">
41
41
  <v-list-item-content>
42
42
  <v-list-item-title>
43
- {{ name }}
43
+ {{ $t(name) }}
44
44
  </v-list-item-title>
45
- <v-list-item-subtitle>{{ value }}</v-list-item-subtitle>
45
+ <v-list-item-subtitle>{{ $t(value) }}</v-list-item-subtitle>
46
46
  </v-list-item-content>
47
47
  </v-list-item>
48
48
  </v-list>
package/src/i18n/de.js CHANGED
@@ -8,6 +8,9 @@ const messages = {
8
8
  menu: {
9
9
  tooltip: 'Menü',
10
10
  },
11
+ share: {
12
+ tooltip: 'Den aktuellen Kartenausschnitt teilen.',
13
+ },
11
14
  },
12
15
  content: {
13
16
  title: 'Inhalte',
@@ -30,7 +33,8 @@ const messages = {
30
33
  title: 'Öffne Stil Auswahl',
31
34
  },
32
35
  layerExtentAction: {
33
- title: 'Jump to layer extent',
36
+ name: 'Ebenenausdehnung',
37
+ title: 'Auf Ebenenausdehnung zoomen',
34
38
  },
35
39
  },
36
40
  navigation: {
@@ -38,7 +42,7 @@ const messages = {
38
42
  obliqueRightTooltip: 'Schrägluftbild nach rechts drehen',
39
43
  zoomInTooltip: 'Hineinzoomen',
40
44
  zoomOutTooltip: 'Herauszoomen',
41
- pitchTooltip: 'Kamera pitch: {0}°',
45
+ pitchTooltip: 'Kameraneigung: {0}°',
42
46
  overviewMapTooltip: 'Übersichtskarte',
43
47
  },
44
48
  categoryManager: {
package/src/i18n/en.js CHANGED
@@ -8,6 +8,9 @@ const messages = {
8
8
  menu: {
9
9
  tooltip: 'Menu',
10
10
  },
11
+ share: {
12
+ tooltip: 'Share current view of the map.',
13
+ },
11
14
  },
12
15
  content: {
13
16
  title: 'Content',
@@ -30,6 +33,7 @@ const messages = {
30
33
  title: 'Open Style selector',
31
34
  },
32
35
  layerExtentAction: {
36
+ name: 'Layer extent',
33
37
  title: 'Jump to layer extent',
34
38
  },
35
39
  },
@@ -1,5 +1,5 @@
1
1
  import { getShapeFromOptions } from '@vcmap/core';
2
- import { ref } from 'vue';
2
+ import { shallowRef } from 'vue';
3
3
 
4
4
  /**
5
5
  * @enum {string}
@@ -142,7 +142,7 @@ export function getLegendEntries(app) {
142
142
  /**
143
143
  * @type {import("vue").Ref<Array<LegendEntry>>}>}
144
144
  */
145
- const entries = ref([]);
145
+ const entries = shallowRef([]);
146
146
  /**
147
147
  * @type {Object<string,function():void>}
148
148
  */
@@ -153,10 +153,8 @@ export function getLegendEntries(app) {
153
153
  */
154
154
  function removeEntryForLayer(layer) {
155
155
  const layerName = layer.name;
156
- const index = entries.value.findIndex(({ key }) => { return key === layerName; });
157
- if (index >= 0) {
158
- entries.value.splice(index, 1);
159
- }
156
+ // reassign to trigger update
157
+ entries.value = entries.value.filter(({ key }) => key !== layerName);
160
158
  if (styleChangedListener[layerName]) {
161
159
  styleChangedListener[layerName]();
162
160
  delete styleChangedListener[layerName];
@@ -176,7 +174,8 @@ export function getLegendEntries(app) {
176
174
  const legend = layer.style?.properties?.legend ?? layer.properties?.legend;
177
175
  if (legend) {
178
176
  const legendEntry = createLayerLegendEntry(key, title, legend);
179
- entries.value.push(legendEntry);
177
+ // use spread since push won't trigger updates
178
+ entries.value = [...entries.value, legendEntry];
180
179
  }
181
180
  if (layer.styleChanged) {
182
181
  styleChangedListener[layer.name] = layer.styleChanged.addEventListener(() => syncLayerLegendEntries(layer));