@dative-gpi/foundation-shared-components 0.0.8 → 0.0.9

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 (139) hide show
  1. package/{models/FSButtons.ts → aliases/FSButton.ts} +24 -21
  2. package/aliases/index.ts +1 -0
  3. package/components/FSAutocompleteField.vue +207 -0
  4. package/components/FSBadge.vue +38 -0
  5. package/components/FSBreadcrumbs.vue +49 -55
  6. package/components/FSButton.vue +116 -101
  7. package/components/FSCalendar.vue +52 -39
  8. package/components/FSCalendarTwin.vue +120 -102
  9. package/components/FSCard.vue +35 -21
  10. package/components/FSCarousel.vue +63 -0
  11. package/components/FSCheckbox.vue +111 -103
  12. package/components/FSChip.vue +140 -0
  13. package/components/FSClock.vue +149 -15
  14. package/components/FSCol.vue +104 -98
  15. package/components/FSColor.vue +61 -64
  16. package/components/FSColorIcon.vue +67 -0
  17. package/components/FSContainer.vue +64 -0
  18. package/components/FSDateField.vue +211 -0
  19. package/components/FSDateRangeField.vue +225 -0
  20. package/components/FSDateTimeField.vue +257 -0
  21. package/components/FSDateTimeRangeField.vue +286 -0
  22. package/components/FSDialog.vue +103 -0
  23. package/components/FSDivider.vue +39 -0
  24. package/components/FSFadeOut.vue +49 -59
  25. package/components/FSFileButton.vue +245 -0
  26. package/components/FSHeaderButton.vue +17 -0
  27. package/components/FSIcon.vue +23 -23
  28. package/components/FSIconField.vue +232 -0
  29. package/components/FSImage.vue +142 -0
  30. package/components/FSLoadTile.vue +93 -0
  31. package/components/FSNumberField.vue +51 -53
  32. package/components/FSPasswordField.vue +99 -101
  33. package/components/FSRadio.vue +107 -109
  34. package/components/FSRadioGroup.vue +55 -57
  35. package/components/FSRemoveDialog.vue +123 -0
  36. package/components/FSRichTextField.vue +26 -33
  37. package/components/FSRow.vue +110 -104
  38. package/components/FSSearchField.vue +35 -27
  39. package/components/FSSelectField.vue +188 -0
  40. package/components/FSSlideGroup.vue +45 -49
  41. package/components/FSSlider.vue +31 -33
  42. package/components/FSSpan.vue +53 -37
  43. package/components/FSSubmitDialog.vue +165 -0
  44. package/components/FSSwitch.vue +110 -109
  45. package/components/FSTab.vue +61 -61
  46. package/components/FSTabs.vue +53 -55
  47. package/components/FSTag.vue +88 -84
  48. package/components/FSTagField.vue +32 -36
  49. package/components/FSTagGroup.vue +38 -45
  50. package/components/FSText.vue +74 -64
  51. package/components/FSTextArea.vue +187 -185
  52. package/components/FSTextField.vue +18 -20
  53. package/components/FSTile.vue +90 -0
  54. package/components/FSToggleSet.vue +282 -0
  55. package/components/FSTooltip.vue +21 -0
  56. package/components/FSWindow.vue +26 -16
  57. package/components/FSWrapGroup.vue +44 -47
  58. package/components/deviceOrganisations/FSConnectivity.vue +114 -0
  59. package/components/deviceOrganisations/FSStatus.vue +117 -0
  60. package/components/deviceOrganisations/FSStatusesCarousel.vue +105 -0
  61. package/components/deviceOrganisations/FSStatusesRow.vue +66 -0
  62. package/components/deviceOrganisations/FSWorstAlert.vue +165 -0
  63. package/components/lists/FSDataIteratorGroup.vue +7 -0
  64. package/components/lists/FSDataIteratorItem.vue +103 -0
  65. package/components/lists/FSDataTable.vue +964 -0
  66. package/components/lists/FSFilterButton.vue +176 -0
  67. package/components/lists/FSHeaderButton.vue +99 -0
  68. package/components/lists/FSHiddenButton.vue +79 -0
  69. package/components/tiles/FSDeviceOrganisationTileUI.vue +232 -0
  70. package/components/tiles/FSGroupTileUI.vue +192 -0
  71. package/composables/index.ts +1 -1
  72. package/composables/useBreakpoints.ts +23 -4
  73. package/composables/useColors.ts +53 -23
  74. package/composables/useSlots.ts +43 -0
  75. package/index.ts +6 -0
  76. package/models/breadcrumbs.ts +8 -0
  77. package/models/colors.ts +17 -0
  78. package/models/deviceAlerts.ts +10 -0
  79. package/models/deviceConnectivities.ts +11 -0
  80. package/models/deviceStatuses.ts +16 -0
  81. package/models/dispositions.ts +33 -0
  82. package/models/index.ts +9 -0
  83. package/models/modelStatuses.ts +11 -0
  84. package/models/rules.ts +50 -0
  85. package/models/toggleSets.ts +7 -0
  86. package/package.json +5 -4
  87. package/plugins/colorPlugin.ts +2 -2
  88. package/shims-plugin.d.ts +1 -1
  89. package/styles/components/fs_autocomplete_field.scss +123 -0
  90. package/styles/components/fs_button.scss +4 -6
  91. package/styles/components/fs_calendar.scss +24 -1
  92. package/styles/components/fs_card.scss +2 -5
  93. package/styles/components/fs_carousel.scss +4 -0
  94. package/styles/components/fs_chip.scss +33 -0
  95. package/styles/components/fs_clock.scss +43 -0
  96. package/styles/components/fs_col.scss +2 -0
  97. package/styles/components/fs_color_icon.scss +37 -0
  98. package/styles/components/fs_container.scss +16 -0
  99. package/styles/components/fs_data_iterator_item.scss +19 -0
  100. package/styles/components/fs_data_table.scss +97 -0
  101. package/styles/components/fs_date_field.scss +8 -0
  102. package/styles/components/fs_dialog.scss +30 -0
  103. package/styles/components/fs_divider.scss +5 -0
  104. package/styles/components/fs_fade_out.scss +10 -2
  105. package/styles/components/fs_filter_button.scss +12 -0
  106. package/styles/components/fs_header_button.scss +4 -0
  107. package/styles/components/fs_icon.scss +19 -3
  108. package/styles/components/fs_icon_field.scss +12 -0
  109. package/styles/components/fs_image.scss +7 -0
  110. package/styles/components/fs_load_tile.scss +49 -0
  111. package/styles/components/fs_password_field.scss +2 -2
  112. package/styles/components/fs_row.scss +4 -1
  113. package/styles/components/fs_select_field.scss +71 -0
  114. package/styles/components/fs_slide_group.scss +6 -0
  115. package/styles/components/fs_slider.scss +29 -9
  116. package/styles/components/fs_span.scss +8 -0
  117. package/styles/components/fs_submit_dialog.scss +9 -0
  118. package/styles/components/fs_tabs.scss +4 -0
  119. package/styles/components/fs_tag_field.scss +0 -11
  120. package/styles/components/fs_text_field.scss +23 -15
  121. package/styles/components/fs_tile.scss +33 -0
  122. package/styles/components/fs_tooltip.scss +5 -0
  123. package/styles/components/fs_wrap_group.scss +7 -8
  124. package/styles/components/index.scss +21 -1
  125. package/styles/globals/breakpoints.scss +7 -0
  126. package/styles/globals/overrides.scss +20 -7
  127. package/styles/globals/text_fonts.scss +8 -8
  128. package/themes/default.ts +1 -11
  129. package/utils/css.ts +11 -0
  130. package/utils/icons.ts +75416 -0
  131. package/utils/index.ts +5 -1
  132. package/utils/levenshtein.ts +97 -0
  133. package/utils/sort.ts +9 -0
  134. package/components/FSDatePicker.vue +0 -226
  135. package/composables/useDates.ts +0 -39
  136. package/models/FSTags.ts +0 -8
  137. package/models/FSTextFields.ts +0 -23
  138. package/styles/components/fs_date_picker.scss +0 -0
  139. /package/utils/{FSRichTextField.ts → lexical.ts} +0 -0
