@dative-gpi/foundation-shared-components 0.0.229 → 0.1.68

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 (228) hide show
  1. package/components/FSAccordionPanel.vue +8 -10
  2. package/components/FSBadge.vue +2 -4
  3. package/components/FSBreadcrumbs.vue +9 -10
  4. package/components/FSButton.vue +81 -31
  5. package/components/FSCalendar.vue +35 -33
  6. package/components/FSCalendarTwin.vue +77 -84
  7. package/components/FSCard.vue +29 -16
  8. package/components/FSCardPlaceholder.vue +1 -2
  9. package/components/FSCheckbox.vue +5 -7
  10. package/components/FSChip.vue +9 -11
  11. package/components/FSClickable.vue +67 -57
  12. package/components/FSClock.vue +4 -4
  13. package/components/FSCol.vue +2 -3
  14. package/components/FSColor.vue +13 -31
  15. package/components/FSColorIcon.vue +25 -9
  16. package/components/FSDialog.vue +1 -2
  17. package/components/FSDialogFormBody.vue +4 -4
  18. package/components/FSDialogMenu.vue +2 -4
  19. package/components/FSDialogMultiFormBody.vue +63 -50
  20. package/components/FSDialogRemove.vue +1 -0
  21. package/components/FSDialogSubmit.vue +5 -7
  22. package/components/FSDivider.vue +7 -9
  23. package/components/FSEditImage.vue +27 -274
  24. package/components/FSEditImageUI.vue +303 -0
  25. package/components/FSErrorToast.vue +3 -4
  26. package/components/FSFadeOut.vue +18 -13
  27. package/components/FSGrid.vue +6 -9
  28. package/components/FSGridMosaic.vue +1 -2
  29. package/components/FSIcon.vue +7 -8
  30. package/components/FSIconCard.vue +23 -30
  31. package/components/FSIconCheck.vue +1 -2
  32. package/components/FSImage.vue +21 -193
  33. package/components/FSImageCard.vue +2 -2
  34. package/components/FSImageUI.vue +212 -0
  35. package/components/FSLabel.vue +18 -20
  36. package/components/FSLink.vue +19 -21
  37. package/components/FSLoader.vue +10 -14
  38. package/components/FSOptionGroup.vue +58 -12
  39. package/components/FSPagination.vue +3 -5
  40. package/components/FSRadio.vue +5 -7
  41. package/components/FSRadioGroup.vue +2 -4
  42. package/components/FSRow.vue +3 -4
  43. package/components/FSSlideGroup.vue +15 -4
  44. package/components/FSSlider.vue +9 -11
  45. package/components/FSSpan.vue +11 -9
  46. package/components/FSSwitch.vue +65 -37
  47. package/components/FSTab.vue +2 -4
  48. package/components/FSTabs.vue +36 -16
  49. package/components/FSTag.vue +23 -14
  50. package/components/FSTagGroup.vue +3 -5
  51. package/components/FSText.vue +8 -12
  52. package/components/FSWindow.vue +11 -5
  53. package/components/FSWrapGroup.vue +15 -4
  54. package/components/agenda/FSAgenda.vue +204 -0
  55. package/components/agenda/FSAgendaDialogCalendar.vue +76 -0
  56. package/components/agenda/FSAgendaHeader.vue +190 -0
  57. package/components/agenda/FSAgendaHorizontalEvent.vue +162 -0
  58. package/components/agenda/FSAgendaHorizontalTimeLineMarker.vue +46 -0
  59. package/components/agenda/FSAgendaHoursCol.vue +103 -0
  60. package/components/agenda/FSAgendaHoursRow.vue +124 -0
  61. package/components/agenda/FSAgendaVerticalEvent.vue +160 -0
  62. package/components/agenda/FSAgendaVerticalTimeLineMarker.vue +46 -0
  63. package/components/agenda/FSDayAgenda.vue +200 -0
  64. package/components/agenda/FSMonthAgenda.vue +257 -0
  65. package/components/agenda/FSSelectAgendaMode.vue +54 -0
  66. package/components/agenda/FSWeekAgenda.vue +328 -0
  67. package/components/autocompletes/FSAutocompleteLanguage.vue +18 -39
  68. package/components/autocompletes/FSAutocompleteTimeZone.vue +20 -38
  69. package/components/buttons/FSButtonCancelMini.vue +1 -0
  70. package/components/buttons/FSButtonCopy.vue +28 -0
  71. package/components/buttons/FSButtonCopyIcon.vue +28 -0
  72. package/components/buttons/FSButtonCopyLabel.vue +27 -0
  73. package/components/buttons/FSButtonCopyMini.vue +28 -0
  74. package/components/buttons/FSButtonDragIcon.vue +27 -0
  75. package/components/buttons/FSButtonDuplicateMini.vue +1 -0
  76. package/components/buttons/FSButtonEditMini.vue +1 -0
  77. package/components/buttons/FSButtonFileMini.vue +1 -0
  78. package/components/buttons/FSButtonNextMini.vue +1 -0
  79. package/components/buttons/FSButtonPreviousMini.vue +1 -0
  80. package/components/buttons/FSButtonRedoMini.vue +1 -0
  81. package/components/buttons/FSButtonRemoveMini.vue +1 -0
  82. package/components/buttons/FSButtonSaveMini.vue +1 -0
  83. package/components/buttons/FSButtonSearchMini.vue +1 -0
  84. package/components/buttons/FSButtonUndoMini.vue +1 -0
  85. package/components/buttons/FSButtonUpdateMini.vue +1 -0
  86. package/components/buttons/FSButtonValidateMini.vue +1 -0
  87. package/components/deviceOrganisations/FSConnectivity.vue +11 -1
  88. package/components/deviceOrganisations/FSConnectivityCard.vue +20 -49
  89. package/components/deviceOrganisations/FSStatus.vue +11 -1
  90. package/components/deviceOrganisations/FSStatusCard.vue +40 -60
  91. package/components/deviceOrganisations/FSStatusesCarousel.vue +1 -0
  92. package/components/deviceOrganisations/FSStatusesRow.vue +10 -5
  93. package/components/deviceOrganisations/FSWorstAlert.vue +19 -13
  94. package/components/deviceOrganisations/FSWorstAlertCard.vue +36 -47
  95. package/components/fields/FSAutocompleteField.vue +501 -323
  96. package/components/fields/FSAutocompleteTag.vue +100 -0
  97. package/components/fields/FSBaseField.vue +26 -16
  98. package/components/fields/FSColorField.vue +63 -55
  99. package/components/fields/FSCommentField.vue +93 -0
  100. package/components/fields/FSDateField.vue +2 -2
  101. package/components/fields/FSDateRangeField.vue +2 -2
  102. package/components/fields/FSDateTimeField.vue +4 -3
  103. package/components/fields/FSDateTimeRangeField.vue +7 -6
  104. package/components/fields/FSEntityFieldUI.vue +271 -0
  105. package/components/fields/FSGradientField.vue +27 -33
  106. package/components/fields/FSIconField.vue +2 -3
  107. package/components/fields/FSMagicConfigField.vue +28 -19
  108. package/components/fields/FSMagicField.vue +25 -17
  109. package/components/fields/FSNumberField.vue +9 -7
  110. package/components/fields/FSPasswordField.vue +2 -3
  111. package/components/fields/FSRichTextField.vue +32 -5
  112. package/components/fields/FSSearchField.vue +2 -2
  113. package/components/fields/FSSelectField.vue +483 -251
  114. package/components/fields/FSTagField.vue +4 -6
  115. package/components/fields/FSTermField.vue +25 -13
  116. package/components/fields/FSTextArea.vue +18 -6
  117. package/components/fields/FSTextField.vue +13 -10
  118. package/components/fields/FSTimeField.vue +1 -1
  119. package/components/fields/FSTimeSlotField.vue +3 -4
  120. package/components/fields/FSTimeStepField.vue +157 -0
  121. package/components/fields/FSTranslateField.vue +3 -2
  122. package/components/fields/FSTranslateRichTextField.vue +4 -3
  123. package/components/fields/FSTranslateTextArea.vue +233 -0
  124. package/components/fields/FSTreeViewField.vue +7 -9
  125. package/components/fields/periodicField/FSPeriodicDailyField.vue +120 -0
  126. package/components/fields/periodicField/FSPeriodicField.vue +131 -0
  127. package/components/fields/periodicField/FSPeriodicMonthlyField.vue +222 -0
  128. package/components/fields/periodicField/FSPeriodicWeeklyField.vue +120 -0
  129. package/components/fields/periodicField/FSPeriodicYearlyField.vue +144 -0
  130. package/components/lists/FSDataIteratorItem.vue +8 -10
  131. package/components/lists/FSDataTableUI.vue +47 -39
  132. package/components/lists/FSFilterButton.vue +20 -22
  133. package/components/lists/FSHiddenButton.vue +10 -12
  134. package/components/lists/FSLoadDataTable.vue +4 -6
  135. package/components/lists/FSSimpleList.vue +229 -0
  136. package/components/map/FSMap.vue +256 -405
  137. package/components/map/FSMapFeatureGroup.vue +51 -0
  138. package/components/map/FSMapLayerButton.vue +6 -3
  139. package/components/map/FSMapMarker.vue +116 -0
  140. package/components/map/FSMapMarkerClusterGroup.vue +72 -0
  141. package/components/map/FSMapOverlay.vue +69 -83
  142. package/components/map/FSMapPolygon.vue +81 -0
  143. package/components/map/FSMapTileLayer.vue +50 -0
  144. package/components/map/keys.ts +4 -0
  145. package/components/selects/FSSelectAutoRefresh.vue +1 -1
  146. package/components/selects/FSSelectDashboardVariableType.vue +1 -1
  147. package/components/selects/FSSelectDateSetting.vue +3 -3
  148. package/components/selects/FSSelectDays.vue +1 -1
  149. package/components/selects/FSSelectListMode.vue +51 -0
  150. package/components/selects/FSSelectMonths.vue +67 -0
  151. package/components/tiles/FSChartTileUI.vue +116 -0
  152. package/components/tiles/FSCommentTileUI.vue +149 -0
  153. package/components/tiles/FSDashboardOrganisationTileUI.vue +6 -8
  154. package/components/tiles/FSDashboardOrganisationTypeTileUI.vue +6 -8
  155. package/components/tiles/FSDashboardShallowTileUI.vue +6 -8
  156. package/components/tiles/FSDeviceOrganisationTileUI.vue +30 -18
  157. package/components/tiles/FSFolderTileUI.vue +6 -6
  158. package/components/tiles/FSGroupTileUI.vue +31 -22
  159. package/components/tiles/FSLoadTile.vue +5 -7
  160. package/components/tiles/FSLocationTileUI.vue +157 -0
  161. package/components/tiles/FSModelTileUI.vue +18 -0
  162. package/components/tiles/FSServiceAccountOrganisationTileUI.vue +142 -0
  163. package/components/tiles/FSSimpleTileUI.vue +57 -36
  164. package/components/tiles/FSTile.vue +115 -55
  165. package/components/tiles/FSUserOrganisationTileUI.vue +25 -35
  166. package/components/toggleSets/FSToggleSetPosition.vue +1 -1
  167. package/components/views/FSEntityHeader.vue +343 -0
  168. package/components/views/FSEntityView.vue +163 -0
  169. package/components/views/FSListHeader.vue +83 -0
  170. package/components/views/FSListView.vue +83 -0
  171. package/components/views/FSSkeletonView.vue +100 -0
  172. package/composables/useAddress.ts +2 -2
  173. package/composables/useColors.ts +15 -5
  174. package/composables/useMagicFieldProvider.ts +7 -6
  175. package/composables/useSlots.ts +51 -28
  176. package/models/agenda.ts +9 -0
  177. package/models/deviceAlerts.ts +1 -1
  178. package/models/deviceConnectivities.ts +1 -1
  179. package/models/index.ts +1 -0
  180. package/models/magicFields.ts +1 -0
  181. package/models/map.ts +2 -2
  182. package/models/rules.ts +10 -5
  183. package/models/tables.ts +3 -1
  184. package/package.json +4 -4
  185. package/styles/components/fs_agenda.scss +32 -0
  186. package/styles/components/fs_agenda_event.scss +41 -0
  187. package/styles/components/fs_agenda_hours_col.scss +4 -0
  188. package/styles/components/fs_agenda_hours_row.scss +13 -0
  189. package/styles/components/fs_agenda_time_line_marker.scss +19 -0
  190. package/styles/components/fs_card.scss +0 -1
  191. package/styles/components/fs_clickable.scss +5 -3
  192. package/styles/components/fs_color_field.scss +1 -0
  193. package/styles/components/fs_data_table.scss +2 -0
  194. package/styles/components/fs_dialog.scss +11 -15
  195. package/styles/components/fs_edit_image.scss +8 -0
  196. package/styles/components/fs_fade_out.scss +2 -1
  197. package/styles/components/fs_filter_button.scss +1 -6
  198. package/styles/components/fs_gradient_field.scss +11 -11
  199. package/styles/components/fs_magic_config_field.scss +2 -2
  200. package/styles/components/fs_map.scss +36 -30
  201. package/styles/components/fs_option_group.scss +15 -5
  202. package/styles/components/fs_radio.scss +11 -0
  203. package/styles/components/fs_rich_text_field.scss +2 -1
  204. package/styles/components/fs_search_field.scss +3 -0
  205. package/styles/components/fs_select_date_settings.scss +3 -0
  206. package/styles/components/fs_slide_group.scss +5 -0
  207. package/styles/components/fs_span.scss +2 -1
  208. package/styles/components/fs_switch.scss +1 -0
  209. package/styles/components/fs_tabs.scss +9 -0
  210. package/styles/components/fs_text_area.scss +15 -1
  211. package/styles/components/fs_tile.scss +22 -6
  212. package/styles/components/fs_window.scss +5 -0
  213. package/styles/components/fs_wrap_group.scss +4 -0
  214. package/styles/components/index.scss +6 -1
  215. package/styles/globals/overrides.scss +22 -19
  216. package/styles/globals/text_fonts.scss +17 -55
  217. package/tools/alertsTools.ts +54 -0
  218. package/tools/chartsTools.ts +300 -0
  219. package/tools/index.ts +2 -0
  220. package/utils/badge.ts +9 -0
  221. package/utils/filter.ts +18 -0
  222. package/utils/index.ts +2 -0
  223. package/utils/leafletMarkers.ts +8 -2
  224. package/utils/statuses.ts +1 -1
  225. package/utils/time.ts +27 -1
  226. package/components/autocompletes/FSAutocompleteTag.vue +0 -138
  227. package/components/map/FSMapEditPointAddressOverlay.vue +0 -164
  228. package/styles/components/fs_map_overlay.scss +0 -38
