@vcmap/ui 5.0.0-rc.21 → 5.0.0-rc.23

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 (153) hide show
  1. package/README.md +2 -2
  2. package/app.config.json +5 -0
  3. package/build/buildHelpers.js +1 -0
  4. package/build/buildPreview.js +2 -2
  5. package/build/commonViteConfig.js +1 -0
  6. package/config/aerowest.config.json +2 -0
  7. package/config/base.config.json +1 -0
  8. package/config/codes.config.json +2 -0
  9. package/config/dev.config.json +6 -0
  10. package/config/graphFeatureInfo.config.json +3 -1
  11. package/config/projects.config.json +27 -0
  12. package/config/www.config.json +27 -14
  13. package/dist/assets/cesium.js +1 -1
  14. package/dist/assets/{core.59d4d1.js → core.9342a1.js} +7912 -5474
  15. package/dist/assets/core.js +1 -1
  16. package/dist/assets/favicon.decf54cc.svg +10 -0
  17. package/dist/assets/index.fd041928.js +1 -0
  18. package/dist/assets/{ol.c1c512.js → ol.d2cba3.js} +12406 -12152
  19. package/dist/assets/ol.js +1 -1
  20. package/dist/assets/ui.c27597.css +5 -0
  21. package/dist/assets/{ui.80175f.js → ui.c27597.js} +6508 -5169
  22. package/dist/assets/ui.js +1 -1
  23. package/dist/assets/vue.js +2 -2
  24. package/dist/assets/vuetify.2f1432.css +5 -0
  25. package/dist/assets/{vuetify.efc158.js → vuetify.2f1432.js} +1 -1
  26. package/dist/assets/vuetify.js +2 -2
  27. package/dist/index.html +6 -1
  28. package/index.html +5 -0
  29. package/index.js +7 -3
  30. package/lib/olLib.js +15 -1
  31. package/package.json +5 -4
  32. package/plugins/@vcmap/project-selector/{ContextsListComponent.vue → ModulesListComponent.vue} +10 -10
  33. package/plugins/@vcmap/project-selector/ProjectSelectorComponent.vue +16 -16
  34. package/plugins/@vcmap/project-selector/README.md +15 -21
  35. package/plugins/@vcmap/project-selector/config.json +3 -3
  36. package/plugins/@vcmap/project-selector/de.json +3 -0
  37. package/plugins/@vcmap/project-selector/en.json +3 -0
  38. package/plugins/@vcmap/project-selector/index.js +76 -101
  39. package/plugins/@vcmap/simple-graph/index.js +1 -1
  40. package/plugins/@vcmap/theme-changer/ThemeChangerComponent.vue +10 -4
  41. package/plugins/@vcmap-show-case/category-tester/Categories.vue +2 -2
  42. package/plugins/@vcmap-show-case/category-tester/Category.vue +1 -4
  43. package/plugins/@vcmap-show-case/config-editor/editor.vue +14 -14
  44. package/plugins/@vcmap-show-case/form-inputs-example/FormInputsExample.vue +92 -81
  45. package/plugins/@vcmap-show-case/form-inputs-example/index.js +8 -3
  46. package/plugins/@vcmap-show-case/form-inputs-example/validation.js +1 -1
  47. package/plugins/@vcmap-show-case/list-example/ListExample.vue +5 -2
  48. package/plugins/@vcmap-show-case/table-example/DataTableExample.vue +202 -0
  49. package/plugins/@vcmap-show-case/table-example/README.md +3 -0
  50. package/plugins/@vcmap-show-case/table-example/index.js +47 -0
  51. package/plugins/@vcmap-show-case/table-example/package.json +5 -0
  52. package/plugins/@vcmap-show-case/wizard-example/wizardExample.vue +57 -23
  53. package/plugins/package.json +2 -1
  54. package/src/actions/actionHelper.js +16 -27
  55. package/src/actions/styleSelector.vue +26 -19
  56. package/src/application/VcsApp.vue +13 -5
  57. package/src/application/VcsAttributions.vue +2 -3
  58. package/src/application/VcsAttributionsFooter.vue +10 -16
  59. package/src/application/VcsNavbar.vue +1 -2
  60. package/src/application/VcsSettings.vue +21 -8
  61. package/src/assets/favicon-128.png +0 -0
  62. package/src/assets/favicon-180.png +0 -0
  63. package/src/assets/favicon-192.png +0 -0
  64. package/src/assets/favicon-32.png +0 -0
  65. package/src/assets/favicon.svg +10 -0
  66. package/src/components/buttons/VcsButton.vue +2 -3
  67. package/src/components/form-inputs-controls/VcsCheckbox.vue +46 -26
  68. package/src/components/form-inputs-controls/VcsDatePicker.vue +111 -0
  69. package/src/components/form-inputs-controls/VcsFormSection.vue +15 -13
  70. package/src/components/form-inputs-controls/VcsLabel.vue +10 -1
  71. package/src/components/form-inputs-controls/VcsRadio.vue +38 -18
  72. package/src/components/form-inputs-controls/VcsSelect.vue +117 -59
  73. package/src/components/form-inputs-controls/VcsTextArea.vue +101 -60
  74. package/src/components/form-inputs-controls/VcsTextField.vue +182 -69
  75. package/src/components/form-inputs-controls/VcsWizard.vue +23 -15
  76. package/src/components/form-inputs-controls/VcsWizardStep.vue +18 -16
  77. package/src/components/form-inputs-controls/composables.js +26 -0
  78. package/src/components/form-output/VcsFormattedNumber.vue +1 -1
  79. package/src/components/icons/2DDistanceIcon.vue +0 -3
  80. package/src/components/icons/3DDistanceIcon.vue +0 -3
  81. package/src/components/icons/3DHeightIcon.vue +0 -3
  82. package/src/components/icons/CheckboxCheckedIcon.vue +4 -11
  83. package/src/components/icons/CheckboxIcon.vue +9 -2
  84. package/src/components/icons/CheckboxIndeterminateIcon.vue +4 -21
  85. package/src/components/icons/CommentIcon.vue +1 -5
  86. package/src/components/icons/LegendIcon.vue +10 -60
  87. package/src/components/icons/ObliqueViewIcon.vue +6 -8
  88. package/src/components/icons/SimpleCircleOutlinedIcon.vue +1 -1
  89. package/src/components/icons/SplitViewIcon.vue +0 -4
  90. package/src/components/icons/ToolsIcon.vue +2 -4
  91. package/src/components/lists/VcsActionList.vue +0 -1
  92. package/src/components/lists/VcsList.vue +30 -30
  93. package/src/components/lists/VcsTreeview.vue +2 -2
  94. package/src/components/lists/VcsTreeviewLeaf.vue +3 -9
  95. package/src/components/lists/VcsTreeviewSearchbar.vue +4 -4
  96. package/src/components/notification/VcsBadge.vue +6 -2
  97. package/src/components/notification/VcsHelp.vue +39 -0
  98. package/src/components/tables/VcsDataTable.vue +386 -0
  99. package/src/components/tables/VcsTable.vue +55 -254
  100. package/src/contentTree/contentTreeCollection.js +1 -1
  101. package/src/contentTree/layerContentTreeItem.js +3 -0
  102. package/src/downloadHelper.js +49 -0
  103. package/src/featureInfo/AddressBalloonComponent.vue +1 -1
  104. package/src/featureInfo/BalloonComponent.vue +21 -15
  105. package/src/featureInfo/abstractFeatureInfoView.js +1 -1
  106. package/src/featureInfo/featureInfo.js +27 -9
  107. package/src/featureInfo/tableFeatureInfoView.js +4 -0
  108. package/src/i18n/de.js +13 -1
  109. package/src/i18n/en.js +13 -1
  110. package/src/i18n/i18nCollection.js +22 -22
  111. package/src/init.js +90 -7
  112. package/src/legend/styleLegendItem.vue +24 -2
  113. package/src/legend/vcsLegend.vue +24 -31
  114. package/src/manager/categoryManager/CategoryComponent.vue +56 -47
  115. package/src/manager/categoryManager/CategoryManager.vue +23 -10
  116. package/src/manager/categoryManager/categoryManager.js +11 -11
  117. package/src/manager/navbarManager.js +18 -0
  118. package/src/manager/toolbox/GroupToolboxComponent.vue +2 -3
  119. package/src/manager/toolbox/SelectToolboxComponent.vue +11 -5
  120. package/src/manager/toolbox/ToolboxManager.vue +0 -7
  121. package/src/manager/window/WindowComponent.vue +10 -16
  122. package/src/manager/window/WindowComponentHeader.vue +6 -4
  123. package/src/manager/window/WindowManager.vue +14 -15
  124. package/src/manager/window/windowHelper.js +1 -1
  125. package/src/manager/window/windowManager.js +18 -7
  126. package/src/navigation/mapNavCompass.vue +1 -1
  127. package/src/navigation/mapNavigation.vue +6 -6
  128. package/src/navigation/obliqueRotation.vue +36 -13
  129. package/src/navigation/orientationToolsButton.vue +0 -1
  130. package/src/navigation/overviewMap.js +11 -20
  131. package/src/navigation/tiltSlider.vue +30 -6
  132. package/src/navigation/vcsZoomButton.vue +37 -11
  133. package/src/pluginHelper.js +20 -0
  134. package/src/search/resultsComponent.vue +0 -1
  135. package/src/search/search.js +19 -20
  136. package/src/search/searchComponent.vue +21 -7
  137. package/src/state.js +6 -6
  138. package/src/styles/_theming.scss +72 -3
  139. package/src/styles/_typography.scss +0 -5
  140. package/src/styles/main.scss +1 -0
  141. package/src/styles/shades.scss +2 -0
  142. package/src/styles/variables.scss +40 -4
  143. package/src/uiConfig.js +4 -3
  144. package/src/vcsUiApp.js +49 -40
  145. package/src/vuePlugins/i18n.js +1 -0
  146. package/src/vuePlugins/vuetify.js +59 -13
  147. package/start.js +8 -2
  148. package/dist/assets/index.a3861d4e.js +0 -1
  149. package/dist/assets/ui.80175f.css +0 -1
  150. package/dist/assets/vuetify.efc158.css +0 -5
  151. package/map.config.json +0 -44
  152. /package/dist/assets/{cesium.49585c.js → cesium.166f91.js} +0 -0
  153. /package/dist/assets/{vue.a08ab1.js → vue.5d00e9.js} +0 -0
