@dative-gpi/foundation-shared-components 1.0.34 → 1.0.36

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.
@@ -20,45 +20,66 @@
20
20
  <template
21
21
  v-if="isExtraSmall"
22
22
  >
23
- <FSTextField
24
- :validationValue="$props.modelValue"
25
- :description="$props.description"
26
- :hideHeader="$props.hideHeader"
27
- :clearable="$props.clearable"
28
- :editable="$props.editable"
29
- :required="$props.required"
30
- :label="$props.label"
31
- :rules="$props.rules"
32
- :messages="messages"
33
- :readonly="true"
34
- :modelValue="mobileValue"
35
- @update:modelValue="$emit('update:modelValue', $event)"
36
- @click="openMobileOverlay"
37
- v-bind="$attrs"
38
- >
39
- <template
40
- v-for="(_, name) in $slots"
41
- v-slot:[name]="slotData"
42
- >
43
- <slot
44
- :name="name"
45
- v-bind="slotData"
46
- />
47
- </template>
48
- <template
49
- v-if="mobileSelectionProps"
50
- #prepend-inner
51
- >
52
- <slot
53
- name="selection-mobile"
54
- v-bind="mobileSelectionProps"
55
- />
56
- </template>
57
- <template
58
- #append-inner
23
+ <FSCol>
24
+ <FSTextField
25
+ :validationValue="$props.modelValue"
26
+ :description="$props.description"
27
+ :hideHeader="$props.hideHeader"
28
+ :clearable="$props.clearable"
29
+ :editable="$props.editable"
30
+ :required="$props.required"
31
+ :label="$props.label"
32
+ :rules="$props.rules"
33
+ :messages="messages"
34
+ :readonly="true"
35
+ :modelValue="mobileValue"
36
+ @click="openMobileOverlay"
37
+ v-bind="$attrs"
59
38
  >
60
- <slot
61
- name="append-inner"
39
+ <template
40
+ v-for="(_, name) in $slots"
41
+ v-slot:[name]="slotData"
42
+ >
43
+ <slot
44
+ :name="name"
45
+ v-bind="slotData"
46
+ />
47
+ </template>
48
+ <template
49
+ #prepend-inner
50
+ >
51
+ <slot
52
+ v-if="selectedItem"
53
+ name="item-prepend"
54
+ v-bind="{ item: selectedItem }"
55
+ />
56
+ </template>
57
+ <template
58
+ #clear
59
+ >
60
+ <FSRow
61
+ :wrap="false"
62
+ >
63
+ <slot
64
+ v-if="selectedItem"
65
+ name="item-append"
66
+ v-bind="{ item: selectedItem }"
67
+ />
68
+ <slot
69
+ name="clear"
70
+ >
71
+ <FSButton
72
+ v-if="$props.clearable && $props.editable && !!$props.modelValue"
73
+ icon="mdi-close"
74
+ variant="icon"
75
+ :color="ColorEnum.Dark"
76
+ @click="$emit('update:modelValue', null)"
77
+ />
78
+ </slot>
79
+ </FSRow>
80
+ </template>
81
+ <template
82
+ #append-inner
62
83
  >
63
84
  <FSButton
64
85
  icon="mdi-chevron-down"
@@ -67,9 +88,45 @@
67
88
  :color="ColorEnum.Dark"
68
89
  @click="openMobileOverlay"
69
90
  />
70
- </slot>
71
- </template>
72
- </FSTextField>
91
+ </template>
92
+ </FSTextField>
93
+ <FSSlideGroup
94
+ v-if="$props.multiple && Array.isArray($props.modelValue)"
95
+ >
96
+ <FSCard
97
+ v-for="(item, index) in $props.items.filter((item: any) => $props.modelValue.includes(item[$props.itemValue!]))"
98
+ variant="standard"
99
+ :height="['40px', '36px']"
100
+ :color="ColorEnum.Light"
101
+ :border="false"
102
+ :key="index"
103
+ >
104
+ <FSRow
105
+ align="center-left"
106
+ padding="0 8px"
107
+ :wrap="false"
108
+ >
109
+ <slot
110
+ name="item-prepend"
111
+ v-bind="{ item }"
112
+ />
113
+ <FSSpan>
114
+ {{ item[$props.itemTitle!] }}
115
+ </FSSpan>
116
+ <slot
117
+ name="item-append"
118
+ v-bind="{ item }"
119
+ />
120
+ <FSButton
121
+ icon="mdi-close"
122
+ variant="icon"
123
+ :color="ColorEnum.Dark"
124
+ @click="() => onCheckboxChange(item[$props.itemValue!])"
125
+ />
126
+ </FSRow>
127
+ </FSCard>
128
+ </FSSlideGroup>
129
+ </FSCol>
73
130
  <FSDialogMenu
