@vcmap/ui 5.0.0-rc.29 → 5.0.0-rc.30
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.
- package/config/dev.config.json +4 -0
- package/dist/assets/cesium.js +1 -1
- package/dist/assets/{core.74da2a.js → core.b16511.js} +2 -2
- package/dist/assets/core.js +1 -1
- package/dist/assets/index-c115e3a1.js +1 -0
- package/dist/assets/ol.js +1 -1
- package/dist/assets/{ui.d3054c.css → ui.ab815e.css} +2 -2
- package/dist/assets/{ui.d3054c.js → ui.ab815e.js} +4081 -3460
- package/dist/assets/ui.js +1 -1
- package/dist/assets/vue.js +2 -2
- package/dist/assets/{vuetify.946bd8.js → vuetify.ea3fa8.js} +1 -1
- package/dist/assets/vuetify.js +2 -2
- package/dist/index.html +1 -1
- package/index.js +6 -0
- package/package.json +1 -1
- package/plugins/@vcmap/search-nominatim/SearchNominatimEditor.vue +90 -0
- package/plugins/@vcmap/search-nominatim/index.js +37 -0
- package/plugins/@vcmap-show-case/form-inputs-example/FormInputsExample.vue +37 -1
- package/plugins/@vcmap-show-case/form-inputs-example/index.js +3 -0
- package/plugins/@vcmap-show-case/form-inputs-example/validation.js +11 -0
- package/plugins/@vcmap-show-case/style-input-example/styleExample.vue +0 -1
- package/plugins/@vcmap-show-case/vector-properties-example/index.js +40 -0
- package/plugins/@vcmap-show-case/vector-properties-example/package.json +5 -0
- package/plugins/@vcmap-show-case/vector-properties-example/vectorPropertiesExample.vue +109 -0
- package/src/components/form-inputs-controls/VcsChipArrayInput.vue +282 -0
- package/src/components/form-inputs-controls/VcsTextField.vue +9 -3
- package/src/components/plugins/AbstractConfigEditor.vue +84 -0
- package/src/components/style/VcsImageSelector.vue +6 -5
- package/src/components/style/VcsTextSelector.vue +1 -1
- package/src/components/vector-properties/VcsVectorPropertiesComponent.vue +737 -0
- package/src/components/vector-properties/composables.js +93 -0
- package/src/i18n/de.js +40 -9
- package/src/i18n/en.js +38 -7
- package/src/manager/collectionManager/collectionComponent.js +1 -1
- package/src/pluginHelper.js +57 -17
- package/src/vcsUiApp.js +17 -27
- package/dist/assets/index-cb070eff.js +0 -1
- /package/dist/assets/{cesium.16590b.js → cesium.eaf7cc.js} +0 -0
- /package/dist/assets/{ol.50a512.js → ol.4bbf0f.js} +0 -0
- /package/dist/assets/{vue.30740e.js → vue.67e80f.js} +0 -0
- /package/dist/assets/{vuetify.946bd8.css → vuetify.ea3fa8.css} +0 -0
@@ -0,0 +1,282 @@
|
|
1
|
+
<template>
|
2
|
+
<div id="vcs-chip-array-input" class="d-flex d-inline-block align-center">
|
3
|
+
<v-btn
|
4
|
+
v-if="hasScrollbar"
|
5
|
+
:dense="isDense"
|
6
|
+
x-small
|
7
|
+
icon
|
8
|
+
:ripple="false"
|
9
|
+
elevation="0"
|
10
|
+
@click="vcsChipArrayInput.scrollLeft -= scrollDx"
|
11
|
+
>
|
12
|
+
<v-icon>mdi-chevron-left</v-icon>
|
13
|
+
</v-btn>
|
14
|
+
<div
|
15
|
+
id="vcs-chip-array-input"
|
16
|
+
ref="vcsChipArrayInput"
|
17
|
+
class="d-flex d-inline-block"
|
18
|
+
:class="{
|
19
|
+
'overflow-x-auto': !column,
|
20
|
+
'hide-scrollbar': !column,
|
21
|
+
row: column,
|
22
|
+
'ma-1': !hasScrollbar,
|
23
|
+
}"
|
24
|
+
>
|
25
|
+
<div v-for="(item, index) in value" :key="index" class="py-1 pr-1">
|
26
|
+
<v-chip
|
27
|
+
v-if="selected !== index"
|
28
|
+
v-bind="{ ...$attrs }"
|
29
|
+
:small="isDense"
|
30
|
+
:disabled="disabled"
|
31
|
+
:close="deletableChips"
|
32
|
+
@click="select(index)"
|
33
|
+
@click:close="remove(index)"
|
34
|
+
class="pa-2"
|
35
|
+
>
|
36
|
+
<span class="text-truncate d-inline-block">{{ item }}</span>
|
37
|
+
</v-chip>
|
38
|
+
<VcsTextField
|
39
|
+
v-else
|
40
|
+
hide-details
|
41
|
+
:dense="isDense"
|
42
|
+
rounded
|
43
|
+
filled
|
44
|
+
autofocus
|
45
|
+
no-padding
|
46
|
+
:height="24"
|
47
|
+
v-bind="{ ...$attrs }"
|
48
|
+
v-model="editValue"
|
49
|
+
@keydown.esc="selected = -1"
|
50
|
+
@blur="selected = -1"
|
51
|
+
@keydown.enter="submitChange"
|
52
|
+
@click:append="submitChange"
|
53
|
+
@update:error="(err) => (isEditValid = !err)"
|
54
|
+
append-icon="mdi-check"
|
55
|
+
:style="{ width: `${inputWidth}px` }"
|
56
|
+
/>
|
57
|
+
</div>
|
58
|
+
<div class="py-1">
|
59
|
+
<v-chip
|
60
|
+
v-if="adding === false"
|
61
|
+
v-bind="{ ...$attrs }"
|
62
|
+
:small="isDense"
|
63
|
+
:disabled="disabled"
|
64
|
+
@click="adding = true"
|
65
|
+
class="pa-2"
|
66
|
+
>
|
67
|
+
<v-icon>$vcsPlus</v-icon>
|
68
|
+
</v-chip>
|
69
|
+
<VcsTextField
|
70
|
+
v-else
|
71
|
+
hide-details
|
72
|
+
:dense="isDense"
|
73
|
+
rounded
|
74
|
+
filled
|
75
|
+
autofocus
|
76
|
+
no-padding
|
77
|
+
:height="24"
|
78
|
+
class="vcs-inside-chip"
|
79
|
+
v-model="newValue"
|
80
|
+
v-bind="{ ...$attrs }"
|
81
|
+
@keydown.enter="add(newValue)"
|
82
|
+
@keydown.esc="cancel"
|
83
|
+
@blur="cancel"
|
84
|
+
@click:append="add(newValue)"
|
85
|
+
@update:error="(err) => (isNewValid = !err)"
|
86
|
+
append-icon="mdi-check"
|
87
|
+
:style="{ width: `${inputWidth}px` }"
|
88
|
+
/>
|
89
|
+
</div>
|
90
|
+
</div>
|
91
|
+
<v-btn
|
92
|
+
v-if="hasScrollbar"
|
93
|
+
:dense="isDense"
|
94
|
+
x-small
|
95
|
+
icon
|
96
|
+
:ripple="false"
|
97
|
+
elevation="0"
|
98
|
+
@click="vcsChipArrayInput.scrollLeft += scrollDx"
|
99
|
+
>
|
100
|
+
<v-icon>mdi-chevron-right</v-icon>
|
101
|
+
</v-btn>
|
102
|
+
</div>
|
103
|
+
</template>
|
104
|
+
|
105
|
+
<style lang="scss" scoped>
|
106
|
+
.hide-scrollbar {
|
107
|
+
-ms-overflow-style: none; /* IE and Edge */
|
108
|
+
scrollbar-width: none; /* Firefox */
|
109
|
+
}
|
110
|
+
.hide-scrollbar::-webkit-scrollbar {
|
111
|
+
display: none;
|
112
|
+
}
|
113
|
+
.v-chip {
|
114
|
+
display: flex;
|
115
|
+
max-width: 260px;
|
116
|
+
padding: 0 8px;
|
117
|
+
.v-chip__content {
|
118
|
+
display: flex;
|
119
|
+
}
|
120
|
+
}
|
121
|
+
.vcs-inside-chip {
|
122
|
+
::v-deep {
|
123
|
+
.v-input__slot {
|
124
|
+
.v-input__append-inner {
|
125
|
+
margin-top: 5px;
|
126
|
+
}
|
127
|
+
}
|
128
|
+
.v-text-field--filled > .v-input__control > .v-input__slot,
|
129
|
+
.v-text-field--outlined > .v-input__control > .v-input__slot {
|
130
|
+
min-height: unset;
|
131
|
+
}
|
132
|
+
}
|
133
|
+
}
|
134
|
+
</style>
|
135
|
+
|
136
|
+
<script>
|
137
|
+
import { computed, nextTick, onMounted, ref } from 'vue';
|
138
|
+
import { VBtn, VChip, VIcon } from 'vuetify/lib';
|
139
|
+
import VcsTextField from './VcsTextField.vue';
|
140
|
+
|
141
|
+
/**
|
142
|
+
* @description Renders elements of an array as chips with an input field to edit or add new elements.
|
143
|
+
* Provides two height options depending on "dense" property
|
144
|
+
* Provides VcsTooltip to show error messages on focus
|
145
|
+
* When clicking esc key, previous input is restored.
|
146
|
+
* @vue-prop {('bottom' | 'left' | 'top' | 'right')} [tooltipPosition='right'] - Position of the error tooltip.
|
147
|
+
* @vue-prop {string} [type] - The input type (string or number)
|
148
|
+
* @vue-prop {boolean} [disabled] - Disables adding or removing new elements
|
149
|
+
* @vue-prop {boolean} [column] - Remove horizontal pagination and wrap items as needed
|
150
|
+
* @vue-prop {boolean} [scrollDx=20] - scroll amount in px
|
151
|
+
* @vue-prop {boolean} [deletableChips=true] - Adds a delete button to elements to remove them from array
|
152
|
+
* @vue-prop {number} [inputWidth=50] - Width of the text fields in px.
|
153
|
+
*/
|
154
|
+
export default {
|
155
|
+
name: 'VcsChipArrayInput',
|
156
|
+
components: {
|
157
|
+
VBtn,
|
158
|
+
VcsTextField,
|
159
|
+
VChip,
|
160
|
+
VIcon,
|
161
|
+
},
|
162
|
+
props: {
|
163
|
+
value: {
|
164
|
+
type: Array,
|
165
|
+
required: true,
|
166
|
+
},
|
167
|
+
tooltipPosition: {
|
168
|
+
type: String,
|
169
|
+
default: 'right',
|
170
|
+
},
|
171
|
+
deletableChips: {
|
172
|
+
type: Boolean,
|
173
|
+
default: true,
|
174
|
+
},
|
175
|
+
inputWidth: {
|
176
|
+
type: Number,
|
177
|
+
default: 50,
|
178
|
+
},
|
179
|
+
disabled: {
|
180
|
+
type: Boolean,
|
181
|
+
default: false,
|
182
|
+
},
|
183
|
+
column: {
|
184
|
+
type: Boolean,
|
185
|
+
default: false,
|
186
|
+
},
|
187
|
+
scrollDx: {
|
188
|
+
type: Number,
|
189
|
+
default: 20,
|
190
|
+
},
|
191
|
+
},
|
192
|
+
setup(props, { attrs, emit }) {
|
193
|
+
const selected = ref(-1);
|
194
|
+
const adding = ref(false);
|
195
|
+
const isEditValid = ref(true);
|
196
|
+
const editValue = ref(undefined);
|
197
|
+
const isNewValid = ref(true);
|
198
|
+
const newValue = ref(undefined);
|
199
|
+
const vcsChipArrayInput = ref();
|
200
|
+
const hasScrollbar = ref();
|
201
|
+
const isDense = computed(() => attrs.dense !== false);
|
202
|
+
|
203
|
+
function emitValue(value) {
|
204
|
+
if (attrs.type === 'number') {
|
205
|
+
emit(
|
206
|
+
'input',
|
207
|
+
value.map((v) => parseFloat(v)),
|
208
|
+
);
|
209
|
+
} else {
|
210
|
+
emit('input', value);
|
211
|
+
}
|
212
|
+
}
|
213
|
+
|
214
|
+
function updateHasScrollbar() {
|
215
|
+
if (!props.column) {
|
216
|
+
hasScrollbar.value =
|
217
|
+
vcsChipArrayInput.value.scrollWidth -
|
218
|
+
vcsChipArrayInput.value.clientWidth >
|
219
|
+
36; // size of the scroll buttons
|
220
|
+
}
|
221
|
+
}
|
222
|
+
|
223
|
+
onMounted(() => updateHasScrollbar());
|
224
|
+
|
225
|
+
function remove(index) {
|
226
|
+
emitValue(props.value.toSpliced(index, 1));
|
227
|
+
updateHasScrollbar();
|
228
|
+
}
|
229
|
+
|
230
|
+
function select(index) {
|
231
|
+
if (!props.disabled) {
|
232
|
+
selected.value = index;
|
233
|
+
editValue.value = props.value[index];
|
234
|
+
}
|
235
|
+
}
|
236
|
+
|
237
|
+
function submitChange() {
|
238
|
+
if (isEditValid.value) {
|
239
|
+
emitValue(props.value.toSpliced(selected.value, 1, editValue.value));
|
240
|
+
selected.value = -1;
|
241
|
+
}
|
242
|
+
}
|
243
|
+
|
244
|
+
function cancel() {
|
245
|
+
newValue.value = undefined;
|
246
|
+
adding.value = false;
|
247
|
+
}
|
248
|
+
|
249
|
+
async function add(value) {
|
250
|
+
if (isNewValid.value) {
|
251
|
+
if (value) {
|
252
|
+
emitValue([...props.value, value]);
|
253
|
+
await nextTick();
|
254
|
+
updateHasScrollbar();
|
255
|
+
await nextTick();
|
256
|
+
vcsChipArrayInput.value.scrollLeft =
|
257
|
+
vcsChipArrayInput.value.scrollWidth;
|
258
|
+
}
|
259
|
+
newValue.value = undefined;
|
260
|
+
adding.value = true;
|
261
|
+
}
|
262
|
+
}
|
263
|
+
|
264
|
+
return {
|
265
|
+
selected,
|
266
|
+
adding,
|
267
|
+
editValue,
|
268
|
+
isEditValid,
|
269
|
+
newValue,
|
270
|
+
isNewValid,
|
271
|
+
isDense,
|
272
|
+
vcsChipArrayInput,
|
273
|
+
hasScrollbar,
|
274
|
+
remove,
|
275
|
+
select,
|
276
|
+
submitChange,
|
277
|
+
add,
|
278
|
+
cancel,
|
279
|
+
};
|
280
|
+
},
|
281
|
+
};
|
282
|
+
</script>
|
@@ -25,8 +25,9 @@
|
|
25
25
|
v-on="{ ...$listeners, ...on }"
|
26
26
|
:height="isDense ? 24 : 32"
|
27
27
|
:rules="rules"
|
28
|
-
class="
|
28
|
+
class="primary--placeholder align-center"
|
29
29
|
:class="{
|
30
|
+
'py-1': !noPadding,
|
30
31
|
'remove-outline': !isOutlined,
|
31
32
|
'outline--current': focus,
|
32
33
|
'outline--error': !!errorMessage,
|
@@ -134,7 +135,7 @@
|
|
134
135
|
.v-icon {
|
135
136
|
font-size: 16px;
|
136
137
|
}
|
137
|
-
fieldset {
|
138
|
+
.v-text-field--rounded fieldset {
|
138
139
|
border-radius: 2px;
|
139
140
|
border-color: var(--v-base-base);
|
140
141
|
}
|
@@ -160,6 +161,7 @@
|
|
160
161
|
* @vue-prop {('bottom' | 'left' | 'top' | 'right')} [tooltipPosition='right'] - Position of the error tooltip.
|
161
162
|
* @vue-prop {string} unit - Unit for number input fields. Is displayed behind the number.
|
162
163
|
* @vue-prop {boolean} showSpinButtons - If true, spin buttons are displayed in number input fields. Overrides Vuetify hide-spin-buttons.
|
164
|
+
* @vue-prop {boolean} noPadding - Padding is required for usage within rows. For standalone usage this prop removes class py-1.
|
163
165
|
* @vue-computed {boolean} isClearable - Whether textfield is isClearable. Makes sure icon is only shown on focus, hover or error.
|
164
166
|
* @vue-computed {boolean} isDense - Whether size of textfield is dense.
|
165
167
|
* @vue-computed {boolean} isOutlined - Textfield is outlined on either hover, focus or error, if not disabled.
|
@@ -186,6 +188,10 @@
|
|
186
188
|
type: Boolean,
|
187
189
|
default: false,
|
188
190
|
},
|
191
|
+
noPadding: {
|
192
|
+
type: Boolean,
|
193
|
+
default: false,
|
194
|
+
},
|
189
195
|
},
|
190
196
|
setup(props, { attrs, emit }) {
|
191
197
|
const hover = ref(false);
|
@@ -223,7 +229,7 @@
|
|
223
229
|
get() {
|
224
230
|
if (
|
225
231
|
attrs.type === 'number' &&
|
226
|
-
attrs.value &&
|
232
|
+
Number.isFinite(attrs.value) &&
|
227
233
|
props.unit &&
|
228
234
|
!focus.value &&
|
229
235
|
!hover.value
|
@@ -0,0 +1,84 @@
|
|
1
|
+
<template>
|
2
|
+
<v-container class="pa-0">
|
3
|
+
<v-form v-model="isValid" @submit.prevent="submit">
|
4
|
+
<slot />
|
5
|
+
<div class="d-flex gap-2 px-2 pt-2 pb-1">
|
6
|
+
<div class="d-flex gap-2 w-full justify-start">
|
7
|
+
<VcsFormButton v-if="showReset" icon="$vcsReturn" @click="reset" />
|
8
|
+
</div>
|
9
|
+
<div class="d-flex gap-2 w-full justify-end">
|
10
|
+
<VcsFormButton type="submit" variant="filled" :disabled="!isValid">
|
11
|
+
{{ $t('appConfigurator.apply') }}
|
12
|
+
</VcsFormButton>
|
13
|
+
<VcsFormButton @click.stop="cancel">
|
14
|
+
{{ $t('appConfigurator.cancel') }}
|
15
|
+
</VcsFormButton>
|
16
|
+
<VcsActionButtonList :actions="actions" button="VcsFormButton" />
|
17
|
+
</div>
|
18
|
+
</div>
|
19
|
+
</v-form>
|
20
|
+
</v-container>
|
21
|
+
</template>
|
22
|
+
|
23
|
+
<script>
|
24
|
+
import { VContainer, VForm } from 'vuetify/lib';
|
25
|
+
import { ref, inject } from 'vue';
|
26
|
+
import VcsFormButton from '../buttons/VcsFormButton.vue';
|
27
|
+
import VcsActionButtonList from '../buttons/VcsActionButtonList.vue';
|
28
|
+
|
29
|
+
/**
|
30
|
+
* @description Basic wrapper for all config editor components using {@link https://vuetifyjs.com/en/api/v-form/ |vuetify form}.
|
31
|
+
* Providing a footer with submit, cancel and optionally reset button.
|
32
|
+
* @vue-prop {boolean} [showReset=false] - Flag to show a reset button in the footer. You need to handle @reset in a child component.
|
33
|
+
* @vue-prop {Array<VcsAction>} [actions] - Optional actions rendered as ActionButtonList in the footer.
|
34
|
+
* @vue-event {Event} submit - Event fired on clicking the submit button.
|
35
|
+
* @vue-event {Event} cancel - Event fired on clicking the cancel button.
|
36
|
+
* @vue-event {Event} reset - Event fired on clicking the reset button.
|
37
|
+
*/
|
38
|
+
export default {
|
39
|
+
name: 'AbstractConfigEditor',
|
40
|
+
components: {
|
41
|
+
VContainer,
|
42
|
+
VForm,
|
43
|
+
VcsFormButton,
|
44
|
+
VcsActionButtonList,
|
45
|
+
},
|
46
|
+
props: {
|
47
|
+
showReset: {
|
48
|
+
type: Boolean,
|
49
|
+
default: false,
|
50
|
+
},
|
51
|
+
actions: {
|
52
|
+
type: Array,
|
53
|
+
default: () => [],
|
54
|
+
},
|
55
|
+
},
|
56
|
+
setup(props, { attrs, emit }) {
|
57
|
+
const app = inject('vcsApp');
|
58
|
+
|
59
|
+
const close = () => {
|
60
|
+
if (app.windowManager.has(attrs['window-state'].id)) {
|
61
|
+
app.windowManager.remove(attrs['window-state'].id);
|
62
|
+
}
|
63
|
+
};
|
64
|
+
|
65
|
+
return {
|
66
|
+
isValid: ref(true),
|
67
|
+
submit(e) {
|
68
|
+
close();
|
69
|
+
emit('submit', e);
|
70
|
+
},
|
71
|
+
cancel(e) {
|
72
|
+
close();
|
73
|
+
attrs.setConfig();
|
74
|
+
emit('cancel', e);
|
75
|
+
},
|
76
|
+
reset(e) {
|
77
|
+
emit('reset', e);
|
78
|
+
},
|
79
|
+
};
|
80
|
+
},
|
81
|
+
};
|
82
|
+
</script>
|
83
|
+
|
84
|
+
<style scoped></style>
|
@@ -74,14 +74,15 @@
|
|
74
74
|
:min="input.range?.[0] || 0"
|
75
75
|
:max="input.range?.[1] || undefined"
|
76
76
|
:rules="[
|
77
|
-
(v) =>
|
77
|
+
(v) =>
|
78
|
+
!input.isRequired || !!v || 'components.validation.required',
|
78
79
|
(v) =>
|
79
80
|
!input.range ||
|
80
81
|
(!input.isRequired && !v) ||
|
81
82
|
between(v, input.range) ||
|
82
|
-
`${$t(
|
83
|
-
'
|
84
|
-
)}`,
|
83
|
+
`${$t(
|
84
|
+
'components.validation.allowedRange',
|
85
|
+
)}: ${input.range.join(' - ')}`,
|
85
86
|
]"
|
86
87
|
:show-spin-buttons="true"
|
87
88
|
/>
|
@@ -458,7 +459,7 @@
|
|
458
459
|
if (Array.isArray(props.value?.scale)) {
|
459
460
|
return props.value.scale[index];
|
460
461
|
} else {
|
461
|
-
return props.value
|
462
|
+
return props.value?.scale;
|
462
463
|
}
|
463
464
|
},
|
464
465
|
set(value) {
|