@@ -0,0 +1,211 @@
1
+ <template>
2
+ <v-menu
3
+ :closeOnContentClick="false"
4
+ :modelValue="menu && $props.editable"
5
+ @update:modelValue="(value) => menu = value"
6
+ >
7
+ <template #activator="{ props }">
8
+ <FSTextField
9
+ class="fs-date-field"
10
+ :label="$props.label"
11
+ :description="$props.description"
12
+ :color="$props.color"
13
+ :hideHeader="$props.hideHeader"
14
+ :required="$props.required"
15
+ :editable="$props.editable"
16
+ :error="messages.length > 0"
17
+ :readonly="true"
18
+ :modelValue="epochToLongDateFormat($props.modelValue)"
19
+ @click:clear="onClear"
20
+ v-bind="props"
21
+ >
22
+ <template v-if="!$props.hideHeader" #label>
23
+ <slot name="label">
24
+ <FSRow :wrap="false">
25
+ <FSSpan
26
+ v-if="$props.label"
27
+ class="fs-date-field-label"
28
+ font="text-overline"
29
+ :style="style"
30
+ >
31
+ {{ $props.label }}
32
+ </FSSpan>
33
+ <FSSpan
34
+ v-if="$props.label && $props.required"
35
+ class="fs-date-field-label"
36
+ style="margin-left: -8px;"
37
+ font="text-overline"
38
+ :ellipsis="false"
39
+ :style="style"
40
+ >
41
+ *
42
+ </FSSpan>
43
+ <v-spacer style="min-width: 40px;" />
44
+ <FSSpan
45
+ v-if="messages.length > 0"
46
+ class="fs-date-field-messages"
47
+ font="text-overline"
48
+ :style="style"
49
+ >
50
+ {{ messages.join(", ") }}
51
+ </FSSpan>
52
+ </FSRow>
53
+ </slot>
54
+ </template>
55
+ <template #prepend-inner>
56
+ <slot name="prepend-inner">
57
+ <FSButton
58
+ variant="icon"
59
+ icon="mdi-calendar"
60
+ :editable="$props.editable"
61
+ :color="ColorEnum.Dark"
62
+ />
63
+ </slot>
64
+ </template>
65
+ <template v-for="(_, name) in $slots" v-slot:[name]="slotData">
66
+ <slot :name="name" v-bind="slotData" />
67
+ </template>
68
+ </FSTextField>
69
+ </template>
70
+ <FSCard
71
+ width="394"
72
+ :elevation="true"
73
+ :border="false"
74
+ >
75
+ <FSCol width="fill">
76
+ <FSCalendar
77
+ :color="$props.color"
78
+ v-model="innerDate"
79
+ />
80
+ <FSButton
81
+ :fullWidth="true"
82
+ :color="$props.color"
83
+ :label="$tr('ui.date-menu.validate', 'Validate')"
84
+ @click="onSubmit"
85
+ />
86
+ </FSCol>
87
+ </FSCard>
88
+ </v-menu>
89
+ </template>
90
+
91
+ <script lang="ts">
92
+ import { computed, defineComponent, PropType, ref } from "vue";
93
+
94
+ import { ColorBase, ColorEnum } from "@dative-gpi/foundation-shared-components/models";
95
+ import { useTimeZone } from "@dative-gpi/foundation-shared-services/composables";
96
+ import { useColors } from "@dative-gpi/foundation-shared-components/composables";
97
+
98
+ import FSTextField from "./FSTextField.vue";
99
+ import FSCalendar from "./FSCalendar.vue";
100
+ import FSButton from "./FSButton.vue";
101
+ import FSCard from "./FSCard.vue";
102
+ import FSCol from "./FSCol.vue";
103
+
104
+ export default defineComponent({
105
+ name: "FSDateField",
106
+ components: {
107
+ FSTextField,
108
+ FSCalendar,
109
+ FSButton,
110
+ FSCard,
111
+ FSCol
112
+ },
113
+ props: {
114
+ label: {
115
+ type: String,
116
+ required: false,
117
+ default: null
118
+ },
119
+ description: {
120
+ type: String,
121
+ required: false,
122
+ default: null
123
+ },
124
+ modelValue: {
125
+ type: Number,
126
+ required: false,
127
+ default: null
128
+ },
129
+ color: {
130
+ type: String as PropType<ColorBase>,
131
+ required: false,
132
+ default: ColorEnum.Primary
133
+ },
134
+ hideHeader: {
135
+ type: Boolean,
136
+ required: false,
137
+ default: false
138
+ },
139
+ required: {
140
+ type: Boolean,
141
+ required: false,
142
+ default: false
143
+ },
144
+ rules: {
145
+ type: Array as PropType<Function[]>,
146
+ required: false,
147
+ default: () => []
148
+ },
149
+ editable: {
150
+ type: Boolean,
151
+ required: false,
152
+ default: true
153
+ }
154
+ },
155
+ emits: ["update:modelValue"],
156
+ setup(props, { emit }) {
157
+ const { epochToLongDateFormat } = useTimeZone();
158
+
159
+ const errors = useColors().getColors(ColorEnum.Error);
160
+ const lights = useColors().getColors(ColorEnum.Light);
161
+ const darks = useColors().getColors(ColorEnum.Dark);
162
+
163
+ const menu = ref(false);
164
+ const innerDate = ref(props.modelValue);
165
+
166
+ const style = computed((): {[code: string]: string} & Partial<CSSStyleDeclaration> => {
167
+ if (!props.editable) {
168
+ return {
169
+ "--fs-date-field-color": lights.dark
170
+ };
171
+ }
172
+ return {
173
+ "--fs-date-field-color" : darks.base,
174
+ "--fs-date-field-error-color": errors.base
175
+ };
176
+ });
177
+
178
+ const messages = computed((): string[] => {
179
+ const messages = [];
180
+ for (const rule of props.rules) {
181
+ const message = rule(props.modelValue ?? null);
182
+ if (typeof(message) === "string") {
183
+ messages.push(message);
184
+ }
185
+ }
186
+ return messages;
187
+ });
188
+
189
+ const onClear = (): void => {
190
+ emit("update:modelValue", null);
191
+ innerDate.value = null;
192
+ };
193
+
194
+ const onSubmit = (): void => {
195
+ emit("update:modelValue", innerDate.value);
196
+ menu.value = false;
197
+ };
198
+
199
+ return {
200
+ ColorEnum,
201
+ innerDate,
202
+ messages,
203
+ style,
204
+ menu,
205
+ onClear,
206
+ onSubmit,
207
+ epochToLongDateFormat
208
+ };
209
+ }
210
+ });
211
+ </script>
@@ -0,0 +1,225 @@
1
+ <template>
2
+ <FSTextField
3
+ class="fs-date-field"
4
+ :label="$props.label"
5
+ :description="$props.description"
6
+ :color="$props.color"
7
+ :hideHeader="$props.hideHeader"
8
+ :required="$props.required"
9
+ :editable="$props.editable"
10
+ :error="messages.length > 0"
11
+ :readonly="true"
12
+ :modelValue="placeholder"
13
+ @click="onClick"
14
+ @click:clear="onClear"
15
+ >
16
+ <template v-if="!$props.hideHeader" #label>
17
+ <slot name="label">
18
+ <FSRow :wrap="false">
19
+ <FSSpan
20
+ v-if="$props.label"
21
+ class="fs-date-field-label"
22
+ font="text-overline"
23
+ :style="style"
24
+ >
25
+ {{ $props.label }}
26
+ </FSSpan>
27
+ <FSSpan
28
+ v-if="$props.label && $props.required"
29
+ class="fs-date-field-label"
30
+ style="margin-left: -8px;"
31
+ font="text-overline"
32
+ :ellipsis="false"
33
+ :style="style"
34
+ >
35
+ *
36
+ </FSSpan>
37
+ <v-spacer style="min-width: 40px;" />
38
+ <FSSpan
39
+ v-if="messages.length > 0"
40
+ class="fs-date-field-messages"
41
+ font="text-overline"
42
+ :style="style"
43
+ >
44
+ {{ messages.join(", ") }}
45
+ </FSSpan>
46
+ </FSRow>
47
+ </slot>
48
+ </template>
49
+ <template #prepend-inner>
50
+ <slot name="prepend-inner">
51
+ <FSButton
52
+ variant="icon"
53
+ icon="mdi-calendar"
54
+ :editable="$props.editable"
55
+ :color="ColorEnum.Dark"
56
+ />
57
+ </slot>
58
+ </template>
59
+ <template v-for="(_, name) in $slots" v-slot:[name]="slotData">
60
+ <slot :name="name" v-bind="slotData" />
61
+ </template>
62
+ </FSTextField>
63
+ <FSSubmitDialog
64
+ :title="$props.label"
65
+ :rightButtonColor="$props.color"
66
+ @click:rightButton="onSubmit"
67
+ v-model="dialog"
68
+ >
69
+ <template #body>
70
+ <FSCalendarTwin
71
+ :color="$props.color"
72
+ v-model="innerDateRange"
73
+ />
74
+ </template>
75
+ </FSSubmitDialog>
76
+ </template>
77
+
78
+ <script lang="ts">
79
+ import { computed, defineComponent, PropType, ref } from "vue";
80
+
81
+ import { ColorBase, ColorEnum } from "@dative-gpi/foundation-shared-components/models";
82
+ import { useTimeZone } from "@dative-gpi/foundation-shared-services/composables";
83
+ import { useColors } from "@dative-gpi/foundation-shared-components/composables";
84
+
85
+ import FSSubmitDialog from "./FSSubmitDialog.vue";
86
+ import FSCalendarTwin from "./FSCalendarTwin.vue";
87
+ import FSTextField from "./FSTextField.vue";
88
+ import FSButton from "./FSButton.vue";
89
+ import FSCard from "./FSCard.vue";
90
+ import FSCol from "./FSCol.vue";
91
+
92
+ export default defineComponent({
93
+ name: "FSDateRangeField",
94
+ components: {
95
+ FSSubmitDialog,
96
+ FSCalendarTwin,
97
+ FSTextField,
98
+ FSButton,
99
+ FSCard,
100
+ FSCol
101
+ },
102
+ props: {
103
+ label: {
104
+ type: String,
105
+ required: false,
106
+ default: null
107
+ },
108
+ description: {
109
+ type: String,
110
+ required: false,
111
+ default: null
112
+ },
113
+ modelValue: {
114
+ type: Array as PropType<number[]>,
115
+ required: false,
116
+ default: null
117
+ },
118
+ color: {
119
+ type: String as PropType<ColorBase>,
120
+ required: false,
121
+ default: ColorEnum.Primary
122
+ },
123
+ hideHeader: {
124
+ type: Boolean,
125
+ required: false,
126
+ default: false
127
+ },
128
+ required: {
129
+ type: Boolean,
130
+ required: false,
131
+ default: false
132
+ },
133
+ rules: {
134
+ type: Array as PropType<Function[]>,
135
+ required: false,
136
+ default: () => []
137
+ },
138
+ editable: {
139
+ type: Boolean,
140
+ required: false,
141
+ default: true
142
+ }
143
+ },
144
+ emits: ["update:modelValue"],
145
+ setup(props, { emit }) {
146
+ const { epochToShortDateFormat } = useTimeZone();
147
+
148
+ const errors = useColors().getColors(ColorEnum.Error);
149
+ const lights = useColors().getColors(ColorEnum.Light);
150
+ const darks = useColors().getColors(ColorEnum.Dark);
151
+
152
+ const dialog = ref(false);
153
+ const innerDateRange = ref(props.modelValue);
154
+
155
+ const style = computed((): {[code: string]: string} & Partial<CSSStyleDeclaration> => {
156
+ if (!props.editable) {
157
+ return {
158
+ "--fs-date-field-color": lights.dark
159
+ };
160
+ }
161
+ return {
162
+ "--fs-date-field-color" : darks.base,
163
+ "--fs-date-field-error-color": errors.base
164
+ };
165
+ });
166
+
167
+ const placeholder = computed((): string => {
168
+ if (!props.modelValue || !Array.isArray(props.modelValue) || !props.modelValue.length) {
169
+ return "";
170
+ }
171
+ return props.modelValue.map((epoch) => epochToShortDateFormat(epoch)).join(" - ");
172
+ });
173
+
174
+ const messages = computed((): string[] => {
175
+ const messages = [];
176
+ for (const rule of props.rules) {
177
+ if (props.modelValue && Array.isArray(props.modelValue)) {
178
+ for (const value of props.modelValue) {
179
+ const message = rule(value);
180
+ if (typeof(message) === "string") {
181
+ messages.push(message);
182
+ break;
183
+ }
184
+ }
185
+ }
186
+ else {
187
+ const message = rule(null);
188
+ if (typeof(message) === "string") {
189
+ messages.push(message);
190
+ }
191
+ }
192
+ }
193
+ return messages;
194
+ });
195
+
196
+ const onClick = (): void => {
197
+ if (props.editable) {
198
+ dialog.value = true;
199
+ }
200
+ };
201
+
202
+ const onClear = (): void => {
203
+ emit("update:modelValue", null);
204
+ innerDateRange.value = null;
205
+ };
206
+
207
+ const onSubmit = (): void => {
208
+ emit("update:modelValue", innerDateRange.value);
209
+ dialog.value = false;
210
+ };
211
+
212
+ return {
213
+ ColorEnum,
214
+ messages,
215
+ style,
216
+ dialog,
217
+ placeholder,
218
+ innerDateRange,
219
+ onClick,
220
+ onClear,
221
+ onSubmit
222
+ };
223
+ }
224
+ });
225
+ </script>
@@ -0,0 +1,257 @@
1
+ <template>
2
+ <v-menu
3
+ :closeOnContentClick="false"
4
+ :modelValue="menu && $props.editable"
5
+ @update:modelValue="(value) => menu = value"
6
+ >
7
+ <template #activator="{ props }">
8
+ <FSTextField
9
+ class="fs-date-field"
10
+ :label="$props.label"
11
+ :description="$props.description"
12
+ :color="$props.color"
13
+ :hideHeader="$props.hideHeader"
14
+ :required="$props.required"
15
+ :editable="$props.editable"
16
+ :error="messages.length > 0"
17
+ :readonly="true"
18
+ :modelValue="epochToLongTimeFormat($props.modelValue)"
19
+ @click:clear="onClear"
20
+ v-bind="props"
21
+ >
22
+ <template v-if="!$props.hideHeader" #label>
23
+ <slot name="label">
24
+ <FSRow :wrap="false">
25
+ <FSSpan
26
+ v-if="$props.label"
27
+ class="fs-date-field-label"
28
+ font="text-overline"
29
+ :style="style"
30
+ >
31
+ {{ $props.label }}
32
+ </FSSpan>
33
+ <FSSpan
34
+ v-if="$props.label && $props.required"
35
+ class="fs-date-field-label"
36
+ style="margin-left: -8px;"
37
+ font="text-overline"
38
+ :ellipsis="false"
39
+ :style="style"
40
+ >
41
+ *
42
+ </FSSpan>
43
+ <v-spacer style="min-width: 40px;" />
44
+ <FSSpan
45
+ v-if="messages.length > 0"
46
+ class="fs-date-field-messages"
47
+ font="text-overline"
48
+ :style="style"
49
+ >
50
+ {{ messages.join(", ") }}
51
+ </FSSpan>
52
+ </FSRow>
53
+ </slot>
54
+ </template>
55
+ <template #prepend-inner>
56
+ <slot name="prepend-inner">
57
+ <FSButton
58
+ variant="icon"
59
+ icon="mdi-calendar"
60
+ :editable="$props.editable"
61
+ :color="ColorEnum.Dark"
62
+ />
63
+ </slot>
64
+ </template>
65
+ <template v-for="(_, name) in $slots" v-slot:[name]="slotData">
66
+ <slot :name="name" v-bind="slotData" />
67
+ </template>
68
+ </FSTextField>
69
+ </template>
70
+ <FSWindow
71
+ :modelValue="tabs"
72
+ >
73
+ <FSCard
74
+ width="394px"
75
+ :elevation="true"
76
+ :border="false"
77
+ :value="0"
78
+ >
79
+ <FSCol width="fill">
80
+ <FSCalendar
81
+ :color="$props.color"
82
+ v-model="innerDate"
83
+ />
84
+ <FSButton
85
+ :fullWidth="true"
86
+ :color="$props.color"
87
+ :label="$tr('ui.date-menu.validate', 'Validate')"
88
+ @click="tabs++"
89
+ />
90
+ </FSCol>
91
+ </FSCard>
92
+ <FSCard
93
+ width="394px"
94
+ :elevation="true"
95
+ :border="false"
96
+ :value="1"
97
+ >
98
+ <FSCol width="fill">
99
+ <FSClock
100
+ :color="$props.color"
101
+ v-model="innerTime"
102
+ />
103
+ <FSButton
104
+ :fullWidth="true"
105
+ :color="$props.color"
106
+ :label="$tr('ui.date-menu.validate', 'Validate')"
107
+ @click="onSubmit"
108
+ />
109
+ </FSCol>
110
+ </FSCard>
111
+ </FSWindow>
112
+ </v-menu>
113
+ </template>
114
+
115
+ <script lang="ts">
116
+ import { computed, defineComponent, PropType, ref, watch } from "vue";
117
+
118
+ import { ColorBase, ColorEnum } from "@dative-gpi/foundation-shared-components/models";
119
+ import { useTimeZone } from "@dative-gpi/foundation-shared-services/composables";
120
+ import { useColors } from "@dative-gpi/foundation-shared-components/composables";
121
+
122
+ import FSTextField from "./FSTextField.vue";
123
+ import FSCalendar from "./FSCalendar.vue";
124
+ import FSWindow from "./FSWindow.vue";
125
+ import FSButton from "./FSButton.vue";
126
+ import FSClock from "./FSClock.vue";
127
+ import FSCard from "./FSCard.vue";
128
+ import FSCol from "./FSCol.vue";
129
+
130
+ export default defineComponent({
131
+ name: "FSDateTimeField",
132
+ components: {
133
+ FSTextField,
134
+ FSCalendar,
135
+ FSWindow,
136
+ FSButton,
137
+ FSClock,
138
+ FSCard,
139
+ FSCol
140
+ },
141
+ props: {
142
+ label: {
143
+ type: String,
144
+ required: false,
145
+ default: null
146
+ },
147
+ description: {
148
+ type: String,
149
+ required: false,
150
+ default: null
151
+ },
152
+ modelValue: {
153
+ type: Number,
154
+ required: false,
155
+ default: null
156
+ },
157
+ color: {
158
+ type: String as PropType<ColorBase>,
159
+ required: false,
160
+ default: ColorEnum.Primary
161
+ },
162
+ hideHeader: {
163
+ type: Boolean,
164
+ required: false,
165
+ default: false
166
+ },
167
+ required: {
168
+ type: Boolean,
169
+ required: false,
170
+ default: false
171
+ },
172
+ rules: {
173
+ type: Array as PropType<Function[]>,
174
+ required: false,
175
+ default: () => []
176
+ },
177
+ editable: {
178
+ type: Boolean,
179
+ required: false,
180
+ default: true
181
+ }
182
+ },
183
+ emits: ["update:modelValue"],
184
+ setup(props, { emit }) {
185
+ const { getUserOffsetMillis, epochToLongTimeFormat } = useTimeZone();
186
+
187
+ const errors = useColors().getColors(ColorEnum.Error);
188
+ const lights = useColors().getColors(ColorEnum.Light);
189
+ const darks = useColors().getColors(ColorEnum.Dark);
190
+
191
+ const menu = ref(false);
192
+ const tabs = ref(0);
193
+
194
+ // FSClock just gives two numbers without consideration for the time zone
195
+ // We must adjust the time to the user's time zone
196
+ const innerTime = ref(0);
197
+ const innerDate = ref(null);
198
+ if (props.modelValue) {
199
+ innerTime.value = Math.floor((props.modelValue + getUserOffsetMillis()) % (24 * 60 * 60 * 1000));
200
+ innerDate.value = props.modelValue - innerTime.value;
201
+ }
202
+
203
+ const style = computed((): {[code: string]: string} & Partial<CSSStyleDeclaration> => {
204
+ if (!props.editable) {
205
+ return {
206
+ "--fs-date-field-color": lights.dark
207
+ };
208
+ }
209
+ return {
210
+ "--fs-date-field-color" : darks.base,
211
+ "--fs-date-field-error-color": errors.base
212
+ };
213
+ });
214
+
215
+ const messages = computed((): string[] => {
216
+ const messages = [];
217
+ for (const rule of props.rules) {
218
+ const message = rule(props.modelValue ?? null);
219
+ if (typeof(message) === "string") {
220
+ messages.push(message);
221
+ }
222
+ }
223
+ return messages;
224
+ });
225
+
226
+ const onClear = (): void => {
227
+ emit("update:modelValue", null);
228
+ innerDate.value = null;
229
+ innerTime.value = 0;
230
+ };
231
+
232
+ const onSubmit = (): void => {
233
+ emit("update:modelValue", innerDate.value + innerTime.value);
234
+ menu.value = false;
235
+ };
236
+
237
+ watch(menu, (): void => {
238
+ if (!menu.value) {
239
+ setTimeout(() => tabs.value = 0, 100);
240
+ }
241
+ });
242
+
243
+ return {
244
+ ColorEnum,
245
+ innerDate,
246
+ innerTime,
247
+ messages,
248
+ style,
249
+ menu,
250
+ tabs,
251
+ onClear,
252
+ onSubmit,
253
+ epochToLongTimeFormat
254
+ };
255
+ }
256
+ });
257
+ </script>