@dative-gpi/foundation-shared-components 0.0.220 → 0.0.222

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.
@@ -0,0 +1,231 @@
1
+ <template>
2
+ <FSWindow
3
+ width="100%"
4
+ :modelValue="currentStep - 1"
5
+ >
6
+ <FSForm
7
+ v-for="(step, index) in $props.steps"
8
+ :variant="$props.variant"
9
+ :key="index"
10
+ @submit="onSubmit"
11
+ v-model="valid"
12
+ >
13
+ <FSCol
14
+ gap="24px"
15
+ >
16
+ <FSFadeOut
17
+ :height="height"
18
+ padding="0 8px 0 0"
19
+ >
20
+ <slot
21
+ :name="`step-${step}`"
22
+ />
23
+ </FSFadeOut>
24
+ <FSRow
25
+ padding="0 16px 0 0"
26
+ >
27
+ <slot
28
+ name="left-footer"
29
+ />
30
+ <FSRow
31
+ class="fs-dialog-actions"
32
+ align="top-right"
33
+ :wrap="false"
34
+ >
35
+ <FSButton
36
+ :prependIcon="$props.cancelButtonPrependIcon"
37
+ :appendIcon="$props.cancelButtonAppendIcon"
38
+ :variant="$props.cancelButtonVariant"
39
+ :color="$props.cancelButtonColor"
40
+ :label="previousButtonLabel"
41
+ @click="onPrevious()"
42
+ />
43
+ <FSButton
44
+ type="submit"
45
+ :prependIcon="$props.submitButtonPrependIcon"
46
+ :appendIcon="$props.submitButtonAppendIcon"
47
+ :color="$props.submitButtonColor"
48
+ :variant="nextButtonVariant"
49
+ :editable="$props.editable"
50
+ :label="nextButtonLabel"
51
+ :load="$props.load"
52
+ />
53
+ </FSRow>
54
+ </FSRow>
55
+ </FSCol>
56
+ </FSForm>
57
+ </FSWindow>
58
+ </template>
59
+
60
+ <script lang="ts">
61
+ import { computed, defineComponent, type PropType, ref } from "vue";
62
+
63
+ import { useTranslations as useTranslationsProvider } from "@dative-gpi/bones-ui/composables";
64
+ import { type ColorBase, ColorEnum } from "@dative-gpi/foundation-shared-components/models";
65
+ import { useBreakpoints } from "@dative-gpi/foundation-shared-components/composables";
66
+
67
+ import FSFadeOut from "./FSFadeOut.vue";
68
+ import FSButton from "./FSButton.vue";
69
+ import FSForm from "./FSForm.vue";
70
+ import FSRow from "./FSRow.vue";
71
+
72
+ export default defineComponent({
73
+ name: "FSDialogMultiFormBody",
74
+ components: {
75
+ FSFadeOut,
76
+ FSButton,
77
+ FSForm,
78
+ FSRow
79
+ },
80
+ props: {
81
+ subtitle: {
82
+ type: String as PropType<string | null>,
83
+ required: false,
84
+ default: null
85
+ },
86
+ width: {
87
+ type: [Array, String, Number] as PropType<"hug" | "fill" | string[] | number[] | string | number | null>,
88
+ required: false,
89
+ default: "auto"
90
+ },
91
+ variant: {
92
+ type: String as PropType<"standard" | "submit">,
93
+ required: false,
94
+ default: "submit"
95
+ },
96
+ steps: {
97
+ type: Number,
98
+ required: true
99
+ },
100
+ cancelButtonPrependIcon: {
101
+ type: String as PropType<string | null>,
102
+ required: false,
103
+ default: null
104
+ },
105
+ cancelButtonLabel: {
106
+ type: String as PropType<string | null>,
107
+ required: false,
108
+ default: null
109
+ },
110
+ cancelButtonAppendIcon: {
111
+ type: String as PropType<string | null>,
112
+ required: false,
113
+ default: null
114
+ },
115
+ cancelButtonVariant: {
116
+ type: String as PropType<"standard" | "full" | "icon">,
117
+ required: false,
118
+ default: "standard"
119
+ },
120
+ cancelButtonColor: {
121
+ type: String as PropType<ColorBase>,
122
+ required: false,
123
+ default: ColorEnum.Light
124
+ },
125
+ submitButtonPrependIcon: {
126
+ type: String as PropType<string | null>,
127
+ required: false,
128
+ default: null
129
+ },
130
+ submitButtonLabel: {
131
+ type: String as PropType<string | null>,
132
+ required: false,
133
+ default: null
134
+ },
135
+ submitButtonAppendIcon: {
136
+ type: String as PropType<string | null>,
137
+ required: false,
138
+ default: null
139
+ },
140
+ submitButtonVariant: {
141
+ type: String as PropType<"standard" | "full" | "icon">,
142
+ required: false,
143
+ default: "full"
144
+ },
145
+ submitButtonColor: {
146
+ type: String as PropType<ColorBase>,
147
+ required: false,
148
+ default: ColorEnum.Primary
149
+ },
150
+ load: {
151
+ type: Boolean,
152
+ required: false,
153
+ default: false
154
+ },
155
+ editable: {
156
+ type: Boolean,
157
+ required: false,
158
+ default: true
159
+ }
160
+ },
161
+ emits: ["click:cancelButton", "click:submitButton"],
162
+ setup(props, { emit }) {
163
+ const { isMobileSized } = useBreakpoints();
164
+ const { $tr } = useTranslationsProvider();
165
+
166
+ const currentStep = ref(1);
167
+ const valid = ref(false);
168
+ const valids = ref(Array.from({ length: props.steps }, () => false));
169
+
170
+ const height = computed(() => {
171
+ const other = 24 + 24 // Paddings
172
+ + (isMobileSized.value ? 24 : 32) + 24 // Title
173
+ + (props.subtitle ? (isMobileSized.value ? 14 : 16) + 8 : 0) // Subtitle
174
+ + (isMobileSized.value ? 36 : 40) + 24; // Footer
175
+ return `calc(100vh - 40px - ${other}px)`;
176
+ });
177
+
178
+ const previousButtonLabel = computed(() => {
179
+ return currentStep.value == 1
180
+ ? props.cancelButtonLabel ?? $tr("ui.button.cancel", "Cancel")
181
+ : $tr("ui.button.back", "Back");
182
+ });
183
+
184
+ const nextButtonLabel = computed(() => {
185
+ return currentStep.value == props.steps
186
+ ? props.submitButtonLabel ?? $tr("ui.button.validate", "Validate")
187
+ : $tr("ui.button.next", "Next");
188
+ });
189
+
190
+ const nextButtonVariant = computed(() => {
191
+ return currentStep.value == props.steps
192
+ ? props.submitButtonVariant ?? "full" : "standard";
193
+ });
194
+
195
+ const onPrevious = () => {
196
+ if (currentStep.value > 1) {
197
+ currentStep.value--;
198
+ }
199
+ else {
200
+ emit("click:cancelButton");
201
+ }
202
+ };
203
+
204
+ const onSubmit = () => {
205
+ if (valid.value) {
206
+ switch (currentStep.value) {
207
+ case props.steps:
208
+ emit("click:submitButton");
209
+ break;
210
+ default:
211
+ currentStep.value++;
212
+ break;
213
+ }
214
+ }
215
+ };
216
+
217
+ return {
218
+ previousButtonLabel,
219
+ nextButtonVariant,
220
+ nextButtonLabel,
221
+ currentStep,
222
+ ColorEnum,
223
+ height,
224
+ valids,
225
+ valid,
226
+ onPrevious,
227
+ onSubmit
228
+ };
229
+ }
230
+ });
231
+ </script>
@@ -0,0 +1,129 @@
1
+ <template>
2
+ <FSCol>
3
+ <FSAutocompleteField
4
+ v-if="variant=='standard'"
5
+ :label="label"
6
+ :items="innerItems"
7
+ :multiple="true"
8
+ :modelValue="modelValue"
9
+ @update:modelValue="$emit('update:modelValue', $event)"
10
+ @keydown="onKeydown"
11
+ v-binds="$attrs"
12
+ >
13
+ <template
14
+ #autocomplete-chip
15
+ >
16
+ </template>
17
+ </FSAutocompleteField>
18
+ <FSAutocompleteField
19
+ v-else
20
+ :label="label"
21
+ :items="innerItems"
22
+ :multiple="true"
23
+ :modelValue="modelValue"
24
+ :showSearch="true"
25
+ @update:modelValue="$emit('update:modelValue', $event)"
26
+ @add:item="onAddItem"
27
+ @keydown="onKeydown"
28
+ v-binds="$attrs"
29
+ >
30
+ <template
31
+ #autocomplete-chip
32
+ >
33
+ </template>
34
+ </FSAutocompleteField>
35
+ <FSTagGroup
36
+ v-if="modelValue != null"
37
+ :tags="innerItems.filter(i=>modelValue && modelValue.includes(i.id)).map(i=>i.label) ?? []"
38
+ @remove="onRemoveValue($event)"
39
+ />
40
+ </FSCol>
41
+ </template>
42
+
43
+ <script lang="ts">
44
+ import { computed, defineComponent, type PropType, ref, watch } from "vue";
45
+
46
+ import { uuidv4 } from '@dative-gpi/bones-ui';
47
+
48
+ import FSAutocompleteField from "../fields/FSAutocompleteField.vue";
49
+ import FSTagGroup from "../FSTagGroup.vue";
50
+
51
+ export default defineComponent({
52
+ components: {
53
+ FSAutocompleteField,
54
+ FSTagGroup,
55
+ },
56
+ props:{
57
+ modelValue: {
58
+ type: Array as PropType<string[] | null>,
59
+ required: false,
60
+ default: () => []
61
+ },
62
+ items: {
63
+ type: Array as PropType<{id : string, label : string}[]>,
64
+ required: false,
65
+ default: () => []
66
+ },
67
+ label : {
68
+ type: String,
69
+ required: false
70
+ },
71
+ variant: {
72
+ type: String as PropType<'standard' | 'tagged'>,
73
+ required: false,
74
+ default : 'standard'
75
+ }
76
+ },
77
+ emits: ["update:modelValue"],
78
+ setup(props, {emit}) {
79
+ const tagValues = ref<{id : string, label : string}[]>([]);
80
+
81
+ const innerItems = computed(() => {
82
+ if (props.variant === 'standard') {
83
+ return props.items
84
+ }
85
+ else {
86
+ return props.items.concat(tagValues.value.filter(t=>props.modelValue?.includes(t.id)) ?? []);
87
+ }
88
+ });
89
+
90
+ const onRemoveValue = (value: string) => {
91
+ const idValue = innerItems.value.find((v) => v.label === value)?.id;
92
+ if (idValue) {
93
+ if (tagValues.value.map((v) => v.label).includes(value)) {
94
+ tagValues.value = tagValues.value.filter((v) => v.label !== value);
95
+ }
96
+ emit('update:modelValue', [...props.modelValue?.filter((v) => v !== idValue) ?? []]);
97
+ }
98
+ };
99
+
100
+ const onAddItem = (value: string) => {
101
+ if (innerItems.value.map((v) => v.label).includes(value)) {
102
+ return;
103
+ }
104
+ let item = {id: uuidv4(), label: value};
105
+ tagValues.value.push(item);
106
+ emit('update:modelValue', [...props.modelValue ?? [], ...[item.id]]);
107
+ };
108
+
109
+ const onKeydown = (event: KeyboardEvent) => {
110
+ if (event.key === 'Backspace') {
111
+ emit('update:modelValue', [...props.modelValue ?? []]);
112
+ }
113
+ };
114
+
115
+ watch(() => props.modelValue, () => {
116
+ if (props.modelValue) {
117
+ tagValues.value = tagValues.value.filter((v) => props.modelValue!.includes(v.id));
118
+ }
119
+ }, {immediate: true});
120
+
121
+ return {
122
+ innerItems,
123
+ onRemoveValue,
124
+ onAddItem,
125
+ onKeydown
126
+ };
127
+ }
128
+ });
129
+ </script>
@@ -278,6 +278,18 @@
278
278
  #no-data