@@ -1,202 +1,364 @@
1
1
  <template>
2
- <FSCol>
3
- <template
4
- v-if="isExtraSmall"
2
+ <FSCol
3
+ v-if="$props.loading"
4
+ >
5
+ <FSLoader
6
+ v-if="!$props.hideHeader"
7
+ variant="text-overline"
8
+ />
9
+ <FSLoader
10
+ v-if="$props.loading"
11
+ width="100%"
12
+ :height="['40px', '36px']"
13
+ />
14
+ </FSCol>
15
+ <FSCol
16
+ v-else-if="isExtraSmall"
17
+ >
18
+ <FSTextField
19
+ :validationValue="$props.modelValue"
20
+ :description="$props.description"
21
+ :hideHeader="$props.hideHeader"
22
+ :clearable="$props.clearable"
23
+ :editable="$props.editable"
24
+ :required="$props.required"
25
+ :validateOn="validateOn"
26
+ :label="$props.label"
27
+ :rules="$props.rules"
28
+ :messages="messages"
29
+ :readonly="true"
30
+ :modelValue="mobileValue"
31
+ @click="openMobileOverlay"
32
+ v-bind="$attrs"
5
33
  >
6
- <FSTextField
7
- :validationValue="$props.modelValue"
8
- :description="$props.description"
9
- :hideHeader="$props.hideHeader"
10
- :clearable="$props.clearable"
11
- :editable="$props.editable"
12
- :required="$props.required"
13
- :validateOn="validateOn"
14
- :label="$props.label"
15
- :rules="$props.rules"
16
- :messages="messages"
17
- :readonly="true"
18
- :modelValue="mobileValue"
19
- @update:modelValue="$emit('update:modelValue', $event)"
20
- @click="openMobileOverlay"
21
- v-bind="$attrs"
34
+ <template
35
+ v-for="(_, name) in $slots"
36
+ v-slot:[name]="slotData"
22
37
  >
