@dative-gpi/foundation-shared-components 0.0.82 → 0.0.84

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.
@@ -32,6 +32,7 @@
32
32
  #body
33
33
  >
34
34
  <FSForm
35
+ ref="formRef"
35
36
  :variant="$props.variant"
36
37
  @submit="onSubmit"
37
38
  v-model="valid"
@@ -198,6 +199,7 @@ export default defineComponent({
198
199
  const { isMobileSized } = useBreakpoints();
199
200
  const { $tr } = useTranslationsProvider();
200
201
 
202
+ const formRef = ref<HTMLElement | null>(null);
201
203
  const valid = ref(false);
202
204
 
203
205
  const height = computed(() => {
@@ -227,6 +229,7 @@ export default defineComponent({
227
229
  cancelButtonLabel,
228
230
  submitButtonLabel,
229
231
  ColorEnum,
232
+ formRef,
230
233
  height,
231
234
  valid,
232
235
  onSubmit
@@ -36,7 +36,7 @@ export default defineComponent({
36
36
  switch (props.variant) {
37
37
  case "standard": return "input";
38
38
  case "lazy": return "blur";
39
- case "submit": return "submit";
39
+ default: return "submit";
40
40
  }
41
41
  });
42
42
 
@@ -1,86 +1,109 @@
1
1
  <template>
2
- <FSWrapGroup
3
- v-if="['wrap'].includes($props.variant)"
4
- ref="toggleSetRef"
5
- :padding="$props.padding"
6
- :gap="$props.gap"
2
+ <v-input
3
+ class="fs-toggle-set"
4
+ ref="inputRef"
5
+ :modelValue="$props.modelValue"
6
+ :rules="$props.rules"
7
7
  >
8
- <template v-if="$props.values.length">
9
- <template v-if="!firstChild">
10
- <FSButton
11
- v-for="(item, index) in $props.values"
12
- :prependIcon="item.prependIcon"
13
- :appendIcon="item.appendIcon"
14
- :editable="$props.editable"
15
- :variant="getVariant(item)"
16
- :color="getColor(item)"
17
- :class="getClass(item)"
18
- :label="item.label"
19
- :icon="item.icon"
20
- :key="index"
21
- @click="toggle(item)"
22
- />
8
+ <FSWrapGroup
9
+ v-if="['wrap'].includes($props.variant)"
10
+ ref="toggleSetRef"
11
+ :padding="$props.padding"
12
+ :gap="$props.gap"
13
+ >
14
+ <template
15
+ v-if="$props.values.length"
16
+ >
17
+ <template
18
+ v-if="!firstChild"
19
+ >
20
+ <FSButton
21
+ v-for="(item, index) in $props.values"
22
+ :prependIcon="item.prependIcon"
23
+ :appendIcon="item.appendIcon"
24
+ :editable="$props.editable"
25
+ :variant="getVariant(item)"
26
+ :color="getColor(item)"
27
+ :class="getClass(item)"
28
+ :label="item.label"
29
+ :icon="item.icon"
30
+ :key="index"
31
+ @click="toggle(item)"
32
+ />
33
+ </template>
34
+ <template
35
+ v-else
36
+ >
37
+ <component
38
+ v-for="(item, index) in $props.values"
39
+ :key="index"
40
+ :is="firstChild"
41
+ :prependIcon="getFromFirstChild('prependIcon', item)"
42
+ :appendIcon="getFromFirstChild('appendIcon', item)"
43
+ :variant="getFromFirstChild('variant', item)"
44
+ :color="getFromFirstChild('color', item)"
45
+ :class="getFromFirstChild('class', item)"
46
+ :label="getFromFirstChild('label', item)"
47
+ :icon="getFromFirstChild('icon', item)"
48
+ :editable="$props.editable"
49
+ @click="toggle(item)"
50
+ />
51
+ </template>
23
52
  </template>
24
- <template v-else>
25
- <component
26
- v-for="(item, index) in $props.values"
27
- :key="index"
28
- :is="firstChild"
29
- :prependIcon="getFromFirstChild('prependIcon', item)"
30
- :appendIcon="getFromFirstChild('appendIcon', item)"
31
- :variant="getFromFirstChild('variant', item)"
32
- :color="getFromFirstChild('color', item)"
33
- :class="getFromFirstChild('class', item)"
34
- :label="getFromFirstChild('label', item)"
35
- :icon="getFromFirstChild('icon', item)"
36
- :editable="$props.editable"
37
- @click="toggle(item)"
38
- />
53
+ <slot
54
+ v-else
55
+ />
56
+ </FSWrapGroup>
57
+ <FSSlideGroup
58
+ v-else
59
+ ref="toggleSetRef"
60
+ :padding="$props.padding"
61
+ :gap="$props.gap"
62
+ >
63
+ <template
64
+ v-if="$props.values.length"
65
+ >
66
+ <template
67
+ v-if="!firstChild"
68
+ >
69
+ <FSButton
70
+ v-for="(item, index) in $props.values"
71
+ :prependIcon="item.prependIcon"
72
+ :appendIcon="item.appendIcon"
73
+ :editable="$props.editable"
74
+ :variant="getVariant(item)"
75
+ :color="getColor(item)"
76
+ :class="getClass(item)"
77
+ :label="item.label"
78
+ :icon="item.icon"
79
+ :key="index"
80
+ @click="toggle(item)"
81
+ />
82
+ </template>
83
+ <template
84
+ v-else
85
+ >
86
+ <component
87
+ v-for="(item, index) in $props.values"
88
+ :key="index"
89
+ :is="firstChild"
90
+ :prependIcon="getFromFirstChild('prependIcon', item)"
91
+ :appendIcon="getFromFirstChild('appendIcon', item)"
92
+ :variant="getFromFirstChild('variant', item)"
93
+ :color="getFromFirstChild('color', item)"
94
+ :class="getFromFirstChild('class', item)"
95
+ :label="getFromFirstChild('label', item)"
96
+ :icon="getFromFirstChild('icon', item)"
97
+ :editable="$props.editable"
98
+ @click="toggle(item)"
99
+ />
100
+ </template>
39
101
  </template>
40
- </template>
41
- <slot v-else />
42
- </FSWrapGroup>
43
- <FSSlideGroup
44
- v-else
45
- ref="toggleSetRef"
46
- :padding="$props.padding"
47
- :gap="$props.gap"
48
- >
49
- <template v-if="$props.values.length">
50
- <template v-if="!firstChild">
51
- <FSButton
52
- v-for="(item, index) in $props.values"
53
- :prependIcon="item.prependIcon"
54
- :appendIcon="item.appendIcon"
55
- :editable="$props.editable"
56
- :variant="getVariant(item)"
57
- :color="getColor(item)"
58
- :class="getClass(item)"
59
- :label="item.label"
60
- :icon="item.icon"
61
- :key="index"
62
- @click="toggle(item)"
63
- />
64
- </template>
65
- <template v-else>
66
- <component
67
- v-for="(item, index) in $props.values"
68
- :key="index"
69
- :is="firstChild"
70
- :prependIcon="getFromFirstChild('prependIcon', item)"
71
- :appendIcon="getFromFirstChild('appendIcon', item)"
72
- :variant="getFromFirstChild('variant', item)"
73
- :color="getFromFirstChild('color', item)"
74
- :class="getFromFirstChild('class', item)"
75
- :label="getFromFirstChild('label', item)"
76
- :icon="getFromFirstChild('icon', item)"
77
- :editable="$props.editable"
78
- @click="toggle(item)"
79
- />
80
- </template>
81
- </template>
82
- <slot v-else />
83
- </FSSlideGroup>
102
+ <slot
103
+ v-else
104
+ />
105
+ </FSSlideGroup>
106
+ </v-input>
84
107
  </template>
85
108
 
86
109
  <script lang="ts">
@@ -88,7 +111,7 @@ import { defineComponent, PropType, ref } from "vue";
88
111
 
89
112
  import { ColorBase, ColorEnum } from "@dative-gpi/foundation-shared-components/models";
90
113
  import { useSlots } from "@dative-gpi/foundation-shared-components/composables";
91
- import { FSToggle } from "@dative-gpi/foundation-shared-components/models";
114
+ import { FSToggle } from "@dative-gpi/foundation-shared-components/models";
92
115
 
93
116
  import FSSlideGroup from "./FSSlideGroup.vue";
94
117
  import FSWrapGroup from "./FSWrapGroup.vue";
@@ -157,6 +180,11 @@ export default defineComponent({
157
180
  required: false,
158
181
  default: "8px"
159
182
  },
183
+ rules: {
184
+ type: Array as PropType<any[]>,
185
+ required: false,
186
+ default: () => []
187
+ },
160
188
  multiple: {
161
189
  type: Boolean,
162
190
  required: false,
@@ -176,9 +204,10 @@ export default defineComponent({
176
204
  emits: ["update:modelValue"],
177
205
  setup(props, { emit }) {
178
206
  const { getFirstChild } = useSlots();
179
-
207
+
180
208
  const firstChild = getFirstChild("item");
181
-
209
+
210
+ const inputRef = ref(null);
182
211
  const toggleSetRef = ref(null);
183
212
 
184
213
  const getFromFirstChild = (prop: string, value: FSToggle): any => {
@@ -264,11 +293,23 @@ export default defineComponent({
264
293
  else {
265
294
  if (props.modelValue === value.id) {
266
295
  if (!props.required) {
296
+ if (props.multiple) {
297
+ emit("update:modelValue", []);
298
+ return;
299
+ }
267
300
  emit("update:modelValue", null);
268
301
  return;
269
302
  }
270
303
  }
271
304
  else {
305
+ if (props.multiple) {
306
+ if (props.modelValue) {
307
+ emit("update:modelValue", [props.modelValue, value.id]);
308
+ return;
309
+ }
310
+ emit("update:modelValue", [value.id]);
311
+ return;
312
+ }
272
313
  emit("update:modelValue", value.id);
273
314
  return;
274
315
  }
@@ -288,6 +329,7 @@ export default defineComponent({
288
329
  };
289
330
 
290
331
  return {
332
+ inputRef,
291
333
  toggleSetRef,
292
334
  firstChild,
293
335
  getFromFirstChild,
@@ -0,0 +1,122 @@
1
+ <template>
2
+ <FSAutocompleteField
3
+ :toggleSet="!$props.toggleSetDisabled && toggleSet"
4
+ :multiple="$props.multiple"
5
+ :loading="loading"
6
+ :items="languages"
7
+ :modelValue="$props.modelValue"
8
+ @update:modelValue="onUpdate"
9
+ v-model:search="search"
10
+ v-bind="$attrs"
11
+ >
12
+ <template
13
+ #selection="{ item }"
14
+ >
15
+ <FSRow
16
+ align="center-center"
17
+ >
18
+ <FSIcon>
19
+ {{ item.raw.icon }}
20
+ </FSIcon>
21
+ <FSSpan>
22
+ {{ item.raw.label }}
23
+ </FSSpan>
24
+ </FSRow>
25
+ </template>
26
+ <template
27
+ #item="{ props, item }"
28
+ >
29
+ <v-list-item
30
+ v-bind="{ ...props, title: '' }"
31
+ >
32
+ <FSRow
33
+ align="center-left"
34
+ >
35
+ <FSCheckbox
36
+ v-if="$props.multiple"
37
+ :modelValue="isSelected(item.value)"
38
+ />
39
+ <FSIcon>
40
+ {{ item.raw.icon }}
41
+ </FSIcon>
42
+ <FSSpan>
43
+ {{ item.raw.label }}
44
+ </FSSpan>
45
+ </FSRow>
46
+ </v-list-item>
47
+ </template>
48
+ </FSAutocompleteField>
49
+ </template>
50
+
51
+ <script lang="ts">
52
+ import { computed, PropType, defineComponent } from "vue"
53
+
54
+ import { useAutocomplete } from "@dative-gpi/foundation-shared-components/composables";
55
+ import { useLanguages } from "@dative-gpi/foundation-shared-services/composables";
56
+ import { LanguageFilters } from "@dative-gpi/foundation-shared-domain/models";
57
+
58
+ import FSCheckbox from "../FSCheckbox.vue"
59
+ import FSAutocompleteField from "../fields/FSAutocompleteField.vue"
60
+
61
+ export default defineComponent({
62
+ name: "FSAutocompleteLanguage",
63
+ components: {
64
+ FSAutocompleteField,
65
+ FSCheckbox
66
+ },
67
+ props: {
68
+ languageFilters: {
69
+ type: Object as PropType<LanguageFilters>,
70
+ required: false,
71
+ default: null
72
+ },
73
+ modelValue: {
74
+ type: [Array, String] as PropType<string[] | string | null>,
75
+ required: false,
76
+ default: null
77
+ },
78
+ multiple: {
79
+ type: Boolean,
80
+ required: false,
81
+ default: false
82
+ },
83
+ toggleSetDisabled: {
84
+ type: Boolean,
85
+ required: false,
86
+ default: false
87
+ }
88
+ },
89
+ emits: ["update:modelValue"],
90
+ setup(props, { emit }) {
91
+ const { getMany: getManyLanguages, fetching: fetchingLanguages, entities: languages } = useLanguages();
92
+
93
+ const innerFetch = (search: string | null) => {
94
+ return getManyLanguages({ ...props.languageFilters, search: search ?? undefined });
95
+ };
96
+
97
+ const { toggleSet, search, init, onUpdate } = useAutocomplete(
98
+ languages,
99
+ [() => props.languageFilters],
100
+ emit,
101
+ innerFetch
102
+ );
103
+
104
+ const isSelected = (id: any) => {
105
+ return props.modelValue?.includes(id);
106
+ }
107
+
108
+ const loading = computed((): boolean => {
109
+ return init.value && fetchingLanguages.value;
110
+ });
111
+
112
+ return {
113
+ languages,
114
+ toggleSet,
115
+ loading,
116
+ search,
117
+ isSelected,
118
+ onUpdate
119
+ };
120
+ }
121
+ })
122
+ </script>
@@ -0,0 +1,43 @@
1
+ <template>
2
+ <FSAutocompleteField
3
+ :loading="fetching"
4
+ :items="organisations"
5
+ v-bind="$attrs" />
6
+ </template>
7
+ <script lang="ts">
8
+ import { PropType, defineComponent, watch } from 'vue'
9
+ import _ from 'lodash';
10
+
11
+ import { OrganisationFilters } from '@dative-gpi/foundation-shared-domain/models';
12
+ import { useOrganisations } from '@dative-gpi/foundation-shared-services/composables';
13
+
14
+ import FSAutocompleteField from '../fields/FSAutocompleteField.vue'
15
+
16
+ export default defineComponent({
17
+ name: 'FSAutocompleteOrganisation',
18
+ components: {
19
+ FSAutocompleteField
20
+ },
21
+ props: {
22
+ organisationFilters: {
23
+ type: Object as PropType<OrganisationFilters>,
24
+ required: false,
25
+ default: null
26
+ }
27
+ },
28
+ setup(props) {
29
+ const { entities: organisations, fetching, getMany } = useOrganisations();
30
+
31
+ watch(() => props.organisationFilters, async (newValue, oldValue) => {
32
+ if (!_.isEqual(newValue, oldValue)) {
33
+ await getMany(newValue);
34
+ }
35
+ }, { immediate: true });
36
+
37
+ return {
38
+ organisations,
39
+ fetching
40
+ }
41
+ }
42
+ })
43
+ </script>
@@ -0,0 +1,49 @@
1
+ <template>
2
+ <FSAutocompleteField
3
+ :loading="fetchingTimeZones"
4
+ :items="timeZones"
5
+ v-model:search="search"
6
+ v-bind="$attrs"
7
+ />
8
+ </template>
9
+
10
+ <script lang="ts">
11
+ import { defineComponent, PropType, ref, watch } from "vue";
12
+ import _ from "lodash";
13
+
14
+ import { useTimeZones } from "@dative-gpi/foundation-shared-services/composables";
15
+ import { TimeZoneFilters } from "@dative-gpi/foundation-shared-domain/models";
16
+
17
+ import FSAutocompleteField from "../fields/FSAutocompleteField.vue";
18
+
19
+ export default defineComponent({
20
+ name: "FSAutocompleteTimeZone",
21
+ components: {
22
+ FSAutocompleteField
23
+ },
24
+ props: {
25
+ timeZoneFilters: {
26
+ type: Object as PropType<TimeZoneFilters>,
27
+ required: false,
28
+ default: null
29
+ }
30
+ },
31
+ setup(props) {
32
+ const { getMany: getManyTimeZones, fetching: fetchingTimeZones, entities: timeZones } = useTimeZones();
33
+
34
+ const search = ref<string | null>(null);
35
+
36
+ watch([() => props.timeZoneFilters, () => search.value], async (newValue, oldValue) => {
37
+ if (!_.isEqual(newValue, oldValue)) {
38
+ await getManyTimeZones({ ...props.timeZoneFilters, search: search.value ?? undefined });
39
+ }
40
+ }, { immediate: true });
41
+
42
+ return {
43
+ fetchingTimeZones,
44
+ timeZones,
45
+ search
46
+ }
47
+ }
48
+ });
49
+ </script>
@@ -1,6 +1,9 @@
1
1
  <template>
2
2
  <FSCol>
3
- <slot v-if="!$props.hideHeader" name="label">
3
+ <slot
4
+ v-if="!$props.hideHeader"
5
+ name="label"
6
+ >
4
7
  <FSRow
5
8
  :wrap="false"
6
9
  >
@@ -22,7 +25,9 @@
22
25
  >
23
26
  *
24
27
  </FSSpan>
25
- <v-spacer style="min-width: 40px;" />
28
+ <v-spacer
29
+ style="min-width: 40px;"
30
+ />
26
31
  <FSSpan
27
32
  v-if="messages.length > 0"
28
33
  class="fs-autocomplete-field-messages"
@@ -33,56 +38,93 @@
33
38
  </FSSpan>
34
39
  </FSRow>
35
40
  </slot>
36
- <v-autocomplete
37
- class="fs-autocomplete-field"
38
- variant="outlined"
39
- :menuIcon="null"
40
- :style="style"
41
- :listProps="listStyle"
42
- :class="classes"
43
- :hideDetails="true"
44
- :items="$props.items"
45
- :autoSelectFirst="true"
46
- :multiple="$props.multiple"
47
- :itemTitle="$props.itemTitle"
48
- :itemValue="$props.itemValue"
49
- :readonly="!$props.editable"
50
- :clearable="$props.editable && !!$props.modelValue"
51
- :returnObject="$props.returnObject"
52
- :rules="$props.rules"
53
- :validateOn="validateOn"
54
- :modelValue="$props.modelValue"
55
- @update:modelValue="onUpdate"
56
- @blur="blurred = true"
57
- v-model:search="innerSearch"
58
- v-bind="$attrs"
41
+ <FSLoader
42
+ v-if="$props.loading"
43
+ width="100%"
44
+ :height="['40px', '36px']"
45
+ />
46
+ <template
47
+ v-else
59
48
  >
60
- <template v-for="(_, name) in slots" v-slot:[name]="slotData">
61
- <slot :name="name" v-bind="slotData" />
62
- </template>
63
- <template #clear>
64
- <slot name="clear">
65
- <FSButton
66
- v-if="$props.editable && $props.modelValue"
67
- icon="mdi-close"
68
- variant="icon"
69
- :color="ColorEnum.Dark"
70
- @click="$emit('update:modelValue', null)"
71
- />
72
- </slot>
73
- </template>
74
- <template #append-inner>
75
- <slot name="append-inner">
76
- <FSButton
77
- icon="mdi-chevron-down"
78
- variant="icon"
79
- :editable="$props.editable"
80
- :color="ColorEnum.Dark"
49
+ <FSToggleSet
50
+ v-if="$props.toggleSet"
51
+ variant="slide"
52
+ :multiple="$props.multiple"
53
+ :values="$props.items"
54
+ :rules="$props.rules"
55
+ :modelValue="$props.modelValue"
56
+ @update:modelValue="onUpdate"
57
+ v-bind="$attrs"
58
+ />
59
+ <v-autocomplete
60
+ v-else
61
+ class="fs-autocomplete-field"
62
+ variant="outlined"
63
+ :menuIcon="null"
64
+ :style="style"
65
+ :listProps="listStyle"
66
+ :class="classes"
67
+ :hideDetails="true"
68
+ :items="$props.items"
69
+ :autoSelectFirst="true"
70
+ :multiple="$props.multiple"
71
+ :itemTitle="$props.itemTitle"
72
+ :itemValue="$props.itemValue"
73
+ :readonly="!$props.editable"
74
+ :loading="$props.loading"
75
+ :clearable="$props.editable && !!$props.modelValue"
76
+ :returnObject="$props.returnObject"
77
+ :rules="$props.rules"
78
+ :validateOn="validateOn"
79
+ :modelValue="$props.modelValue"
80
+ @update:modelValue="onUpdate"
81
+ @blur="blurred = true"
82
+ v-model:search="innerSearch"
83
+ v-bind="$attrs"
84
+ >
85
+ <template
86
+ v-for="(_, name) in slots"
87
+ v-slot:[name]="slotData"
88
+ >
89
+ <slot
90
+ :name="name"
91
+ v-bind="slotData"
81
92
  />
82
- </slot>
83
- </template>
84
- </v-autocomplete>
85
- <slot name="description">
93
+ </template>
94
+ <template
95
+ #clear
96
+ >
97
+ <slot
98
+ name="clear"
99
+ >
100
+ <FSButton
101
+ v-if="$props.editable && $props.modelValue"
102
+ icon="mdi-close"
103
+ variant="icon"
104
+ :color="ColorEnum.Dark"
105
+ @click="$emit('update:modelValue', null)"
106
+ />
107
+ </slot>
108
+ </template>
109
+ <template
110
+ #append-inner
111
+ >
112
+ <slot
113
+ name="append-inner"
114
+ >
115
+ <FSButton
116
+ icon="mdi-chevron-down"
117
+ variant="icon"
118
+ :editable="$props.editable"
119
+ :color="ColorEnum.Dark"
120
+ />
121
+ </slot>
122
+ </template>
123
+ </v-autocomplete>
124
+ </template>
125
+ <slot
126
+ name="description"
127
+ >
86
128
  <FSSpan
87
129
  v-if="$props.description"
88
130
  class="fs-autocomplete-field-description"
@@ -105,14 +147,18 @@ import FSButton from "../FSButton.vue";
105
147
  import FSSpan from "../FSSpan.vue";
106
148
  import FSCol from "../FSCol.vue";
107
149
  import FSRow from "../FSRow.vue";
150
+ import FSLoader from "../FSLoader.vue";
151
+ import FSToggleSet from "../FSToggleSet.vue";
108
152
 
109
153
  export default defineComponent({
110
154
  name: "FSAutocompleteField",
111
155
  components: {
156
+ FSToggleSet,
112
157
  FSButton,
158
+ FSLoader,
113
159
  FSSpan,
114
160
  FSCol,
115
- FSRow
161
+ FSRow,
116
162
  },
117
163
  props: {
118
164
  label: {
@@ -178,6 +224,16 @@ export default defineComponent({
178
224
  type: Boolean,
179
225
  required: false,
180
226
  default: true
227
+ },
228
+ loading: {
229
+ type: Boolean,
230
+ required: false,
231
+ default: false
232
+ },
233
+ toggleSet: {
234
+ type: Boolean,
235
+ required: false,
236
+ default: false
181
237
  }
182
238
  },
183
239
  emits: ["update:modelValue", "update:search"],
@@ -196,23 +252,23 @@ export default defineComponent({
196
252
 
197
253
  const innerSearch = ref("");
198
254
 
199
- const style = computed((): { [key: string] : string | undefined } => {
255
+ const style = computed((): { [key: string]: string | undefined } => {
200
256
  if (!props.editable) {
201
257
  return {
202
- "--fs-autocomplete-field-cursor" : "default",
203
- "--fs-autocomplete-field-border-color" : lights.base,
204
- "--fs-autocomplete-field-color" : lights.dark,
258
+ "--fs-autocomplete-field-cursor": "default",
259
+ "--fs-autocomplete-field-border-color": lights.base,
260
+ "--fs-autocomplete-field-color": lights.dark,
205
261
  "--fs-autocomplete-field-active-border-color": lights.base
206
262
  };
207
263
  }
208
264
  return {
209
- "--fs-autocomplete-field-cursor" : "text",
210
- "--fs-autocomplete-field-background-color" : backgrounds.base,
211
- "--fs-autocomplete-field-border-color" : lights.dark,
212
- "--fs-autocomplete-field-color" : darks.base,
265
+ "--fs-autocomplete-field-cursor": "text",
266
+ "--fs-autocomplete-field-background-color": backgrounds.base,
267
+ "--fs-autocomplete-field-border-color": lights.dark,
268
+ "--fs-autocomplete-field-color": darks.base,
213
269
  "--fs-autocomplete-field-active-border-color": darks.dark,
214
- "--fs-autocomplete-field-error-color" : errors.base,
215
- "--fs-autocomplete-field-error-border-color" : errors.base
270
+ "--fs-autocomplete-field-error-color": errors.base,
271
+ "--fs-autocomplete-field-error-border-color": errors.base
216
272
  };
217
273
  });
218
274
 
@@ -234,7 +290,6 @@ export default defineComponent({
234
290
 
235
291
  const onUpdate = (value: string[] | string) => {
236
292
  emit('update:modelValue', value);
237
- innerSearch.value = "";
238
293
  };
239
294
 
240
295
  watch(innerSearch, () => {
@@ -4,7 +4,9 @@
4
4
  :modelValue="menu && $props.editable"
5
5
  @update:modelValue="(value) => menu = value"
6
6
  >
7
- <template #activator="{ props }">
7
+ <template
8
+ #activator="{ props }"
9
+ >
8
10
  <FSTextField
9
11
  class="fs-date-field"
10
12
  :label="$props.label"
@@ -19,12 +21,16 @@
19
21
  :validateOn="validateOn"
20
22
  :validationValue="$props.modelValue"
21
23
  :modelValue="epochToLongDateFormat($props.modelValue)"
22
- @click:clear="onClear"
24
+ @update:modelValue="onClear"
23
25
  @blur="blurred = true"
24
26
  v-bind="props"
25
27
  >
26
- <template #prepend-inner>
27
- <slot name="prepend-inner">
28
+ <template
29
+ #prepend-inner
30
+ >
31
+ <slot
32
+ name="prepend-inner"
33
+ >
28
34
  <FSButton
29
35
  variant="icon"
30
36
  icon="mdi-calendar"
@@ -33,8 +39,14 @@
33
39
  />
34
40
  </slot>
35
41
  </template>
36
- <template v-for="(_, name) in $slots" v-slot:[name]="slotData">
37
- <slot :name="name" v-bind="slotData" />
42
+ <template
43
+ v-for="(_, name) in $slots"
44
+ v-slot:[name]="slotData"
45
+ >
46
+ <slot
47
+ :name="name"
48
+ v-bind="slotData"
49
+ />
38
50
  </template>
39
51
  </FSTextField>
40
52
  </template>
@@ -44,7 +56,9 @@
44
56
  :elevation="true"
45
57
  :border="false"
46
58
  >
47
- <FSCol width="fill">
59
+ <FSCol
60
+ width="fill"
61
+ >
48
62
  <FSCalendar
49
63
  :color="$props.color"
50
64
  v-model="innerDate"
@@ -14,11 +14,15 @@
14
14
  :validationValue="$props.modelValue"
15
15
  :modelValue="toShortDateFormat"
16
16
  @click="onClick"
17
- @click:clear="onClear"
17
+ @update:modelValue="onClear"
18
18
  @blur="blurred = true"
19
19
  >
20
- <template #prepend-inner>
21
- <slot name="prepend-inner">
20
+ <template
21
+ #prepend-inner
22
+ >
23
+ <slot
24
+ name="prepend-inner"
25
+ >
22
26
  <FSButton
23
27
  variant="icon"
24
28
  icon="mdi-calendar"
@@ -27,8 +31,14 @@
27
31
  />
28
32
  </slot>
29
33
  </template>
30
- <template v-for="(_, name) in $slots" v-slot:[name]="slotData">
31
- <slot :name="name" v-bind="slotData" />
34
+ <template
35
+ v-for="(_, name) in $slots"
36
+ v-slot:[name]="slotData"
37
+ >
38
+ <slot
39
+ :name="name"
40
+ v-bind="slotData"
41
+ />
32
42
  </template>
33
43
  </FSTextField>
34
44
  <FSDialogSubmit
@@ -37,7 +47,9 @@
37
47
  @click:rightButton="onSubmit"
38
48
  v-model="dialog"
39
49
  >
40
- <template #body>
50
+ <template
51
+ #body
52
+ >
41
53
  <FSCalendarTwin
42
54
  :color="$props.color"
43
55
  v-model="innerDateRange"
@@ -4,7 +4,9 @@
4
4
  :modelValue="menu && $props.editable"
5
5
  @update:modelValue="(value) => menu = value"
6
6
  >
7
- <template #activator="{ props }">
7
+ <template
8
+ #activator="{ props }"
9
+ >
8
10
  <FSTextField
9
11
  class="fs-date-field"
10
12
  :label="$props.label"
@@ -19,12 +21,16 @@
19
21
  :validateOn="validateOn"
20
22
  :validationValue="$props.modelValue"
21
23
  :modelValue="epochToLongTimeFormat($props.modelValue)"
22
- @click:clear="onClear"
24
+ @update:modelValue="onClear"
23
25
  @blur="blurred = true"
24
26
  v-bind="props"
25
27
  >
26
- <template #prepend-inner>
27
- <slot name="prepend-inner">
28
+ <template
29
+ #prepend-inner
30
+ >
31
+ <slot
32
+ name="prepend-inner"
33
+ >
28
34
  <FSButton
29
35
  variant="icon"
30
36
  icon="mdi-calendar"
@@ -33,8 +39,14 @@
33
39
  />
34
40
  </slot>
35
41
  </template>
36
- <template v-for="(_, name) in $slots" v-slot:[name]="slotData">
37
- <slot :name="name" v-bind="slotData" />
42
+ <template
43
+ v-for="(_, name) in $slots"
44
+ v-slot:[name]="slotData"
45
+ >
46
+ <slot
47
+ :name="name"
48
+ v-bind="slotData"
49
+ />
38
50
  </template>
39
51
  </FSTextField>
40
52
  </template>
@@ -48,7 +60,9 @@
48
60
  :border="false"
49
61
  :value="0"
50
62
  >
51
- <FSCol width="fill">
63
+ <FSCol
64
+ width="fill"
65
+ >
52
66
  <FSCalendar
53
67
  :color="$props.color"
54
68
  v-model="innerDate"
@@ -68,7 +82,9 @@
68
82
  :border="false"
69
83
  :value="1"
70
84
  >
71
- <FSCol width="fill">
85
+ <FSCol
86
+ width="fill"
87
+ >
72
88
  <FSClock
73
89
  :color="$props.color"
74
90
  v-model="innerTime"
@@ -14,11 +14,15 @@
14
14
  :validationValue="$props.modelValue"
15
15
  :modelValue="toShortTimeFormat"
16
16
  @click="onClick"
17
- @click:clear="onClear"
17
+ @update:modelValue="onClear"
18
18
  @blur="blurred = true"
19
19
  >
20
- <template #prepend-inner>
21
- <slot name="prepend-inner">
20
+ <template
21
+ #prepend-inner
22
+ >
23
+ <slot
24
+ name="prepend-inner"
25
+ >
22
26
  <FSButton
23
27
  variant="icon"
24
28
  icon="mdi-calendar"
@@ -27,8 +31,14 @@
27
31
  />
28
32
  </slot>
29
33
  </template>
30
- <template v-for="(_, name) in $slots" v-slot:[name]="slotData">
31
- <slot :name="name" v-bind="slotData" />
34
+ <template
35
+ v-for="(_, name) in $slots"
36
+ v-slot:[name]="slotData"
37
+ >
38
+ <slot
39
+ :name="name"
40
+ v-bind="slotData"
41
+ />
32
42
  </template>
33
43
  </FSTextField>
34
44
  <FSDialogSubmit
@@ -37,7 +47,9 @@
37
47
  @click:rightButton="onSubmit"
38
48
  v-model="dialog"
39
49
  >
40
- <template #body>
50
+ <template
51
+ #body
52
+ >
41
53
  <FSCol>
42
54
  <FSCalendarTwin
43
55
  :color="$props.color"
@@ -163,11 +175,13 @@ export default defineComponent({
163
175
  case 1: {
164
176
  innerTimeLeft.value = Math.floor((props.modelValue[0] + getUserOffsetMillis()) % (24 * 60 * 60 * 1000));
165
177
  innerDateRange.value = [props.modelValue[0] - innerTimeLeft.value];
178
+ break;
166
179
  }
167
180
  default: {
168
181
  innerTimeLeft.value = Math.floor((props.modelValue[0] + getUserOffsetMillis()) % (24 * 60 * 60 * 1000));
169
182
  innerTimeRight.value = Math.floor((props.modelValue[1] + getUserOffsetMillis()) % (24 * 60 * 60 * 1000));
170
183
  innerDateRange.value = [props.modelValue[0] - innerTimeLeft.value, props.modelValue[1] - innerTimeRight.value];
184
+ break;
171
185
  }
172
186
  }
173
187
  }
@@ -1,6 +1,9 @@
1
1
  <template>
2
2
  <FSCol>
3
- <slot v-if="!$props.hideHeader" name="label">
3
+ <slot
4
+ v-if="!$props.hideHeader"
5
+ name="label"
6
+ >
4
7
  <FSRow
5
8
  :wrap="false"
6
9
  >
@@ -22,7 +25,9 @@
22
25
  >
23
26
  *
24
27
  </FSSpan>
25
- <v-spacer style="min-width: 40px;" />
28
+ <v-spacer
29
+ style="min-width: 40px;"
30
+ />
26
31
  <FSSpan
27
32
  v-if="messages.length > 0"
28
33
  class="fs-text-field-messages"
@@ -48,10 +53,18 @@
48
53
  @blur="blurred = true"
49
54
  v-bind="$attrs"
50
55
  >
51
- <template v-for="(_, name) in slots" v-slot:[name]="slotData">
52
- <slot :name="name" v-bind="slotData" />
56
+ <template
57
+ v-for="(_, name) in slots"
58
+ v-slot:[name]="slotData"
59
+ >
60
+ <slot
61
+ :name="name"
62
+ v-bind="slotData"
63
+ />
53
64
  </template>
54
- <template #clear>
65
+ <template
66
+ #clear
67
+ >
55
68
  <FSButton
56
69
  v-if="$props.editable && $props.modelValue"
57
70
  icon="mdi-close"
@@ -61,7 +74,9 @@
61
74
  />
62
75
  </template>
63
76
  </v-text-field>
64
- <slot name="description">
77
+ <slot
78
+ name="description"
79
+ >
65
80
  <FSSpan
66
81
  v-if="$props.description"
67
82
  class="fs-text-field-description"
@@ -420,7 +420,7 @@
420
420
  v-bind="props"
421
421
  >
422
422
  <FSSpan
423
- :key="index"
423
+ font="text-overline"
424
424
  >
425
425
  {{ props.item[item.value] }}
426
426
  </FSSpan>
@@ -569,11 +569,11 @@
569
569
  :name="item.slotName"
570
570
  v-bind="props"
571
571
  >
572
- <FSText
573
- :key="index"
572
+ <FSSpan
573
+ font="text-overline"
574
574
  >
575
575
  {{ props.item[item.value] }}
576
- </FSText>
576
+ </FSSpan>
577
577
  </slot>
578
578
  </template>
579
579
  <template
@@ -1,3 +1,4 @@
1
+ export * from "./useAutocomplete";
1
2
  export * from "./useBreakpoints";
2
3
  export * from "./useColors";
3
4
  export * from "./useDebounce";
@@ -0,0 +1,81 @@
1
+ import { computed, onMounted, ref, Ref, watch } from "vue";
2
+ import _ from "lodash";
3
+
4
+ import { useDebounce } from "./useDebounce";
5
+
6
+ export const useAutocomplete = <TInfos>(
7
+ entities: Ref<TInfos[]>,
8
+ filters: (() => any)[],
9
+ emit: (event: "update:modelValue", value: string[] | string | null) => void,
10
+ customFetch: (search: string | null) => Promise<any>,
11
+ customUpdate: ((item: TInfos[] | TInfos | null) => void) | null = null,
12
+ toId: (item: TInfos) => string | null = (item: TInfos) => (item as any).id,
13
+ toText: (item: TInfos) => string | null = (item: TInfos) => (item as any).label,
14
+ fetchOnSearch: boolean = false,
15
+ allowToggleSet: boolean = true,
16
+ breakpointToggleSet: number = 5,
17
+ debounceInterval: number = 1000
18
+ ) => {
19
+ const { debounce } = useDebounce();
20
+
21
+ const search = ref<string | null>(null);
22
+ const entitiesLength = ref(0);
23
+ const init = ref(true);
24
+
25
+ const toggleSet = computed((): boolean => {
26
+ console.log(allowToggleSet, entitiesLength.value, breakpointToggleSet);
27
+ return allowToggleSet && entitiesLength.value < breakpointToggleSet;
28
+ });
29
+
30
+ const debouncedFetch = () => debounce(() => customFetch(search.value), debounceInterval);
31
+
32
+ const onUpdate = (value: string[] | string | null) => {
33
+ if (customUpdate) {
34
+ if (Array.isArray(value)) {
35
+ const items = value.map(v => entities.value.find(e => toId(e) === v) || null).filter(e => e !== null) as TInfos[];
36
+ customUpdate(items);
37
+ }
38
+ else {
39
+ customUpdate((value && entities.value.find(e => toId(e) === value)) || null);
40
+ }
41
+ }
42
+ else {
43
+ emit("update:modelValue", value);
44
+ }
45
+ };
46
+
47
+ watch(filters, (newValue, oldValue) => {
48
+ if (!_.isEqual(newValue, oldValue)) {
49
+ debouncedFetch();
50
+ }
51
+ });
52
+
53
+ watch(search, (newValue, oldValue) => {
54
+ if (newValue !== oldValue) {
55
+ const found = entities.value.map(e => toText(e)).includes(search.value);
56
+ if (!found && (!search.value || !search.value.length || search.value.length > 2)) {
57
+ if (fetchOnSearch) {
58
+ debouncedFetch();
59
+ }
60
+ }
61
+ }
62
+ });
63
+
64
+ watch(entities, () => {
65
+ if (init.value) {
66
+ init.value = false;
67
+ entitiesLength.value = entities.value.length;
68
+ }
69
+ });
70
+
71
+ onMounted((): void => {
72
+ customFetch(search.value);
73
+ });
74
+
75
+ return {
76
+ toggleSet,
77
+ search,
78
+ init,
79
+ onUpdate
80
+ };
81
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dative-gpi/foundation-shared-components",
3
3
  "sideEffects": false,
4
- "version": "0.0.82",
4
+ "version": "0.0.84",
5
5
  "description": "",
6
6
  "publishConfig": {
7
7
  "access": "public"
@@ -10,8 +10,8 @@
10
10
  "author": "",
11
11
  "license": "ISC",
12
12
  "dependencies": {
13
- "@dative-gpi/foundation-shared-domain": "0.0.82",
14
- "@dative-gpi/foundation-shared-services": "0.0.82",
13
+ "@dative-gpi/foundation-shared-domain": "0.0.84",
14
+ "@dative-gpi/foundation-shared-services": "0.0.84",
15
15
  "@fontsource/montserrat": "^5.0.16",
16
16
  "@lexical/clipboard": "^0.12.5",
17
17
  "@lexical/history": "^0.12.5",
@@ -32,5 +32,5 @@
32
32
  "sass": "^1.69.5",
33
33
  "sass-loader": "^13.3.2"
34
34
  },
35
- "gitHead": "141bace76ddc3dd2c520076bc636a67edb87f49e"
35
+ "gitHead": "3e92b90afe656cd7aaa98a0a73c014de059a4296"
36
36
  }
@@ -4,7 +4,7 @@
4
4
  flex: 1 0 0;
5
5
 
6
6
  & > .fs-col > .fs-row:first-of-type > :last-child {
7
- padding-right: 22px;
7
+ padding-right: 32px;
8
8
  }
9
9
  }
10
10
 
@@ -0,0 +1,4 @@
1
+ .fs-toggle-set > .v-input__control > .v-slide-group {
2
+ height: calc(100% + 0.4px);
3
+ width: calc(100% + 0.4px);
4
+ }
@@ -55,6 +55,7 @@
55
55
  @import "fs_tile.scss";
56
56
  @import "fs_time_field.scss";
57
57
  @import "fs_timeslot_field.scss";
58
+ @import "fs_toggle_set.scss";
58
59
  @import "fs_tooltip.scss";
59
60
  @import "fs_window.scss";
60
61
  @import "fs_wrap_group.scss";
@@ -142,6 +142,8 @@ $nthOverlay: 25;
142
142
  color: var(--fs-group-hover-color);
143
143
  }
144
144
 
145
+ /***************************************************************************/
146
+
145
147
  // Badges are totally overriden
146
148
  .v-badge__badge {
147
149
  align-items: center !important;
@@ -152,5 +154,3 @@ $nthOverlay: 25;
152
154
  min-width: 16px !important;
153
155
  height: 16px !important;
154
156
  }
155
-
156
- /***************************************************************************/