279
279
  >
280
280
  <FSRow
281
+ v-if="showSearch"
282
+ padding="17px"
283
+ >
284
+ <FSButton
285
+ variant="icon"
286
+ :label="$tr('ui.common.add', 'Add this item')"
287
+ :color="ColorEnum.Primary"
288
+ @click="$emit('add:item', search)"
289
+ />
290
+ </FSRow>
291
+ <FSRow
292
+ v-else
281
293
  padding="17px"
282
294
  >
283
295
  <FSSpan>
@@ -293,7 +305,7 @@
293
305
 
294
306
  <script lang="ts">
295
307
  import type { PropType} from "vue";
296
- import { computed, defineComponent, ref, watch } from "vue";
308
+ import { computed, defineComponent, ref } from "vue";
297
309
 
298
310
  import { useBreakpoints, useColors, useRules, useSlots } from "@dative-gpi/foundation-shared-components/composables";
299
311
  import { ColorEnum } from "@dative-gpi/foundation-shared-components/models";
@@ -404,9 +416,14 @@ export default defineComponent({
404
416
  type: Boolean,
405
417
  required: false,
406
418
  default: false
419
+ },
420
+ showSearch: {
421
+ type: Boolean,
422
+ required: false,
423
+ default: false
407
424
  }
408
425
  },