23
- <template
24
- v-for="(_, name) in $slots"
25
- v-slot:[name]="slotData"
26
- >
27
- <slot
28
- :name="name"
29
- v-bind="slotData"
30
- />
31
- </template>
32
- <template
33
- v-if="mobileSelectionProps"
34
- #prepend-inner
38
+ <slot
39
+ :name="name"
40
+ v-bind="slotData"
41
+ />
42
+ </template>
43
+ <template
44
+ #prepend-inner
45
+ >
46
+ <slot
47
+ v-if="selectedItem"
48
+ name="item-prepend"
49
+ v-bind="{ item: selectedItem }"
50
+ />
51
+ </template>
52
+ <template
53
+ #clear
54
+ >
55
+ <FSRow
56
+ :wrap="false"
35
57
  >
36
58
  <slot
37
- name="selection-mobile"
38
- v-bind="mobileSelectionProps"
59
+ v-if="selectedItem"
60
+ name="item-append"
61
+ v-bind="{ item: selectedItem }"
39
62
  />
40
- </template>
41
- <template
42
- #append-inner
43
- >
44
63
  <slot
45
- name="append-inner"
64
+ name="clear"
46
65
  >
47
66
  <FSButton
48
- icon="mdi-chevron-down"
67
+ v-if="$props.clearable && $props.editable && !!$props.modelValue"
68
+ icon="mdi-close"
49
69
  variant="icon"