74
131
  v-model="dialog"
75
132
  >
@@ -84,7 +141,6 @@
84
141
  :maxHeight="maxHeight"
85
142
  >
86
143
  <FSCol
87
- v-if="$props.multiple"
88
144
  gap="12px"
89
145
  >
90
146
  <FSRow
@@ -92,40 +148,89 @@
92
148
  :key="index"
93
149
  >
94
150
  <FSCheckbox
95
- :label="item[$props.itemTitle]"
151
+ v-if="$props.multiple"
152
+ :label="item[$props.itemTitle!]"
96
153
  :editable="$props.editable"
97
- :modelValue="$props.modelValue?.includes(item[$props.itemValue])"
98
- @update:modelValue="() => onCheckboxChange(item[$props.itemValue])"
154
+ :modelValue="$props.modelValue?.includes(item[$props.itemValue!])"
155
+ @update:modelValue="() => onCheckboxChange(item[$props.itemValue!])"
99
156
  >
100
157
  <template
101
158
  #label="{ font }"
102
159
  >
103
- <slot
104
- name="item-label"
105
- v-bind="mobileItemProps(item, font)"
106
- />
160
+ <FSRow
161
+ align="center-left"
162
+ :wrap="false"
163
+ >
164
+ <slot
165
+ name="item-prepend"
166
+ v-bind="{ item }"
167
+ />
168
+ <FSSpan
169
+ :font="font"
170
+ >
171
+ {{ item[$props.itemTitle!] }}
172
+ </FSSpan>
173
+ </FSRow>
107
174
  </template>
108
175
  </FSCheckbox>
176
+ <FSRadio
177
+ v-else
178
+ :selected="$props.modelValue === item[$props.itemValue!]"
179
+ :label="item[$props.itemTitle!]"
180
+ :editable="$props.editable"
181
+ :item="item"
182
+ :modelValue="item[$props.itemValue!]"
183
+ @update:modelValue="() => onRadioChange(item[$props.itemValue!])"
184
+ >
185
+ <template
186
+ #label="{ font }"
187
+ >
188
+ <FSRow
189
+ align="center-left"
190
+ :wrap="false"
191
+ >
192
+ <slot
193
+ name="item-prepend"
194
+ v-bind="{ item }"
195
+ />
196
+ <FSSpan
197
+ :font="font"
198
+ >
199
+ {{ item[$props.itemTitle!] }}
200
+ </FSSpan>
201
+ </FSRow>
202
+ </template>
203
+ </FSRadio>
204
+ <FSRow
205
+ align="center-right"
206
+ >
207
+ <slot
208
+ name="item-append"
209
+ v-bind="{ item }"
210
+ />
211
+ </FSRow>
109
212
  </FSRow>
110
213
  </FSCol>
111
- <FSRadioGroup
112
- v-else
113
- gap="12px"
114
- :values="searchItems.map((item: any) => ({ value: item[$props.itemValue], label: item[$props.itemTitle], item: item }))"
115
- :editable="$props.editable"
116
- :modelValue="$props.modelValue"
117
- @update:modelValue="onRadioChange"
118
- >
119
- <template
120
- #label="{ item, font }"
121
- >
122
- <slot
123
- name="item-label"
124
- v-bind="mobileItemProps(item, font)"
125
- />
126
- </template>
127
- </FSRadioGroup>
128
214
  </FSFadeOut>
215
+ <FSRow
216
+ v-if="allowAddItem"
217
+ padding="4px 3px"
218
+ >
219
+ <FSButton
220
+ variant="icon"
221
+ :label="$tr('ui.autocomplete.add-item', 'Add new item')"
222
+ :color="ColorEnum.Primary"
223
+ @click="$emit('add:item', search)"
224
+ />
225
+ </FSRow>
226
+ <FSRow
227
+ v-if="!allowAddItem && searchItems.length === 0"
228
+ padding="4px 3px"
229
+ >
230
+ <FSSpan>
231
+ {{ $tr("ui.common.no-data", "No data") }}
232
+ </FSSpan>
233
+ </FSRow>
129
234
  </template>