409
- emits: ["update:modelValue", "update:search"],
426
+ emits: ["update:modelValue", "update:search", "add:item"],
410
427
  setup: (props, { emit }) => {
411
428
  const { isExtraSmall, isMobileSized } = useBreakpoints();
412
429
  const { validateOn, getMessages } = useRules();
@@ -434,13 +451,14 @@ export default defineComponent({
434
451
  };
435
452
  }
436
453
  return {
437
- "--fs-autocomplete-field-cursor": "text",
438
- "--fs-autocomplete-field-background-color": backgrounds.base,
439
- "--fs-autocomplete-field-border-color": lights.dark,
440
- "--fs-autocomplete-field-color": darks.base,
441
- "--fs-autocomplete-field-active-border-color": darks.dark,
442
- "--fs-autocomplete-field-error-color": errors.base,
443
- "--fs-autocomplete-field-error-border-color": errors.base
454
+ "--fs-autocomplete-field-cursor": "text",
455
+ "--fs-autocomplete-field-background-color": backgrounds.base,
456
+ "--fs-autocomplete-field-no-data-background-color": lights.light,
457
+ "--fs-autocomplete-field-border-color": lights.dark,
458
+ "--fs-autocomplete-field-color": darks.base,
459
+ "--fs-autocomplete-field-active-border-color": darks.dark,
460
+ "--fs-autocomplete-field-error-color": errors.base,
461
+ "--fs-autocomplete-field-error-border-color": errors.base
444
462
  };
445
463
  });