50
- :editable="$props.editable"
51
70
  :color="ColorEnum.Dark"
52
- @click="openMobileOverlay"
71
+ @click="onClear"
53
72
  />
54
73
  </slot>
55
- </template>
56
- </FSTextField>
57
- <FSDialogMenu
58
- v-model="dialog"
74
+ </FSRow>
75
+ </template>
76
+ <template
77
+ #append-inner
59
78
  >
60
- <template
61
- #body
79
+ <FSButton
80
+ icon="mdi-chevron-down"
81
+ variant="icon"
82
+ :editable="$props.editable"
83
+ :color="ColorEnum.Dark"
84
+ @click="openMobileOverlay"
85
+ />
86
+ </template>
87
+ </FSTextField>
88
+ <FSSlideGroup
89
+ v-if="$props.multiple && Array.isArray($props.modelValue)"
90
+ >
91
+ <FSCard
92
+ v-for="(item, index) in $props.items.filter((item: any) => $props.modelValue.includes(item[$props.itemValue!]))"
93
+ variant="standard"
94
+ :height="['40px', '36px']"
95
+ :color="ColorEnum.Light"
96
+ :border="false"
97
+ :key="index"
98
+ >
99
+ <FSRow
100
+ align="center-left"
101
+ padding="0 8px"
102
+ :wrap="false"
62
103
  >
63
- <FSFadeOut
64
- :height="height"
104
+ <slot
105
+ name="item-prepend"
106
+ v-bind="{ item }"
107
+ />
108
+ <FSSpan>
109
+ {{ item[$props.itemTitle!] }}
110
+ </FSSpan>
111
+ <slot
112
+ name="item-append"
113
+ v-bind="{ item }"
114
+ />
115
+ <FSButton
116
+ icon="mdi-close"
117
+ variant="icon"
118
+ :color="ColorEnum.Dark"
119
+ @click="() => onCheckboxChange(item[$props.itemValue!])"
120
+ />
121
+ </FSRow>
122
+ </FSCard>
123
+ </FSSlideGroup>
124
+ <FSDialogMenu
125
+ v-model="dialog"
126
+ >
127
+ <template
128
+ #body
129
+ >
130
+ <FSFadeOut
131
+ :maxHeight="maxHeight"
132
+ >
133
+ <FSCol
134
+ gap="12px"
65
135
  >
66
- <FSCol
67
- v-if="$props.multiple"
68
- gap="12px"
136
+ <FSRow
137
+ v-for="(item, index) in $props.items"
138
+ :key="index"
69
139
  >
70
- <FSRow
71
- v-for="(item, index) in $props.items"
72
- :key="index"
140
+ <FSCheckbox
141
+ v-if="$props.multiple"
142
+ :label="item[$props.itemTitle!]"
143
+ :editable="$props.editable"
144
+ :modelValue="$props.modelValue?.includes(item[$props.itemValue!])"
145
+ @update:modelValue="() => onCheckboxChange(item[$props.itemValue!])"
73
146
  >
74
- <FSCheckbox
75
- :label="item[$props.itemTitle]"
76
- :editable="$props.editable"
77
- :modelValue="$props.modelValue?.includes(item[$props.itemValue])"
78
- @update:modelValue="() => onCheckboxChange(item[$props.itemValue])"
147
+ <template
148
+ #label="{ font }"
79
149
  >
80
- <template
81
- #label="{ font }"
150
+ <FSRow
151
+ align="center-left"
152
+ :wrap="false"
82
153
  >
83
154
  <slot
84
- name="item-label"
85
- v-bind="mobileItemProps(item, font)"
155
+ name="item-prepend"
156
+ v-bind="{ item }"
86
157
  />