130
235
  </FSDialogMenu>
131
236
  </template>
@@ -161,175 +266,231 @@
161
266
  />
162
267
  </template>
163
268
  </FSToggleSet>
164
- <v-autocomplete
269
+ <FSCol
165
270
  v-else
166
- class="fs-autocomplete-field"
167
- variant="outlined"
168
- :clearable="$props.clearable && $props.editable && !!$props.modelValue"
169
- :itemTitle="$props.itemTitle"
170
- :itemValue="$props.itemValue"
171
- :readonly="!$props.editable"
172
- :multiple="$props.multiple"
173
- :validateOn="validateOn"
174
- :autoSelectFirst="true"
175
- :persistentClear="true"
176
- :listProps="listStyle"
177
- :returnObject="false"
178
- :items="$props.items"
179
- :rules="$props.rules"
180
- :hideDetails="true"
181
- :menuIcon="null"
182
- :class="classes"
183
- :style="style"
184
- :modelValue="$props.modelValue"
185
- @update:modelValue="$emit('update:modelValue', $event)"
186
- @click="onClick"
187
- v-model:search="search"
188
- v-bind="$attrs"
189
271
  >
190
- <template
191
- v-for="(_, name) in autocompleteSlots"
192
- v-slot:[name]="slotData"
193
- >
194
- <slot
195
- :name="`autocomplete-${name}`"
196
- v-bind="slotData"
197
- />
198
- </template>
199
- <template
200
- #item="{ props, item }"
272
+ <v-autocomplete
273
+ class="fs-autocomplete-field"
274
+ variant="outlined"
275
+ :clearable="$props.clearable && $props.editable && !!$props.modelValue"
276
+ :itemTitle="$props.itemTitle"
277
+ :itemValue="$props.itemValue"
278
+ :readonly="!$props.editable"
279
+ :multiple="$props.multiple"
280
+ :validateOn="validateOn"
281
+ :autoSelectFirst="true"
282
+ :persistentClear="true"
283
+ :listProps="listStyle"
284
+ :returnObject="false"
285
+ :items="$props.items"
286
+ :rules="$props.rules"
287
+ :hideDetails="true"
288
+ :menuIcon="null"
289
+ :class="classes"
290
+ :style="style"
291
+ :modelValue="$props.modelValue"
292
+ @update:modelValue="onSingleChange"
293
+ @click="onClick"
294
+ v-model:search="search"
295
+ v-bind="$attrs"
201
296
  >
202
- <v-list-item
203
- v-bind="{ ...props, title: '' }"
297
+ <template
298
+ v-for="(_, name) in autocompleteSlots"
299
+ v-slot:[name]="slotData"
204
300
  >
205
- <FSRow
206
- align="center-left"
301
+ <slot
302
+ :name="`autocomplete-${name}`"
303
+ v-bind="slotData"
304
+ />
305
+ </template>
306
+ <template
307
+ #item="{ props, item }"
308
+ >
309
+ <v-list-item
310
+ v-bind="{ ...props, title: '' }"
207
311
  >
208
- <FSCheckbox
209
- v-if="$props.multiple"
210
- :modelValue="$props.modelValue?.includes(item.raw[$props.itemValue])"
211
- @click="props.onClick"
312
+ <FSRow
313
+ align="center-left"
314
+ :wrap="false"
212
315
  >
213
- <template
214
- #label="{ font }"
316
+ <FSCheckbox
317
+ v-if="$props.multiple"
318
+ :modelValue="$props.modelValue?.includes(item.raw[$props.itemValue!])"
319
+ @click="props.onClick"
215
320
  >
216
- <slot
217
- name="item-label"
218
- v-bind="{ item, font }"
321
+ <template
322
+ #label="{ font }"
219
323
  >
324
+ <slot
325
+ name="item-prepend"
326
+ v-bind="{ item: item.raw }"
327
+ />
220
328
  <FSSpan
221
329
  :font="font"