446
464
 
@@ -576,19 +594,10 @@ export default defineComponent({
576
594
 
577
595
  const onClick = () => {
578
596
  if (props.modelValue && !props.multiple) {
579
- search.value = "";
580
- emit("update:search", search.value);
581
- emit("update:modelValue", null);
582
- }
597
+ search.value="";
598
+ }
583
599
  };
584
600
 
585
- watch(search, () => {
586
- emit("update:search", search.value);
587
- if (props.modelValue && search.value && !props.multiple) {
588
- emit("update:modelValue", null);
589
- }
590
- });
591
-
592
601
  return {
593
602
  mobileSelectionProps,
594
603
  autocompleteSlots,
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.220",
4
+ "version": "0.0.222",
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.220",
14
- "@dative-gpi/foundation-shared-services": "0.0.220"
13
+ "@dative-gpi/foundation-shared-domain": "0.0.222",
14
+ "@dative-gpi/foundation-shared-services": "0.0.222"
15
15
  },
16
16
  "peerDependencies": {
17
17
  "@dative-gpi/bones-ui": "^0.0.75",
@@ -35,5 +35,5 @@
35
35
  "sass": "1.71.1",
36
36
  "sass-loader": "13.3.2"
37
37
  },
38
- "gitHead": "5386c0eed28a035ac9da6a8a00ba7681bc86f942"
38
+ "gitHead": "84398c44d065b454974c48e07f494d6e2c73690a"
39
39
  }