@@ -3,24 +3,26 @@
3
3
  :tooltip-position="tooltipPosition"
4
4
  :tooltip="errorMessage"
5
5
  color="error"
6
+ :max-width="200"
6
7
  >
7
8
  <template #activator="{ on, attrs }">
8
9
  <span v-on="on">
9
10
  <v-checkbox
11
+ ref="checkbox"
10
12
  :input-value="$attrs.value"
11
13
  on-icon="$vcsCheckboxChecked"
12
14
  off-icon="$vcsCheckbox"
13
15
  class="vcs-checkbox"
16
+ :class="{'pl-1': !isDense }"
14
17
  hide-details
15
18
  indeterminate-icon="$vcsCheckboxIndeterminate"
16
- :dense="$attrs.dense!==false"
19
+ :dense="isDense"
17
20
  :ripple="false"
18
21
  v-bind="{...$attrs, ...attrs}"
19
22
  v-on="{...$listeners, ...on}"
20
- @update:error="setError"
21
23
  >
22
24
  <template #label>
23
- <VcsLabel :html-for="$attrs.id" :dense="!!$attrs.dense">
25
+ <VcsLabel :html-for="$attrs.id" :dense="isDense">
24
26
  <slot name="label" />
25
27
  <span v-if="!$slots.label">{{ $t($attrs.label) }}</span>