87
- </template>
88
- </FSCheckbox>
89
- </FSRow>
90
- </FSCol>
91
- <FSRadioGroup
92
- v-else
93
- gap="12px"
94
- :values="$props.items.map((item: any) => ({ value: item[$props.itemValue], label: item[$props.itemTitle], item: item }))"
95
- :editable="$props.editable"
96
- :modelValue="$props.modelValue"
97
- @update:modelValue="onRadioChange"
98
- >
99
- <template
100
- #label="{ item, font }"
158
+ <FSSpan
159
+ :font="font"
160
+ >
161
+ {{ item[$props.itemTitle!] }}
162
+ </FSSpan>
163
+ </FSRow>
164
+ </template>
165
+ </FSCheckbox>
166
+ <FSRadio
167
+ v-else
168
+ :selected="$props.modelValue === item[$props.itemValue!]"
169
+ :label="item[$props.itemTitle!]"
170
+ :editable="$props.editable"
171
+ :item="item"
172
+ :modelValue="item[$props.itemValue!]"
173
+ @update:modelValue="() => onRadioChange(item[$props.itemValue!])"
174
+ >
175
+ <template
176
+ #label="{ font }"
177
+ >
178
+ <FSRow
179
+ align="center-left"
180
+ :wrap="false"
181
+ >
182
+ <slot
183
+ name="item-prepend"
184
+ v-bind="{ item }"
185
+ />
186
+ <FSSpan
187
+ :font="font"
188
+ >
189
+ {{ item[$props.itemTitle!] }}
190
+ </FSSpan>
191
+ </FSRow>
192
+ </template>
193
+ </FSRadio>
194
+ <FSRow
195
+ align="center-right"
101
196
  >
102
197
  <slot
103
- name="item-label"
104
- v-bind="mobileItemProps(item, font)"
198
+ name="item-append"
199
+ v-bind="{ item }"
105
200
  />
106
- </template>
107
- </FSRadioGroup>
108
- </FSFadeOut>
109
- </template>
110
- </FSDialogMenu>
111
- </template>
112
- <template
201
+ </FSRow>
202
+ </FSRow>
203
+ </FSCol>
204
+ </FSFadeOut>
205
+ <FSRow
206
+ v-if="!$props.items || $props.items.length === 0"
207
+ padding="4px 3px"
208
+ >
209
+ <FSSpan>
210
+ {{ $tr("ui.select-field.no-data", "No data") }}
211
+ </FSSpan>
212
+ </FSRow>
213
+ </template>
214
+ </FSDialogMenu>
215
+ </FSCol>
216
+ <FSBaseField
217
+ v-else
218
+ :description="$props.description"
219
+ :hideHeader="$props.hideHeader"
220
+ :required="$props.required"
221
+ :editable="$props.editable"
222
+ :label="$props.label"
223
+ :messages="messages"
224
+ >
225
+ <FSToggleSet
226
+ v-if="$props.toggleSet"
227
+ :editable="$props.editable"
228
+ :multiple="$props.multiple"
229
+ :required="$props.required"
230
+ :values="$props.items"
231
+ :rules="$props.rules"
232
+ :modelValue="$props.modelValue"
233
+ @update:modelValue="$emit('update:modelValue', $event)"
234
+ v-bind="$attrs"
235
+ >
236
+ <template
237
+ v-for="(_, name) in toggleSetSlots"
238
+ v-slot:[name]="slotData"
239
+ >
240
+ <slot
241
+ :name="`toggle-set-${name}`"
242
+ v-bind="slotData"
243
+ />
244
+ </template>
245
+ </FSToggleSet>
246
+ <FSCol
113
247
  v-else
114
248
  >
115
- <FSBaseField
116
- :description="$props.description"
117
- :hideHeader="$props.hideHeader"
118
- :required="$props.required"
119
- :editable="$props.editable"
120
- :label="$props.label"
121
- :messages="messages"
249
+ <v-select
250
+ class="fs-select-field"
251
+ variant="outlined"
252
+ :clearable="$props.clearable && $props.editable && !!$props.modelValue"
253
+ :itemTitle="$props.itemTitle"
254
+ :itemValue="$props.itemValue"
255
+ :readonly="!$props.editable"
256
+ :multiple="$props.multiple"
257
+ :validateOn="validateOn"
258
+ :persistentClear="true"
259
+ :listProps="listStyle"
260
+ :returnObject="false"
261
+ :items="$props.items"
262
+ :rules="$props.rules"
263
+ :hideDetails="true"
264
+ :menuIcon="null"
265
+ :style="style"
266
+ :modelValue="$props.modelValue"
267
+ @update:modelValue="onSingleChange"
268
+ v-bind="$attrs"
122
269
  >
123
- <v-select
124
- class="fs-select-field"
125
- variant="outlined"
126
- :clearable="$props.clearable && $props.editable && !!$props.modelValue"
127
- :itemTitle="$props.itemTitle"
128
- :itemValue="$props.itemValue"
129
- :readonly="!$props.editable"
130
- :multiple="$props.multiple"
131
- :validateOn="validateOn"
132
- :persistentClear="true"
133
- :listProps="listStyle"
134
- :returnObject="false"
135
- :items="$props.items"
136
- :rules="$props.rules"
137
- :hideDetails="true"
138
- :menuIcon="null"
139
- :style="style"
140
- :modelValue="$props.modelValue"
141
- @update:modelValue="$emit('update:modelValue', $event)"
142
- v-bind="$attrs"
270
+ <template
271
+ v-for="(_, name) in selectSlots"
272
+ v-slot:[name]="slotData"
143
273
  >
144
- <template
145
- v-for="(_, name) in $slots"
146
- v-slot:[name]="slotData"
147
- >
148
- <slot
149
- :name="name"
150
- v-bind="slotData"
151
- />
152
- </template>
153
- <template
154
- #item="{ props, item }"
274
+ <slot
275
+ :name="`select-${name}`"
276
+ v-bind="slotData"
277
+ />
278
+ </template>
279
+ <template
280
+ #item="{ props, item }"
281
+ >
282
+ <v-list-item
283
+ v-bind="{ ...props, title: '' }"
155
284
  >