222
330
  >
223
- {{ item.raw[$props.itemTitle] }}
331
+ {{ item.raw[$props.itemTitle!] }}
224
332
  </FSSpan>
225
- </slot>
226
- </template>
227
- </FSCheckbox>
228
- <FSSpan
229
- v-else
230
- >
231
- <slot
232
- name="item-label"
233
- v-bind="{
234
- item,
235
- font: $props.modelValue === item.raw[$props.itemTitle] ? 'text-button' : 'text-body'
236
- }"
333
+ </template>
334
+ </FSCheckbox>
335
+ <template
336
+ v-else
237
337
  >
338
+ <slot
339
+ name="item-prepend"
340
+ v-bind="{ item: item.raw }"
341
+ />
238
342
  <FSSpan
239
- :font="$props.modelValue === item.raw[$props.itemTitle] ? 'text-button' : 'text-body'"
343
+ :font="$props.modelValue === item.raw[$props.itemTitle!] ? 'text-button' : 'text-body'"
240
344
  >
241
- {{ item.raw[$props.itemTitle] }}
345
+ {{ item.raw[$props.itemTitle!] }}
242
346
  </FSSpan>
243
- </slot>
244
- </FSSpan>
245
- </FSRow>
246
- </v-list-item>
247
- </template>
248
- <template
249
- #clear
250
- >
251
- <slot
252
- name="clear"
347
+ </template>
348
+ <FSRow
349
+ align="center-right"
350
+ >
351
+ <slot
352
+ name="item-append"
353
+ v-bind="{ item: item.raw }"
354
+ />
355
+ </FSRow>
356
+ </FSRow>
357
+ </v-list-item>
358
+ </template>
359
+ <template
360
+ #prepend-inner
361
+ >
362
+ <slot
363
+ v-if="selectedItem && addExtra"
364
+ name="item-prepend"
365
+ v-bind="{ item: selectedItem }"
366
+ />
367
+ </template>
368
+ <template
369
+ v-if="$props.multiple"
370
+ #selection="{ index }"
371
+ >
372
+ <FSSpan
373
+ v-if="index === $props.modelValue.length - 1 && addExtra"
374
+ >
375
+ {{ $props.placeholder }}
376
+ </FSSpan>
377
+ </template>
378
+ <template
379
+ #clear
253
380
  >
254
381
  <FSRow
255
- gap="16px"
256
382
  :wrap="false"
257
383
  >
258
384
  <slot
259
- v-if="!$props.multiple"
260
- name="autocomplete-suffix"
385
+ v-if="selectedItem"
386
+ name="item-append"
387
+ v-bind="{ item: selectedItem }"
261
388
  />
389
+ <slot
390
+ name="clear"
391
+ >
392
+ <FSButton
393
+ v-if="$props.clearable && $props.editable && !!$props.modelValue"
394
+ icon="mdi-close"
395
+ variant="icon"
396
+ :color="ColorEnum.Dark"
397
+ @click="$emit('update:modelValue', null)"
398
+ />
399
+ </slot>
400
+ </FSRow>
401
+ </template>
402
+ <template
403
+ #append-inner
404
+ >
405
+ <slot
406
+ name="append-inner"
407
+ >
262
408
  <FSButton
263
- v-if="$props.clearable && $props.editable && !!$props.modelValue"
264
- icon="mdi-close"
409
+ icon="mdi-chevron-down"
265
410
  variant="icon"
411
+ :editable="$props.editable"
266
412
  :color="ColorEnum.Dark"
267
- @click="$emit('update:modelValue', null)"
268
413
  />
269
- </FSRow>
270
- </slot>
271
- </template>
272
- <template
273
- #append-inner
274
- >
275
- <slot
276
- name="append-inner"
277
- >
278
- <FSButton
279
- icon="mdi-chevron-down"
280
- variant="icon"
281
- :editable="$props.editable"
282
- :color="ColorEnum.Dark"
283
- />
284
- </slot>
285
- </template>
286
- <template
287
- #append-item
288
- >
289
- <FSRow
290
- v-if="showSearch && !searchItems.map((item: any) => item[$props.itemTitle]).some(s=>s.toLowerCase() == search.toLowerCase())"
291
- padding="17px"
414
+ </slot>
415
+ </template>
416
+ <template
417
+ #append-item
292
418
  >