26
28
  </VcsLabel>
@@ -31,28 +33,45 @@
31
33
  </VcsTooltip>
32
34
  </template>
33
35
  <style lang="scss" scoped>
34
- .vcs-checkbox {
35
- ::v-deep {
36
- label.v-label,
37
- .v-icon.v-icon{
38
- color: inherit;
39
- }
40
- .v-input--selection-controls__input {
41
- margin: 0;
42
- padding: 0;
36
+ @import '../../styles/shades.scss';
37
+ .vcs-checkbox {
38
+ ::v-deep {
39
+ .v-input--selection-controls__input {
40
+ margin: 0;
41
+ padding: 0;
42
+ }
43
+ label.v-label.error--text {
44
+ animation: none;
45
+ }
46
+ .v-icon,
47
+ .v-label {
48
+ &.theme--light {
49
+ color: map-get($shades, 'black') !important;
50
+ &.error--text{
51
+ color: var(--v-error-base) !important;
52
+ }
53
+ }
54
+ &.theme--dark {
55
+ color: map-get($shades, 'white') !important;
56
+ &.error--text{
57
+ color: var(--v-error-base) !important;
58
+ }
59
+ }
60
+ }
43
61
  }
44
62
  }
45
- }
46
- .v-input--selection-controls {
47
- margin: 0;
48
- padding: 0;
49
- }
63
+ .v-input--selection-controls {
64
+ margin: 0;
65
+ padding: 0;
66
+ }
67
+
50
68
  </style>
51
69
  <script>
70
+ import { computed, ref } from 'vue';
52
71
  import { VCheckbox } from 'vuetify/lib';
53
72
  import VcsLabel from './VcsLabel.vue';
54
73
  import VcsTooltip from '../notification/VcsTooltip.vue';
55
- import validate from '../notification/validation.js';
74
+ import { useErrorSync } from './composables.js';
56
75
 
57
76
  /**
58
77
  * @description Stylized wrapper around {@link https://vuetifyjs.com/en/api/v-checkbox/ |vuetify checkbox}.
@@ -77,17 +96,18 @@
77
96
  default: 'right',
78
97
  },
79
98
  },
80
- data() {
99
+ setup(props, { attrs }) {
100
+ const checkbox = ref();
101
+
102
+ const errorMessage = useErrorSync(checkbox);
103
+ const isDense = computed(() => attrs.dense !== false);
104
+
81
105
  return {
82
- errorMessage: '',
106
+ checkbox,
107
+ errorMessage,
108
+ isDense,
83
109
  };
84
110
  },
85
- methods: {
86
- setError() {
87
- const rules = [...this.$attrs.rules].concat(this.$attrs.errorMessages);
88
- this.errorMessage = validate(rules, this.$attrs.value).join('\n');
89
- },
90
- },
91
111
  model: {
92
112
  event: 'change',
93
113
  },
@@ -0,0 +1,111 @@
1
+ <template>
2
+ <v-menu
3
+ v-model="menuOpen"
4
+ :close-on-content-click="false"
5
+ transition="scale-transition"
6
+ offset-y
7
+ max-width="290px"
8
+ min-width="290px"
9
+ >
10
+ <template #activator="{ on, attrs }">
11
+ <v-text-field
12
+ v-model="formattedDate"
13
+ :placeholder="formatDate(new Date().toISOString())"
14
+ v-bind="{...$attrs, ...attrs}"
15
+ v-on="{...$listeners, ...on}"
16
+ :prepend-icon="icon"
17
+ readonly
18
+ hide-details
19
+ class="ma-0 py-1"
20
+ />
21
+ </template>
22
+ <v-date-picker v-model="date" no-title @input="menuOpen = false" :locale="locale" color="primary">
23
+ <v-btn color="primary" @click="goToToday">
24
+ {{ $t('datePicker.today') }}
25
+ </v-btn>
26
+ </v-date-picker>
27
+ </v-menu>
28
+ </template>
29
+ <style lang="scss" scoped>
30
+ ::v-deep {
31
+ .v-input__control{
32
+ padding: 0 8px;
33
+ }
34
+ }
35
+ </style>
36
+ <script>
37
+ import {
38
+ computed, ref, watch, inject, onUnmounted, onBeforeMount,
39
+ } from 'vue';
40
+ import {
41
+ VMenu, VTextField, VDatePicker, VBtn,
42
+ } from 'vuetify/lib';
43
+ /**
44
+ * @description stylized wrapper around {@link https://v15.vuetifyjs.com/en/components/date-pickers/#month-pickers-in-dialog-and-menu}.
45
+ * @vue-prop {string} value - value of the date picker in {@link https://tc39.es/ecma262/#sec-date-time-string-format | Date Time String Format}
46
+ * @vue-prop {string} icon - specify optional prepend icon, defaults to mdi-calendar
47
+ * @vue-event {string} input - raised when calendar date is selected
48
+ */
49
+ export default {
50
+ name: 'VcsDatePicker',
51
+ props: {
52
+ value: {
53
+ type: String,
54
+ required: true,
55
+ },
56
+ icon: {
57
+ type: String,
58
+ default: 'mdi-calendar',
59
+ },
60
+ },
61
+ components: {
62
+ VMenu,
63
+ VTextField,
64
+ VDatePicker,
65
+ VBtn,
66
+ },
67
+ setup(props, context) {
68
+ /**
69
+ * @type {import("@vcmap/ui").VcsUiApp}
70
+ */
71
+ const app = /** @type {import("@vcmap/ui").VcsUiApp} */ (inject('vcsApp'));
72
+ const localValue = ref(props.value);
73
+ const menuOpen = ref(false);
74
+ const locale = ref(app.locale);
75
+
76
+ const isValid = date => !Number.isNaN(Date.parse(date));
77
+ const setFromValue = () => {
78
+ if (isValid(localValue.value)) {
79
+ localValue.value = props.value;
80
+ } else {
81
+ // eslint-disable-next-line no-console
82
+ console.error('Invalid date provided: ', props.value);
83
+ }
84
+ };
85
+ onBeforeMount(() => setFromValue());
86
+ const destroyLocaleChanged = app.localeChanged.addEventListener(() => { locale.value = app.locale; });
87
+ onUnmounted(() => destroyLocaleChanged());
88
+
89
+ const formatDate = (date) => {
90
+ if (date) {
91
+ return new Intl.DateTimeFormat(locale.value, { dateStyle: 'short' }).format(Date.parse(date));
92
+ }
93
+ return '';
94
+ };
95
+ const goToToday = () => {
96
+ localValue.value = new Date(Date.now()).toISOString().substring(0, 10);
97
+ menuOpen.value = false;
98
+ };
99
+ watch(() => props.value, () => setFromValue());
100
+ const formattedDate = computed({
101
+ get: () => { return formatDate(localValue.value); },
102
+ set: () => {},
103
+ });
104
+ const date = computed({ get: () => localValue.value, set: (nv) => { localValue.value = nv; context.emit('input', localValue.value); } });
105
+
106
+ return {
107
+ formattedDate, date, menuOpen, formatDate, locale, goToToday,
108
+ };
109
+ },
110
+ };
111
+ </script>
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <section class="vcs-form-section">
3
3
  <slot name="header" :heading="heading" :actions="actions">
4
- <article class="pa-2 accent">
4
+ <article class="pa-2 base lighten-3">
5
5
  <div class="form-section-header d-flex justify-space-between align-center">
6
6
  <strong class="caption">{{ $t(heading) }}</strong>
7
7
  <VcsActionButtonList
@@ -12,17 +12,13 @@
12
12
  </div>
13
13
  </article>
14
14
  </slot>
15
- <v-alert
16
- :value="showHelp"
17
- dense
18
- text
19
- color="secondary"
20
- class="ma-0"
15
+ <VcsHelp
16
+ :text="helpText"
17
+ :show="showHelp"
18
+ class="base lighten-4"
21
19
  >
22
- <slot name="help">
23
- <span>{{ $t(helpText) }}</span>
24
- </slot>
25
- </v-alert>
20
+ <slot name="help" />
21
+ </VcsHelp>
26
22
  <article class="section-content">
27
23
  <slot />
28
24
  </article>
@@ -32,8 +28,8 @@
32
28
 
33
29
  <script>
34
30
  import { computed, reactive } from 'vue';
35
- import { VAlert } from 'vuetify/lib';
36
31
  import VcsActionButtonList from '../buttons/VcsActionButtonList.vue';
32
+ import VcsHelp from '../notification/VcsHelp.vue';
37
33
 
38
34
  /**
39
35
  * @description
@@ -51,7 +47,7 @@
51
47
  name: 'VcsFormSection',
52
48
  components: {
53
49
  VcsActionButtonList,
54
- VAlert,
50
+ VcsHelp,
55
51
  },
56
52
  props: {
57
53
  heading: {
@@ -98,3 +94,9 @@
98
94
  },
99
95
  };
100
96
  </script>
97
+
98
+ <style scoped>
99
+ .v-alert--text:before{
100
+ background-color: transparent;
101
+ }
102
+ </style>
@@ -1,8 +1,17 @@
1
1
  <template>
2
- <label :htmlFor="htmlFor" class="vcs-label" :class="{'vcs-label-dense': dense}">
2
+ <label
3
+ :htmlFor="htmlFor"
4
+ class="vcs-label"
5
+ :class="{
6
+ 'vcs-label-dense': dense,
7
+ 'px-1': dense,
8
+ 'px-2': !dense,
9
+ }"
10
+ >
3
11
  <slot />
4
12
  </label>
5
13
  </template>
14
+
6
15
  <style lang="scss" scoped>
7
16
  @import "../../styles/vcsGrid.scss";
8
17
  @import "../../styles/vcsFont";
@@ -3,30 +3,31 @@
3
3
  :tooltip-position="tooltipPosition"
4
4
  :tooltip="errorMessage"
5
5
  color="error"
6
+ :max-width="200"
6
7
  >
7
8
  <template #activator="{ on, attrs }">
8
9
  <span v-on="on">
9
10
  <v-radio-group
11
+ ref="radioGroup"
10
12
  hide-details
11
13
  class="w-full vcs-radio-group"
12
- :dense="$attrs.dense!==false"
14
+ :dense="isDense"
13
15
  :ripple="false"
14
16
  v-bind="{...$attrs, ...attrs}"
15
17
  v-on="{...$listeners, ...on}"
16
- @update:error="setError"
17
18
  >
18
19
  <v-radio
19
20
  v-for="(item, idx) in items"
20
21
  :id="`radio-${idx}`"
21
22
  :key="`radio-${idx}`"
22
23
  :ripple="false"
23
- :color="item.color ?? 'secondary'"
24
24
  :value="item.value ?? item"
25
25
  :disabled="item.disabled ?? false"
26
- :class="$attrs.dense!==false ? 'vcs-radio-dense' : 'vcs-radio'"
26
+ class="ma-0"
27
+ :class="isDense ? 'vcs-radio-dense' : 'vcs-radio'"
27
28
  >
28
29
  <template #label>
29
- <VcsLabel :html-for="`radio-${idx}`" :dense="!!$attrs.dense">
30
+ <VcsLabel :html-for="`radio-${idx}`" :dense="isDense">
30
31
  {{ $t(item.label ?? item) }}
31
32
  </VcsLabel>
32
33
  </template>
@@ -38,11 +39,12 @@
38
39
  </template>
39
40
  <style lang="scss" scoped>
40
41
  @import "../../styles/vcsFont";
42
+ @import '../../styles/shades.scss';
41
43
  .v-input--radio-group--column .v-radio:not(:last-child):not(:only-child) {
42
44
  margin-bottom: 0;
43
45
  }
44
- .v-input{
45
- &.vcs-radio-group{
46
+ .v-input {
47
+ &.vcs-radio-group {
46
48
  ::v-deep {
47
49
  margin-top: 0;
48
50
  padding-top: 0;
@@ -50,19 +52,35 @@
50
52
  .v-icon.v-icon{
51
53
  font-size: $base-font-size;
52
54
  color: inherit;
55
+ &.theme--light{
56
+ color: map-get($shades, 'black') !important;
57
+ &.error--text{
58
+ color: var(--v-error-base) !important;
59
+ }
60
+ }
61
+ &.theme--dark{
62
+ color: map-get($shades, 'white') !important;
63
+ &.error--text{
64
+ color: var(--v-error-base) !important;
65
+ }
66
+ }
53
67
  }
54
- .v-radio:not(:last-child):not(:only-child){
68
+ .v-radio:not(:last-child):not(:only-child) {
55
69
  margin-bottom: 0;
56
70
  }
57
- .v-input--selection-controls__input{
71
+ .v-input--selection-controls__input {
58
72
  margin: 0;
59
73
  }
74
+ label.v-label.error--text {
75
+ animation: none;
76
+ }
60
77
  }
61
78
  }
62
79
  }
63
80
  .vcs-radio {
64
81
  height: 40px;
65
82
  align-items: center;
83
+ padding-left: 4px;
66
84
  }
67
85
  .vcs-radio-dense {
68
86
  height: 32px;
@@ -70,10 +88,11 @@
70
88
  }
71
89
  </style>
72
90
  <script>
91
+ import { computed, ref } from 'vue';
73
92
  import { VRadio, VRadioGroup } from 'vuetify/lib';
74
93
  import VcsTooltip from '../notification/VcsTooltip.vue';
75
94
  import VcsLabel from './VcsLabel.vue';
76
- import validate from '../notification/validation.js';
95
+ import { useErrorSync } from './composables.js';
77
96
 
78
97
  /**
79
98
  * @typedef {Object} VcsRadioItem
@@ -111,17 +130,18 @@
111
130
  required: true,
112
131
  },
113
132
  },
114
- data() {
133
+ setup(props, { attrs }) {
134
+ const radioGroup = ref();
135
+
136
+ const errorMessage = useErrorSync(radioGroup);
137
+ const isDense = computed(() => attrs.dense !== false);
138
+
115
139
  return {
116
- errorMessage: '',
140
+ radioGroup,
141
+ errorMessage,
142
+ isDense,
117
143
  };
118
144
  },
119
- methods: {
120
- setError() {
121
- const rules = [...this.$attrs.rules].concat(this.$attrs.errorMessages);
122
- this.errorMessage = validate(rules, this.$attrs.value).join('\n');
123
- },
124
- },
125
145
  model: {
126
146
  event: 'change',
127
147
  },
@@ -1,33 +1,42 @@
1
1
  <template>
2
- <div
3
- @mouseover="hover = true"
4
- @mouseleave="hover = false"
5
- >
2
+ <div>
6
3
  <VcsTooltip
7
4
  :tooltip-position="tooltipPosition"
8
5
  :tooltip="errorMessage"
9
6
  color="error"
7
+ :max-width="200"
10
8
  >
11
9
  <template #activator="{ on, attrs }">
12
10
  <span v-on="on">
13
11
  <v-select
12
+ ref="selectField"
14
13
  append-icon="mdi-chevron-down"
15
14
  hide-details
16
15
  flat
17
- :outlined="isOutlined"
16
+ outlined
18
17
  :dense="isDense"
19
18
  :height="isDense ? 24 : 32"
20
19
  :item-text="item => $t(getText(item))"
21
- :class="$attrs.color === 'primary' ? 'primary--select' : ''"
20
+ class="py-1 primary--placeholder"
21
+ :class="{
22
+ 'remove-outline': !isOutlined,
23
+ 'input--dense': isDense,
24
+ 'input--not-dense': !isDense,
25
+ 'outline--current': focus,
26
+ 'outline--error': !!errorMessage,
27
+ }"
22
28
  v-bind="{...$attrs, ...attrs}"
23
29
  v-on="{...$listeners, ...on}"
24
- @update:error="setError"
30
+ @focus="focus = true;"
31
+ @blur="focus = false;"
32
+ @mouseover="hover = true"
33
+ @mouseleave="hover = false"
25
34
  >
26
35
  <template #selection="{ item, index }">
27
36
  <span v-if="index === 0" class="text-truncate">
28
37
  {{ $t(getText(item)) }}
29
38
  </span>
30
- <span v-if="index === 1" class="text-no-wrap grey--text text-caption">
39
+ <span v-if="index === 1" class="text-no-wrap text-caption">
31
40
  (+{{ $attrs.value.length - 1 }})
32
41
  </span>
33
42
  </template>
@@ -38,39 +47,85 @@
38
47
  </div>
39
48
  </template>
40
49
  <style lang="scss" scoped>
41
- .v-text-field {
42
- padding: 0;
43
- margin: 0;
44
- }
45
-
46
- .vcs-select-hover{
47
- color: var(--v-primary-base) !important;
48
- }
49
-
50
- .primary--select {
51
- ::v-deep {
52
- .v-select__selection,
53
- .v-select__selection--comma,
54
- .v-select.v-text-field input {
55
- color: var(--v-primary-base);
56
- }
57
- }
58
- }
59
- .v-select{
60
- &.v-select--is-multi{
61
- ::v-deep {
62
- .v-select__selections{
50
+ .primary--placeholder {
51
+ ::v-deep {
52
+ input::placeholder {
53
+ color: var(--v-primary-base);
54
+ font-style: italic;
55
+ opacity: 1;
56
+ }
57
+ }
58
+ }
59
+ .v-select{
60
+ &.v-select--is-multi{
61
+ ::v-deep {
62
+ .v-select__selections{
63
63
  flex-wrap: nowrap;
64
- }
65
- }
66
- }
67
- }
64
+ }
65
+ }
66
+ }
67
+ }
68
+ .remove-outline {
69
+ ::v-deep {
70
+ fieldset {
71
+ border-width: 0;
72
+ border-radius: 0;
73
+ }
74
+ }
75
+ }
76
+ .outline--current {
77
+ ::v-deep {
78
+ .v-input__slot fieldset, .v-input__slot .v-select__slot {
79
+ border-color: currentColor;
80
+ transition: border-color 0.5s ease;
81
+ }
82
+ }
83
+ }
84
+ .outline--error {
85
+ ::v-deep {
86
+ .v-input__slot fieldset, .v-input__slot .v-select__slot {
87
+ border-color: var(--v-error-base);
88
+ }
89
+ }
90
+ }
91
+ .input--dense {
92
+ ::v-deep {
93
+ .v-input__slot {
94
+ padding: 0 4px !important;
95
+ }
96
+ fieldset {
97
+ padding-left: 2px;
98
+ }
99
+ }
100
+ }
101
+ .input--not-dense {
102
+ ::v-deep {
103
+ .v-input__slot {
104
+ padding: 0 8px !important;
105
+ }
106
+ fieldset {
107
+ padding-left: 6px;
108
+ }
109
+ }
110
+ }
111
+ .v-input {
112
+ ::v-deep {
113
+ fieldset {
114
+ border-radius: 2px;
115
+ border-color: var(--v-base-base);
116
+ }
117
+ .v-select__slot {
118
+ border-bottom: 1px solid var(--v-base-base);
119
+ }
120
+ }
121
+ }
68
122
  </style>
69
123
  <script>
70
124
 
71
125
  import { VSelect } from 'vuetify/lib';
126
+ import { computed, ref } from 'vue';
72
127
  import VcsTooltip from '../notification/VcsTooltip.vue';
73
- import validate from '../notification/validation.js';
128
+ import { useErrorSync } from './composables.js';
74
129
 
75
130
  /**
76
131
  * @description Stylized wrapper around {@link https://vuetifyjs.com/en/api/v-select/ |vuetify select}.
@@ -100,33 +155,36 @@
100
155
  default: undefined,
101
156
  },
102
157
  },
103
- data() {
104
- return {
105
- hover: false,
106
- errorMessage: '',
107
- };
108
- },
109
- computed: {
110
- isDense() {
111
- return this.$attrs.dense !== undefined && this.$attrs.dense !== false;
112
- },
113
- isOutlined() {
114
- return (this.hover || this.errorMessage.length > 0) &&
115
- !(this.$attrs.disabled || this.$attrs.disabled === '');
116
- },
117
- },
118
- methods: {
119
- setError() {
120
- const rules = [...this.$attrs.rules].concat(this.$attrs.errorMessages);
121
- this.errorMessage = validate(rules, this.$attrs.value).join('\n');
122
- },
123
- getText(item) {
124
- if (this.itemText) {
125
- return this.itemText(item);
158
+ setup(props, { attrs }) {
159
+ const hover = ref(false);
160
+ const focus = ref(false);
161
+ // $ref to v-select element
162
+ const selectField = ref();
163
+
164
+ const errorMessage = useErrorSync(selectField);
165
+
166
+ const isDense = computed(() => attrs.dense !== false);
167
+ const isOutlined = computed(() => {
168
+ return (hover.value || focus.value || !!errorMessage.value) && !(attrs.disabled || attrs.disabled === '');
169
+ });
170
+
171
+ function getText(item) {
172
+ if (props.itemText) {
173
+ return props.itemText(item);
126
174
  } else {
127
175
  return item?.text ?? item;
128
176
  }
129
- },
177
+ }
178
+
179
+ return {
180
+ hover,
181
+ focus,
182
+ errorMessage,
183
+ isDense,
184
+ isOutlined,
185
+ getText,
186
+ selectField,
187
+ };
130
188
  },
131
189
  };
132
190
  </script>