156
- <v-list-item
157
- v-bind="{ ...props, title: '' }"
285
+ <FSRow
286
+ align="center-left"
287
+ :wrap="false"
158
288
  >
159
- <FSRow
160
- align="center-left"
289
+ <FSCheckbox
290
+ v-if="$props.multiple"
291
+ :modelValue="$props.modelValue?.includes(item.raw[$props.itemValue!])"
292
+ @click="props.onClick"
161
293
  >
162
- <FSCheckbox
163
- v-if="$props.multiple"
164
- :modelValue="$props.modelValue?.includes(item.raw[$props.itemValue])"
165
- @click="props.onClick"
294
+ <template
295
+ #label="{ font }"
166
296
  >
167
- <template
168
- #label="{ font }"
297
+ <slot
298
+ name="item-prepend"
299
+ v-bind="{ item: item.raw }"
300
+ />
301
+ <FSSpan
302
+ :font="font"
169
303
  >
170
- <slot
171
- name="item-label"
172
- v-bind="{ item, font }"
173
- >
174
- <FSSpan
175
- :font="font"
176
- >
177
- {{ item.raw[$props.itemTitle] }}
178
- </FSSpan>
179
- </slot>
180
- </template>
181
- </FSCheckbox>
304
+ {{ item.raw[$props.itemTitle!] }}
305
+ </FSSpan>
306
+ </template>
307
+ </FSCheckbox>
308
+ <template
309
+ v-else
310
+ >
311
+ <slot
312
+ name="item-prepend"
313
+ v-bind="{ item: item.raw }"
314
+ />
182
315
  <FSSpan
183
- v-else
316
+ :font="$props.modelValue === item.raw[$props.itemTitle!] ? 'text-button' : 'text-body'"
184
317
  >
185
- <slot
186
- name="item-label"
187
- v-bind="{ item }"
188
- >
189
- <FSSpan>
190
- {{ item.raw[$props.itemTitle] }}
191
- </FSSpan>
192
- </slot>
318
+ {{ item.raw[$props.itemTitle!] }}
193
319
  </FSSpan>
320
+ </template>
321
+ <FSRow
322
+ align="center-right"
323
+ >
324
+ <slot
325
+ name="item-append"
326
+ v-bind="{ item: item.raw }"
327
+ />
194
328
  </FSRow>
195
- </v-list-item>
196
- </template>
197
- <template
198
- #clear
329
+ </FSRow>
330
+ </v-list-item>
331
+ </template>
332
+ <template
333
+ #prepend-inner
334
+ >
335
+ <slot
336
+ v-if="selectedItem"
337
+ name="item-prepend"
338
+ v-bind="{ item: selectedItem }"
339
+ />
340
+ </template>
341
+ <template
342
+ v-if="$props.multiple"
343
+ #selection="{ index }"
344
+ >
345
+ <FSSpan
346
+ v-if="index === $props.modelValue.length - 1"
347
+ >
348
+ {{ $props.placeholder }}
349
+ </FSSpan>
350
+ </template>
351
+ <template
352
+ #clear
353
+ >
354
+ <FSRow
355
+ :wrap="false"
199
356
  >
357
+ <slot
358
+ v-if="selectedItem"
359
+ name="item-append"
360
+ v-bind="{ item: selectedItem }"
361
+ />
200
362
  <slot
201
363
  name="clear"
202
364
  >
@@ -205,55 +367,94 @@
205
367
  icon="mdi-close"
206
368
  variant="icon"
207
369
  :color="ColorEnum.Dark"
208
- @click="$emit('update:modelValue', null)"
370
+ @click="onClear"
209
371
  />
210
372
  </slot>
211
- </template>
212
- <template
213
- #append-inner
373
+ </FSRow>
374
+ </template>
375
+ <template
376
+ #append-inner
377
+ >
378
+ <slot
379
+ name="append-inner"
214
380
  >
215
- <slot
216
- name="append-inner"
217
- >
218
- <FSButton
219
- icon="mdi-chevron-down"
220
- variant="icon"
221
- :editable="$props.editable"
222
- :color="ColorEnum.Dark"
223
- />
224
- </slot>
225
- </template>
226
- <template
227
- #no-data
381
+ <FSButton
382
+ icon="mdi-chevron-down"
383
+ variant="icon"
384
+ :editable="$props.editable"
385
+ :color="ColorEnum.Dark"
386
+ />
387
+ </slot>
388
+ </template>
389
+ <template
390
+ #no-data
391
+ >
392
+ <FSRow
393
+ v-if="!$props.items || $props.items.length === 0"
394
+ padding="15px"
228
395
  >