293
- <FSButton
294
- v-if="search && search.trim().length > 0"
295
- variant="icon"
296
- :label="$tr('ui.common.add', 'Add this item')"
297
- :color="ColorEnum.Primary"
298
- @click="$emit('add:item', search)"
299
- />
300
- </FSRow>
301
- </template>
302
- <template
303
- #no-data
304
- >
419
+ <FSRow
420
+ v-if="allowAddItem"
421
+ padding="17px"
422
+ >
423
+ <FSButton
424
+ variant="icon"
425
+ :label="$tr('ui.autocomplete.add-item', 'Add new item')"
426
+ :color="ColorEnum.Primary"
427
+ @click="$emit('add:item', search)"
428
+ />
429
+ </FSRow>
430
+ </template>
305
431
  <template
306
- v-if="showSearch"
432
+ #no-data
307
433
  >
434
+ <FSRow
435
+ v-if="!allowAddItem"
436
+ padding="17px"
437
+ >
438
+ <FSSpan>
439
+ {{ $tr("ui.common.no-data", "No data") }}
440
+ </FSSpan>
441
+ </FSRow>
308
442
  </template>
309
- <FSRow
310
- v-else
311
- padding="17px"
443
+ </v-autocomplete>
444
+ <FSSlideGroup
445
+ v-if="$props.multiple && Array.isArray($props.modelValue)"
446
+ >
447
+ <FSCard
448
+ v-for="(item, index) in $props.items.filter((item: any) => $props.modelValue.includes(item[$props.itemValue!]))"
449
+ variant="standard"
450
+ :height="['40px', '36px']"
451
+ :color="ColorEnum.Light"
452
+ :border="false"
453
+ :key="index"
312
454
  >
313
- <FSSpan>
314
- {{ $tr("ui.common.no-data", "No data") }}
315
- </FSSpan>
316
- </FSRow>
317
- </template>
318
- </v-autocomplete>
455
+ <FSRow
456
+ align="center-left"
457
+ padding="0 8px"
458
+ >
459
+ <slot
460
+ name="item-prepend"
461
+ v-bind="{ item }"
462
+ />
463
+ <FSSpan>
464
+ {{ item[$props.itemTitle!] }}
465
+ </FSSpan>
466
+ <slot
467
+ name="item-append"
468
+ v-bind="{ item }"
469
+ />
470
+ <FSButton
471
+ icon="mdi-close"
472
+ variant="icon"
473
+ :color="ColorEnum.Dark"
474
+ @click="() => onCheckboxChange(item[$props.itemValue!])"
475
+ />
476
+ </FSRow>
477
+ </FSCard>
478
+ </FSSlideGroup>
479
+ </FSCol>
319
480
  </FSBaseField>
320
481
  </template>
321
482
  </template>
322
483
  </template>
323
484
 
324
485
  <script lang="ts">
325
- import { computed, defineComponent, type PropType, ref, type StyleValue } from "vue";
486
+ import { computed, defineComponent, type PropType, ref, type StyleValue, type Slot } from "vue";
326
487
 
327
488
  import { useBreakpoints, useColors, useRules, useSlots } from "@dative-gpi/foundation-shared-components/composables";
328
489
  import { ColorEnum } from "@dative-gpi/foundation-shared-components/models";
329
490
 
330
491
  import FSSearchField from "./FSSearchField.vue";
331
492
  import FSDialogMenu from "../FSDialogMenu.vue";
332
- import FSRadioGroup from "../FSRadioGroup.vue";
493
+ import FSSlideGroup from "../FSSlideGroup.vue";
333
494
  import FSToggleSet from "../FSToggleSet.vue";
334
495
  import FSBaseField from "./FSBaseField.vue";
335
496
  import FSTextField from "./FSTextField.vue";
@@ -337,6 +498,8 @@ import FSCheckbox from "../FSCheckbox.vue";
337
498
  import FSFadeOut from "../FSFadeOut.vue";
338
499
  import FSButton from "../FSButton.vue";
339
500
  import FSLoader from "../FSLoader.vue";
501
+ import FSRadio from "../FSRadio.vue";
502
+ import FSCard from "../FSCard.vue";
340
503
  import FSSpan from "../FSSpan.vue";
341
504
  import FSCol from "../FSCol.vue";
342
505
  import FSRow from "../FSRow.vue";
@@ -347,7 +510,7 @@ export default defineComponent({
347
510
  components: {
348
511
  FSSearchField,
349
512
  FSDialogMenu,
350
- FSRadioGroup,
513
+ FSSlideGroup,
351
514
  FSBaseField,
352
515
  FSTextField,
353
516
  FSToggleSet,
@@ -355,6 +518,8 @@ export default defineComponent({
355
518
  FSFadeOut,
356
519
  FSButton,
357
520
  FSLoader,
521
+ FSRadio,
522
+ FSCard,
358
523
  FSSpan,
359
524
  FSCol,
360
525
  FSRow
@@ -365,6 +530,11 @@ export default defineComponent({
365
530
  required: false,
366
531
  default: null
367
532
  },
533
+ placeholder: {
534
+ type: String as PropType<string | null>,
535
+ required: false,
536
+ default: null
537
+ },
368
538
  description: {
369
539
  type: String as PropType<string | null>,
370
540
  required: false,
@@ -457,6 +627,7 @@ export default defineComponent({
457
627
 
458
628
  const dialog = ref(false);
459
629
  const search = ref("");
630
+ const addExtra = ref(true);
460
631
 
461
632
  const style = computed((): StyleValue => {
462
633
  if (!props.editable) {
@@ -479,21 +650,21 @@ export default defineComponent({
479
650
  };
480
651
  });
481
652
 
482
- const autocompleteSlots = computed((): any => {
483
- return Object.keys(slots).filter(k => k.startsWith("autocomplete-")).reduce((acc, key) => {
653
+ const autocompleteSlots = computed((): { [key: string]: Slot<any> } => {
654
+ return Object.keys(slots).filter(k => k.startsWith("autocomplete-")).reduce((acc: { [key: string]: Slot<any> }, key) => {
484
655
  acc[key.substring("autocomplete-".length)] = slots[key];
485
656
  return acc;
486
657
  }, {});
487
658
  });
488
659
 
489
- const toggleSetSlots = computed((): any => {
490
- return Object.keys(slots).filter(k => k.startsWith("toggle-set-")).reduce((acc, key) => {
660
+ const toggleSetSlots = computed((): { [key: string]: Slot<any> } => {
661
+ return Object.keys(slots).filter(k => k.startsWith("toggle-set-")).reduce((acc: { [key: string]: Slot<any> }, key) => {
491
662
  acc[key.substring("toggle-set-".length)] = slots[key];
492
663
  return acc;
493
664
  }, {});
494
665
  });
495
666
 
496
- const listStyle = computed((): any => {
667
+ const listStyle = computed((): { style: StyleValue } => {
497
668
  return {
498
669
  style: style.value
499
670
  };
@@ -509,12 +680,42 @@ export default defineComponent({
509
680
 
510
681
  const messages = computed((): string[] => props.messages ?? getMessages(props.modelValue, props.rules));
511
682
 
512
- const searchItems = computed(() => {
683
+ const searchItems = computed((): any[] => {
513
684
  return props.items.filter((item: any) => {
514
685
  return item[props.itemTitle].toLowerCase().includes(search.value.toLowerCase());
515
686
  });
516
687
  });
517
688
 
689
+ const selectedItem = computed((): any => {
690
+ if (props.multiple) {
691
+ return null;
692
+ }
693
+ if (Array.isArray(props.modelValue) && props.modelValue.length > 0) {
694
+ return props.items.find((item: any) => item[props.itemValue] === props.modelValue[0]) ?? null;
695
+ }
696
+ else if (props.modelValue) {
697
+ return props.items.find((item: any) => item[props.itemValue] === props.modelValue) ?? null;
698
+ }
699
+ return null;
700
+ });
701
+
702
+ const selectedItems = computed((): any[] => {
703
+ if (Array.isArray(props.modelValue) && props.modelValue.length > 0) {
704
+ return props.items.filter((item: any) => props.modelValue.includes(item[props.itemValue]));
705
+ }
706
+ else if (props.modelValue) {
707
+ const item = props.items.find((item: any) => item[props.itemValue] === props.modelValue);
708
+ if (item) {
709
+ return [item];
710
+ }
711
+ }
712
+ return [];
713
+ });
714
+
715
+ const allowAddItem = computed((): boolean => {
716
+ return props.showSearch && search.value.trim().length > 0;
717
+ });
718
+
518
719
  const maxHeight = computed(() => {
519
720
  const other = 8 + 8 // Paddings
520
721
  + (isMobileSized ? 36 : 40) + 8; // Header
@@ -523,58 +724,14 @@ export default defineComponent({
523
724
 
524
725
  const mobileValue = computed((): string | null => {
525
726
  if (props.multiple) {
526
- if (Array.isArray(props.modelValue)) {
527
- return props.modelValue.map((value: any) => {
528
- const item = props.items.find((item: object) => item[props.itemValue] === value);
529
- if (item) {
530
- return item[props.itemTitle];
531
- }
532
- }).filter(value => !!value).join(", ");
533
- }
727
+ return props.placeholder;
534
728
  }
535
- if (props.modelValue) {
536
- const item = props.items.find((item: object) => item[props.itemValue] === props.modelValue);
537
- if (item) {
538
- return item[props.itemTitle];
539
- }
540
- }
541
- return null;
542
- });
543
-
544
- const mobileSelectionProps = computed((): any | null => {
545
- const item = props.items.find((item: any) => item[props.itemValue] === props.modelValue);
546
- if (item) {
547
- return {
548
- item: {
549
- title: "",
550
- value: item[props.itemValue],
551
- props: {
552
- title: item[props.itemTitle],
553
- value: item[props.itemValue]
554
- },
555
- raw: { ...item }
556
- },
557
- font: "text-body"
558
- };
729
+ if (selectedItem.value) {
730
+ return selectedItem.value[props.itemTitle];
559
731
  }
560
732
  return null;
561
733
  });
562
734
 
563
- const mobileItemProps = (item: any, font: "text-body" | "text-button" | null): any => {
564
- return {
565
- item: {
566
- title: "",
567
- value: item[props.itemValue],
568
- props: {
569
- title: item[props.itemTitle],
570
- value: item[props.itemValue]
571
- },
572
- raw: { ...item }
573
- },
574
- font
575
- }
576
- };
577
-
578
735
  const openMobileOverlay = () => {
579
736
  if (!props.editable) {
580
737
  return;
@@ -583,11 +740,13 @@ export default defineComponent({
583
740
  };
584
741
 
585
742
  const onRadioChange = (value: string | null) => {
743
+ addExtra.value = true;
586
744
  emit("update:modelValue", value);
587
745
  dialog.value = false;
588
746
  };
589
747
 
590
748
  const onCheckboxChange = (value: string) => {
749
+ addExtra.value = true;
591
750
  if (Array.isArray(props.modelValue)) {
592
751
  if (props.modelValue.includes(value)) {
593
752
  emit("update:modelValue", props.modelValue.filter((item: any) => item !== value));
@@ -609,23 +768,32 @@ export default defineComponent({
609
768
  }
610
769
  };
611
770
 
612
- const onClick = () => {
771
+ const onSingleChange = (value: string) => {
772
+ addExtra.value = true;
773
+ emit("update:modelValue", value);
774
+ };
775
+
776
+ const onClick = (): void => {
777
+ addExtra.value = false;
613
778
  if (props.modelValue && !props.multiple) {
614
- search.value="";
615
- }
779
+ search.value = "";
780
+ }
616
781
  };
617
782
 
618
783
  return {
619
- mobileSelectionProps,
620
784
  autocompleteSlots,
621
785
  toggleSetSlots,
786
+ selectedItems,
622
787
  isExtraSmall,
788
+ allowAddItem,
789
+ selectedItem,
623
790
  mobileValue,
624
791
  searchItems,
625
792
  validateOn,
626
793
  ColorEnum,
627
794
  listStyle,
628
795
  maxHeight,
796
+ addExtra,
629
797
  messages,
630
798
  classes,
631
799
  dialog,
@@ -634,7 +802,7 @@ export default defineComponent({
634
802
  style,
635
803
  openMobileOverlay,
636
804
  onCheckboxChange,
637
- mobileItemProps,
805
+ onSingleChange,
638
806
  onRadioChange,
639
807
  onClick
640
808
  };