229
- <FSRow
230
- padding="17px"
231
- >
232
- <FSSpan>
233
- {{ $tr("ui.common.no-data", "No data") }}
234
- </FSSpan>
235
- </FSRow>
236
- </template>
237
- </v-select>
238
- </FSBaseField>
239
- </template>
240
- </FSCol>
396
+ <FSSpan>
397
+ {{ $tr("ui.select-field.no-data", "No data") }}
398
+ </FSSpan>
399
+ </FSRow>
400
+ </template>
401
+ </v-select>
402
+ <FSSlideGroup
403
+ v-if="$props.multiple && Array.isArray($props.modelValue)"
404
+ >
405
+ <FSCard
406
+ v-for="(item, index) in $props.items.filter((item: any) => $props.modelValue.includes(item[$props.itemValue!]))"
407
+ variant="standard"
408
+ :height="['40px', '36px']"
409
+ :color="ColorEnum.Light"
410
+ :border="false"
411
+ :key="index"
412
+ >
413
+ <FSRow
414
+ align="center-left"
415
+ padding="0 8px"
416
+ >
417
+ <slot
418
+ name="item-prepend"
419
+ v-bind="{ item }"
420
+ />
421
+ <FSSpan>
422
+ {{ item[$props.itemTitle!] }}
423
+ </FSSpan>
424
+ <slot
425
+ name="item-append"
426
+ v-bind="{ item }"
427
+ />
428
+ <FSButton
429
+ icon="mdi-close"
430
+ variant="icon"
431
+ :color="ColorEnum.Dark"
432
+ @click="() => onCheckboxChange(item[$props.itemValue!])"
433
+ />
434
+ </FSRow>
435
+ </FSCard>
436
+ </FSSlideGroup>
437
+ </FSCol>
438
+ </FSBaseField>
241
439
  </template>
242
440
 
243
441
  <script lang="ts">
244
- import type { PropType} from "vue";
245
- import { computed, defineComponent, ref } from "vue";
442
+ import { computed, defineComponent, type PropType, ref, type Slot, type StyleValue } from "vue";
246
443
 
247
- import { useBreakpoints, useColors, useRules } from "@dative-gpi/foundation-shared-components/composables";
444
+ import { useBreakpoints, useColors, useRules, useSlots } from "@dative-gpi/foundation-shared-components/composables";
248
445
  import { ColorEnum } from "@dative-gpi/foundation-shared-components/models";
249
446
 
250
447
  import FSDialogMenu from "../FSDialogMenu.vue";
251
- import FSRadioGroup from "../FSRadioGroup.vue";
448
+ import FSSlideGroup from "../FSSlideGroup.vue";
449
+ import FSToggleSet from "../FSToggleSet.vue";
252
450
  import FSBaseField from "./FSBaseField.vue";
253
451
  import FSTextField from "./FSTextField.vue";
254
452
  import FSCheckbox from "../FSCheckbox.vue";
255
453
  import FSFadeOut from "../FSFadeOut.vue";
256
454
  import FSButton from "../FSButton.vue";
455
+ import FSLoader from "../FSLoader.vue";
456
+ import FSRadio from "../FSRadio.vue";
457
+ import FSCard from "../FSCard.vue";
257
458
  import FSSpan from "../FSSpan.vue";
258
459
  import FSCol from "../FSCol.vue";
259
460
  import FSRow from "../FSRow.vue";
@@ -262,12 +463,16 @@ export default defineComponent({
262
463
  name: "FSSelectField",
263
464
  components: {
264
465
  FSDialogMenu,
265
- FSRadioGroup,
466
+ FSSlideGroup,
266
467
  FSBaseField,
267
468
  FSTextField,
469
+ FSToggleSet,
268
470
  FSCheckbox,
269
471
  FSFadeOut,
270
472
  FSButton,
473
+ FSLoader,
474
+ FSRadio,
475
+ FSCard,
271
476
  FSSpan,
272
477
  FSCol,
273
478
  FSRow
@@ -278,6 +483,11 @@ export default defineComponent({
278
483
  required: false,
279
484
  default: null
280
485
  },
486
+ placeholder: {
487
+ type: String as PropType<string | null>,
488
+ required: false,
489
+ default: null
490
+ },
281
491
  description: {
282
492
  type: String as PropType<string | null>,
283
493
  required: false,
@@ -298,21 +508,21 @@ export default defineComponent({
298
508
  default: "label"
299
509
  },
300
510
  modelValue: {
301
- type: [Array, String, Number] as PropType<(string | number)[] | string | number | null>,
511
+ type: [Array, String, Number] as PropType<(string | number)[] | string | number | null | any>,
302
512
  required: false,
303
513
  default: null
304
514
  },
305
- hideHeader: {
515
+ multiple: {
306
516
  type: Boolean,
307
517
  required: false,
308
518
  default: false
309
519
  },
310
- required: {
520
+ hideHeader: {
311
521
  type: Boolean,
312
522
  required: false,
313
523
  default: false
314
524
  },
315
- multiple: {
525
+ required: {
316
526
  type: Boolean,
317
527
  required: false,
318
528
  default: false
@@ -336,6 +546,16 @@ export default defineComponent({
336
546
  type: Boolean,
337
547
  required: false,
338
548
  default: true
549
+ },
550
+ loading: {
551
+ type: Boolean,
552
+ required: false,
553
+ default: false
554
+ },
555
+ toggleSet: {
556
+ type: Boolean,
557
+ required: false,
558
+ default: false
339
559
  }
340
560
  },
341
561
  emits: ["update:modelValue"],
@@ -343,6 +563,10 @@ export default defineComponent({
343
563
  const { validateOn, getMessages } = useRules();
344
564
  const { isExtraSmall } = useBreakpoints();
345
565
  const { getColors } = useColors();
566
+ const { slots } = useSlots();
567
+
568
+ delete slots.label;
569
+ delete slots.description;
346
570
 
347
571
  const backgrounds = getColors(ColorEnum.Background);
348
572
  const errors = getColors(ColorEnum.Error);
@@ -351,7 +575,7 @@ export default defineComponent({
351
575
 
352
576
  const dialog = ref(false);
353
577
 
354
- const style = computed((): { [key: string] : string | null | undefined } => {
578
+ const style = computed((): StyleValue => {
355
579
  if (!props.editable) {
356
580
  return {
357
581
  "--fs-select-field-cursor" : "default",
@@ -370,7 +594,21 @@ export default defineComponent({
370
594
  };
371
595
  });
372
596
 
373
- const listStyle = computed((): { [key: string] : object } => {
597
+ const selectSlots = computed((): { [key: string]: Slot<any> } => {
598
+ return Object.keys(slots).filter(k => k.startsWith("select-")).reduce((acc: { [key: string]: Slot<any> }, key) => {
599
+ acc[key.substring("select-".length)] = slots[key];
600
+ return acc;
601
+ }, {});
602
+ });
603
+
604
+ const toggleSetSlots = computed((): { [key: string]: Slot<any> } => {
605
+ return Object.keys(slots).filter(k => k.startsWith("toggle-set-")).reduce((acc: { [key: string]: Slot<any> }, key) => {
606
+ acc[key.substring("toggle-set-".length)] = slots[key];
607
+ return acc;
608
+ }, {});
609
+ });
610
+
611
+ const listStyle = computed((): { style: StyleValue } => {
374
612
  return {
375
613
  style: style.value
376
614
  };
@@ -378,64 +616,46 @@ export default defineComponent({
378
616
 
379
617
  const messages = computed((): string[] => props.messages ?? getMessages(props.modelValue, props.rules));
380
618
 
381
- const height = computed(() => {
382
- const other = 8 + 8; // Paddings
383
- return `calc(100vh - 40px - ${other}px)`;
619
+ const selectedItem = computed((): any => {
620
+ if (props.multiple) {
621
+ return null;
622
+ }
623
+ if (Array.isArray(props.modelValue) && props.modelValue.length > 0) {
624
+ return props.items.find((item: any) => item[props.itemValue] === props.modelValue[0]) ?? null;
625
+ }
626
+ else if (props.modelValue) {
627
+ return props.items.find((item: any) => item[props.itemValue] === props.modelValue) ?? null;
628
+ }
629
+ return null;
384
630
  });
385
631
 
386
- const mobileValue = computed((): string | null => {
387
- if (props.multiple) {
388
- if (Array.isArray(props.modelValue)) {
389
- return props.modelValue.map((value: any) => {
390
- const item = props.items.find((item: object) => item[props.itemValue] === value);
391
- if (item) {
392
- return item[props.itemTitle];
393
- }
394
- }).filter(value => !!value).join(", ");
395
- }
632
+ const selectedItems = computed((): any[] => {
633
+ if (Array.isArray(props.modelValue) && props.modelValue.length > 0) {
634
+ return props.items.filter((item: any) => props.modelValue.includes(item[props.itemValue]));
396
635
  }
397
- if (props.modelValue) {
398
- const item = props.items.find((item: object) => item[props.itemValue] === props.modelValue);
636
+ else if (props.modelValue) {
637
+ const item = props.items.find((item: any) => item[props.itemValue] === props.modelValue);
399
638
  if (item) {
400
- return item[props.itemTitle];
639
+ return [item];
401
640
  }
402
641
  }
403
- return null;
642
+ return [];
404
643
  });
405
644
 
406
- const mobileSelectionProps = computed((): any | null => {
407
- const item = props.items.find((item: any) => item[props.itemValue] === props.modelValue);
408
- if (item) {
409
- return {
410
- item: {
411
- title: "",
412
- value: item[props.itemValue],
413
- props: {
414
- title: item[props.itemTitle],
415
- value: item[props.itemValue]
416
- },
417
- raw: { ...item }
418
- },
419
- font: "text-body"
420
- };
421
- }
422
- return null;
645
+ const maxHeight = computed(() => {
646
+ const other = 8 + 8; // Paddings
647
+ return `calc(100vh - 40px - ${other}px)`;
423
648
  });
424
649
 
425
- const mobileItemProps = (item: any, font: "text-body" | "text-button" | null): any => {
426
- return {
427
- item: {
428
- title: "",
429
- value: item[props.itemValue],
430
- props: {
431
- title: item[props.itemTitle],
432
- value: item[props.itemValue]
433
- },
434
- raw: { ...item }
435
- },
436
- font
650
+ const mobileValue = computed((): string | null => {
651
+ if (props.multiple && Array.isArray(props.modelValue) && props.modelValue.length > 0) {
652
+ return props.placeholder;
437
653
  }
438
- };
654
+ if (selectedItem.value) {
655
+ return selectedItem.value[props.itemTitle];
656
+ }
657
+ return null;
658
+ });
439
659
 
440
660
  const openMobileOverlay = () => {
441
661
  if (!props.editable) {
@@ -471,21 +691,33 @@ export default defineComponent({
471
691
  }
472
692
  };
473
693
 
694
+ const onSingleChange = (value: string) => {
695
+ emit("update:modelValue", value);
696
+ };
697
+
698
+ const onClear = () => {
699
+ emit("update:modelValue", null);
700
+ };
701
+
474
702
  return {
475
- mobileSelectionProps,
703
+ toggleSetSlots,
704
+ selectedItems,
476
705
  isExtraSmall,
706
+ selectedItem,
477
707
  mobileValue,
708
+ selectSlots,
478
709
  validateOn,
479
710
  ColorEnum,
480
711
  listStyle,
712
+ maxHeight,
481
713
  messages,
482
714
  dialog,
483
- height,
484
715
  style,
485
716
  openMobileOverlay,
486
717
  onCheckboxChange,
487
- mobileItemProps,
488
- onRadioChange
718
+ onSingleChange,
719
+ onRadioChange,
720
+ onClear
489
721
  };
490
722
  }
491
723
  });