@dative-gpi/foundation-shared-components 0.0.11 → 0.0.13

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 (98) hide show
  1. package/aliases/FSButton.ts +8 -6
  2. package/components/FSBreadcrumbs.vue +3 -1
  3. package/components/FSButton.vue +13 -10
  4. package/components/FSCalendar.vue +4 -3
  5. package/components/FSCalendarTwin.vue +4 -3
  6. package/components/FSCarousel.vue +3 -1
  7. package/components/FSCheckbox.vue +8 -6
  8. package/components/FSChip.vue +5 -3
  9. package/components/FSClock.vue +50 -34
  10. package/components/FSColor.vue +3 -1
  11. package/components/FSColorIcon.vue +3 -1
  12. package/components/FSContainer.vue +4 -2
  13. package/components/FSDivider.vue +49 -8
  14. package/components/FSFadeOut.vue +3 -1
  15. package/components/FSFileButton.vue +4 -3
  16. package/components/FSForm.vue +52 -0
  17. package/components/FSImage.vue +42 -33
  18. package/components/FSLabel.vue +105 -0
  19. package/components/FSLink.vue +95 -0
  20. package/components/FSPagination.vue +96 -0
  21. package/components/FSPermissions.vue +0 -0
  22. package/components/FSRadio.vue +8 -6
  23. package/components/FSRemoveDialog.vue +1 -1
  24. package/components/FSSlideGroup.vue +2 -1
  25. package/components/FSSlider.vue +5 -3
  26. package/components/FSSubmitDialog.vue +2 -2
  27. package/components/FSSwitch.vue +9 -7
  28. package/components/FSTabs.vue +4 -3
  29. package/components/FSTag.vue +4 -2
  30. package/components/FSText.vue +3 -2
  31. package/components/FSWrapGroup.vue +2 -1
  32. package/components/deviceOrganisations/FSConnectivity.vue +2 -1
  33. package/components/deviceOrganisations/FSWorstAlert.vue +2 -1
  34. package/components/{FSAutocompleteField.vue → fields/FSAutocompleteField.vue} +25 -22
  35. package/components/fields/FSColorField.vue +194 -0
  36. package/components/{FSDateField.vue → fields/FSDateField.vue} +18 -52
  37. package/components/{FSDateRangeField.vue → fields/FSDateRangeField.vue} +22 -67
  38. package/components/{FSDateTimeField.vue → fields/FSDateTimeField.vue} +20 -54
  39. package/components/{FSDateTimeRangeField.vue → fields/FSDateTimeRangeField.vue} +27 -70
  40. package/components/{FSIconField.vue → fields/FSIconField.vue} +20 -53
  41. package/components/{FSNumberField.vue → fields/FSNumberField.vue} +0 -24
  42. package/components/{FSPasswordField.vue → fields/FSPasswordField.vue} +9 -31
  43. package/components/{FSRichTextField.vue → fields/FSRichTextField.vue} +10 -9
  44. package/components/{FSSearchField.vue → fields/FSSearchField.vue} +47 -14
  45. package/components/{FSSelectField.vue → fields/FSSelectField.vue} +22 -24
  46. package/components/{FSTagField.vue → fields/FSTagField.vue} +19 -53
  47. package/components/{FSTextArea.vue → fields/FSTextArea.vue} +28 -27
  48. package/components/{FSTextField.vue → fields/FSTextField.vue} +23 -21
  49. package/components/fields/FSTimeField.vue +104 -0
  50. package/components/fields/FSTimeSlotField.vue +263 -0
  51. package/components/lists/FSDataTableUI.vue +7 -6
  52. package/components/lists/FSFilterButton.vue +25 -17
  53. package/components/lists/FSHiddenButton.vue +1 -0
  54. package/components/lists/FSLoadDataTable.vue +88 -0
  55. package/components/tiles/FSDeviceOrganisationTileUI.vue +5 -10
  56. package/components/tiles/FSGroupTileUI.vue +5 -10
  57. package/components/{FSLoadTile.vue → tiles/FSLoadTile.vue} +9 -7
  58. package/components/{FSTile.vue → tiles/FSTile.vue} +5 -4
  59. package/composables/index.ts +2 -0
  60. package/composables/useBreakpoints.ts +7 -5
  61. package/composables/useDebounce.ts +22 -0
  62. package/composables/useRules.ts +72 -0
  63. package/elements/FSFormElement.ts +17 -0
  64. package/icons/flags/France.vue +9 -0
  65. package/icons/flags/Germany.vue +7 -0
  66. package/icons/flags/GreatBritain.vue +9 -0
  67. package/icons/flags/Italy.vue +9 -0
  68. package/icons/flags/Portugal.vue +59 -0
  69. package/icons/flags/Spain.vue +546 -0
  70. package/icons/flags/UnitedStates.vue +12 -0
  71. package/icons/sets.ts +17 -0
  72. package/models/rules.ts +10 -1
  73. package/package.json +6 -4
  74. package/pages/FSExternalIdentityButton.vue +64 -0
  75. package/pages/FSLanguageSetter.vue +140 -0
  76. package/pages/FSLoginPage.vue +253 -0
  77. package/styles/components/fs_clock.scss +4 -0
  78. package/styles/components/fs_color_field.scss +17 -0
  79. package/styles/components/fs_divider.scss +5 -0
  80. package/styles/components/fs_image.scss +12 -1
  81. package/styles/components/fs_label.scss +86 -0
  82. package/styles/components/fs_link.scss +6 -0
  83. package/styles/components/fs_load_data_table.scss +77 -0
  84. package/styles/components/fs_pagination.scss +11 -0
  85. package/styles/components/fs_time_field.scss +3 -0
  86. package/styles/components/fs_timeslot_field.scss +75 -0
  87. package/styles/components/index.scss +7 -0
  88. package/styles/globals/text_fonts.scss +18 -0
  89. package/styles/main.scss +3 -1
  90. package/styles/pages/fs_language_setter.scss +55 -0
  91. package/styles/pages/index.scss +1 -0
  92. package/utils/color.ts +7 -0
  93. package/utils/css.ts +2 -1
  94. package/utils/index.ts +3 -1
  95. package/utils/time.ts +29 -0
  96. package/components/FSHeaderButton.vue +0 -17
  97. package/components/lists/FSDataIteratorGroup.vue +0 -7
  98. package/index.ts +0 -6
@@ -41,13 +41,15 @@
41
41
  :items="$props.items"
42
42
  :autoSelectFirst="true"
43
43
  :multiple="$props.multiple"
44
- :error="messages.length > 0"
45
44
  :itemTitle="$props.itemTitle"
46
45
  :itemValue="$props.itemValue"
47
46
  :readonly="!$props.editable"
48
- :clearable="$props.editable"
47
+ :clearable="$props.editable && !!$props.modelValue"
48
+ :rules="$props.rules"
49
+ :validateOn="validateOn"
49
50
  :modelValue="$props.modelValue"
50
51
  @update:modelValue="(value) => $emit('update:modelValue', value)"
52
+ @blur="blurred = true"
51
53
  v-model:search="innerSearch"
52
54
  v-bind="$attrs"
53
55
  >
@@ -71,12 +73,12 @@
71
73
  <script lang="ts">
72
74
  import { computed, defineComponent, PropType, ref, watch } from "vue";
73
75
 
74
- import { useColors, useSlots } from "@dative-gpi/foundation-shared-components/composables";
76
+ import { useColors, useRules, useSlots } from "@dative-gpi/foundation-shared-components/composables";
75
77
  import { ColorEnum } from "@dative-gpi/foundation-shared-components/models";
76
78
 
77
- import FSSpan from "./FSSpan.vue";
78
- import FSCol from "./FSCol.vue";
79
- import FSRow from "./FSRow.vue";
79
+ import FSSpan from "../FSSpan.vue";
80
+ import FSCol from "../FSCol.vue";
81
+ import FSRow from "../FSRow.vue";
80
82
 
81
83
  export default defineComponent({
82
84
  name: "FSAutocompleteField",
@@ -135,6 +137,11 @@ export default defineComponent({
135
137
  required: false,
136
138
  default: () => []
137
139
  },
140
+ messages: {
141
+ type: Array as PropType<string[]>,
142
+ required: false,
143
+ default: null
144
+ },
138
145
  editable: {
139
146
  type: Boolean,
140
147
  required: false,
@@ -142,16 +149,19 @@ export default defineComponent({
142
149
  }
143
150
  },
144
151
  emits: ["update:modelValue", "update:search"],
145
- setup: (props, { emit }) => {
152
+ setup: (props, { emit }) => {
153
+ const { validateOn, blurred, getMessages } = useRules();
154
+ const { getColors } = useColors();
146
155
  const { slots } = useSlots();
156
+
147
157
  delete slots.label;
148
158
  delete slots.description;
149
159
 
150
- const innerSearch = ref("");
160
+ const errors = getColors(ColorEnum.Error);
161
+ const lights = getColors(ColorEnum.Light);
162
+ const darks = getColors(ColorEnum.Dark);
151
163
 
152
- const errors = useColors().getColors(ColorEnum.Error);
153
- const lights = useColors().getColors(ColorEnum.Light);
154
- const darks = useColors().getColors(ColorEnum.Dark);
164
+ const innerSearch = ref("");
155
165
 
156
166
  const style = computed((): {[code: string]: string} & Partial<CSSStyleDeclaration> => {
157
167
  if (!props.editable) {
@@ -172,17 +182,6 @@ export default defineComponent({
172
182
  };
173
183
  });
174
184
 
175
- const messages = computed((): string[] => {
176
- const messages = [];
177
- for (const rule of props.rules) {
178
- const message = rule(props.modelValue ?? "");
179
- if (typeof(message) === "string") {
180
- messages.push(message);
181
- }
182
- }
183
- return messages;
184
- });
185
-
186
185
  const classes = computed((): string[] => {
187
186
  const classNames = ["fs-autocomplete-field"];
188
187
  if (props.multiple) {
@@ -191,12 +190,16 @@ export default defineComponent({
191
190
  return classNames;
192
191
  });
193
192
 
193
+ const messages = computed((): string[] => props.messages ?? getMessages(props.modelValue, props.rules));
194
+
194
195
  watch(innerSearch, () => {
195
196
  emit("update:search", innerSearch.value);
196
197
  });
197
198
 
198
199
  return {
200
+ validateOn,
199
201
  messages,
202
+ blurred,
200
203
  slots,
201
204
  style,
202
205
  classes,
@@ -0,0 +1,194 @@
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
+ <FSRow
9
+ height="fill"
10
+ v-bind="props"
11
+ >
12
+ <FSTextField
13
+ class="fs-color-field"
14
+ :hideHeader="$props.hideHeader"
15
+ :required="$props.required"
16
+ :editable="$props.editable"
17
+ :clearable="false"
18
+ :readonly="true"
19
+ :modelValue="innerColor"
20
+ v-bind="$attrs"
21
+ >
22
+ <template #prepend-inner>
23
+ <slot name="prepend-inner">
24
+ <FSIcon
25
+ size="xl"
26
+ :color="innerColor"
27
+ >
28
+ mdi-circle
29
+ </FSIcon>
30
+ </slot>
31
+ </template>
32
+ <template #append>
33
+ <FSButton
34
+ prependIcon="mdi-pencil"
35
+ variant="full"
36
+ :editable="$props.editable"
37
+ />
38
+ </template>
39
+ </FSTextField>
40
+ <FSTextField
41
+ class="fs-color-field-opacity"
42
+ :label="$tr('ui.color-field.opacity', 'Opacity')"
43
+ :hideHeader="$props.hideHeader"
44
+ :required="$props.required"
45
+ :editable="$props.editable"
46
+ :clearable="false"
47
+ :readonly="true"
48
+ :modelValue="(Math.round(getPercentageFromHex(innerOpacity)*100)) + ' %'"
49
+ >
50
+ <template #prepend-inner>
51
+ <slot name="prepend-inner">
52
+ <FSIcon
53
+ icon="mdi-circle"
54
+ size="xl"
55
+ :color="ColorEnum.Dark"
56
+ :editable="$props.editable"
57
+ :style="{ opacity: getPercentageFromHex(innerOpacity) }"
58
+ />
59
+ </slot>
60
+ </template>
61
+ <template #append>
62
+ <FSButton
63
+ prependIcon="mdi-pencil"
64
+ variant="full"
65
+ :editable="$props.editable"
66
+ />
67
+ </template>
68
+ </FSTextField>
69
+ </FSRow>
70
+ </template>
71
+ <FSCard
72
+ :elevation="true"
73
+ :border="false"
74
+ >
75
+ <FSCol
76
+ width="fill"
77
+ >
78
+ <v-color-picker
79
+ class="fs-color-field-picker"
80
+ mode="hexa"
81
+ :elevation="0"
82
+ :modes="['hexa', 'rgba']"
83
+ :modelValue="fullColor"
84
+ @update:modelValue="onSubmit"
85
+ />
86
+ </FSCol>
87
+ </FSCard>
88
+ </v-menu>
89
+ </template>
90
+
91
+ <script lang="ts">
92
+ import { computed, defineComponent, ref } from "vue";
93
+
94
+ import { getPercentageFromHex, getHexFromPercentage } from "@dative-gpi/foundation-shared-components/utils";
95
+ import { useColors } from "@dative-gpi/foundation-shared-components/composables";
96
+ import { ColorEnum } from "@dative-gpi/foundation-shared-components/models";
97
+
98
+ import FSTextField from "./FSTextField.vue";
99
+ import FSButton from "../FSButton.vue";
100
+ import FSCard from "../FSCard.vue";
101
+ import FSIcon from "../FSIcon.vue";
102
+ import FSRow from "../FSRow.vue";
103
+ import FSCol from "../FSCol.vue";
104
+
105
+ export default defineComponent({
106
+ name: "FSColorField",
107
+ components: {
108
+ FSTextField,
109
+ FSButton,
110
+ FSCard,
111
+ FSIcon,
112
+ FSCol,
113
+ FSRow
114
+ },
115
+ props: {
116
+ modelValue: {
117
+ type: String,
118
+ required: false,
119
+ default: "#000000"
120
+ },
121
+ opacityValue: {
122
+ type: Number,
123
+ required: false,
124
+ default: 1
125
+ },
126
+ hideHeader: {
127
+ type: Boolean,
128
+ required: false,
129
+ default: false
130
+ },
131
+ required: {
132
+ type: Boolean,
133
+ required: false,
134
+ default: false
135
+ },
136
+ editable: {
137
+ type: Boolean,
138
+ required: false,
139
+ default: true
140
+ }
141
+ },
142
+ emits: ["update:modelValue", "update:opacity"],
143
+ setup(props, { emit }) {
144
+ const innerColor = ref(props.modelValue.toString().substring(0, 7));
145
+ const innerOpacity = ref(getHexFromPercentage(props.opacityValue));
146
+ const fullColor = ref(innerColor.value + innerOpacity.value);
147
+
148
+ const menu = ref(false);
149
+
150
+ const errors = useColors().getColors(ColorEnum.Error);
151
+ const lights = useColors().getColors(ColorEnum.Light);
152
+ const darks = useColors().getColors(ColorEnum.Dark);
153
+
154
+ const style = computed((): {[code: string]: string} & Partial<CSSStyleDeclaration> => {
155
+ if (!props.editable) {
156
+ return {
157
+ "--fs-color-field-cursor" : "default",
158
+ "--fs-color-field-border-color" : lights.base,
159
+ "--fs-color-field-color" : lights.dark,
160
+ "--fs-color-field-active-border-color": lights.base
161
+ };
162
+ }
163
+ return {
164
+ "--fs-color-field-cursor" : "text",
165
+ "--fs-color-field-border-color" : lights.dark,
166
+ "--fs-color-field-color" : darks.base,
167
+ "--fs-color-field-active-border-color": darks.dark,
168
+ "--fs-color-field-error-color" : errors.base,
169
+ "--fs-color-field-error-border-color" : errors.base
170
+ };
171
+ });
172
+
173
+
174
+ const onSubmit = (value: string) => {
175
+ innerColor.value = value.substring(0, 7);
176
+ innerOpacity.value = value.length === 9 ? value.substring(7, 9) : "FF";
177
+ fullColor.value = innerColor.value + innerOpacity.value;
178
+ emit("update:modelValue", innerColor.value);
179
+ emit("update:opacity", getPercentageFromHex(innerOpacity.value));
180
+ };
181
+
182
+ return {
183
+ ColorEnum,
184
+ getPercentageFromHex,
185
+ onSubmit,
186
+ innerColor,
187
+ innerOpacity,
188
+ fullColor,
189
+ style,
190
+ menu
191
+ };
192
+ }
193
+ });
194
+ </script>
@@ -13,45 +13,16 @@
13
13
  :hideHeader="$props.hideHeader"
14
14
  :required="$props.required"
15
15
  :editable="$props.editable"
16
- :error="messages.length > 0"
17
16
  :readonly="true"
17
+ :rules="$props.rules"
18
+ :messages="messages"
19
+ :validateOn="validateOn"
20
+ :validationValue="$props.modelValue"
18
21
  :modelValue="epochToLongDateFormat($props.modelValue)"
19
22
  @click:clear="onClear"
23
+ @blur="blurred = true"
20
24
  v-bind="props"
21
25
  >
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
26
  <template #prepend-inner>
56
27
  <slot name="prepend-inner">
57
28
  <FSButton
@@ -91,15 +62,15 @@
91
62
  <script lang="ts">
92
63
  import { computed, defineComponent, PropType, ref } from "vue";
93
64
 
65
+ import { useColors, useRules } from "@dative-gpi/foundation-shared-components/composables";
94
66
  import { ColorBase, ColorEnum } from "@dative-gpi/foundation-shared-components/models";
95
67
  import { useTimeZone } from "@dative-gpi/foundation-shared-services/composables";
96
- import { useColors } from "@dative-gpi/foundation-shared-components/composables";
97
68
 
98
69
  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";
70
+ import FSCalendar from "../FSCalendar.vue";
71
+ import FSButton from "../FSButton.vue";
72
+ import FSCard from "../FSCard.vue";
73
+ import FSCol from "../FSCol.vue";
103
74
 
104
75
  export default defineComponent({
105
76
  name: "FSDateField",
@@ -154,11 +125,13 @@ export default defineComponent({
154
125
  },
155
126
  emits: ["update:modelValue"],
156
127
  setup(props, { emit }) {
128
+ const {validateOn, blurred, getMessages} = useRules();
157
129
  const { epochToLongDateFormat } = useTimeZone();
130
+ const { getColors } = useColors();
158
131
 
159
- const errors = useColors().getColors(ColorEnum.Error);
160
- const lights = useColors().getColors(ColorEnum.Light);
161
- const darks = useColors().getColors(ColorEnum.Dark);
132
+ const errors = getColors(ColorEnum.Error);
133
+ const lights = getColors(ColorEnum.Light);
134
+ const darks = getColors(ColorEnum.Dark);
162
135
 
163
136
  const menu = ref(false);
164
137
  const innerDate = ref(props.modelValue);
@@ -175,16 +148,7 @@ export default defineComponent({
175
148
  };
176
149
  });
177
150
 
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
- });
151
+ const messages = computed((): string[] => getMessages(props.modelValue, props.rules));
188
152
 
189
153
  const onClear = (): void => {
190
154
  emit("update:modelValue", null);
@@ -199,7 +163,9 @@ export default defineComponent({
199
163
  return {
200
164
  ColorEnum,
201
165
  innerDate,
166
+ validateOn,
202
167
  messages,
168
+ blurred,
203
169
  style,
204
170
  menu,
205
171
  onClear,
@@ -7,45 +7,16 @@
7
7
  :hideHeader="$props.hideHeader"
8
8
  :required="$props.required"
9
9
  :editable="$props.editable"
10
- :error="messages.length > 0"
11
10
  :readonly="true"
12
- :modelValue="placeholder"
11
+ :rules="$props.rules"
12
+ :messages="messages"
13
+ :validateOn="validateOn"
14
+ :validationValue="$props.modelValue"
15
+ :modelValue="toShortDateFormat"
13
16
  @click="onClick"
14
17
  @click:clear="onClear"
18
+ @blur="blurred = true"
15
19
  >
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
20
  <template #prepend-inner>
50
21
  <slot name="prepend-inner">
51
22
  <FSButton
@@ -78,16 +49,16 @@
78
49
  <script lang="ts">
79
50
  import { computed, defineComponent, PropType, ref } from "vue";
80
51
 
52
+ import { useColors, useRules } from "@dative-gpi/foundation-shared-components/composables";
81
53
  import { ColorBase, ColorEnum } from "@dative-gpi/foundation-shared-components/models";
82
54
  import { useTimeZone } from "@dative-gpi/foundation-shared-services/composables";
83
- import { useColors } from "@dative-gpi/foundation-shared-components/composables";
84
55
 
85
- import FSSubmitDialog from "./FSSubmitDialog.vue";
86
- import FSCalendarTwin from "./FSCalendarTwin.vue";
56
+ import FSSubmitDialog from "../FSSubmitDialog.vue";
57
+ import FSCalendarTwin from "../FSCalendarTwin.vue";
87
58
  import FSTextField from "./FSTextField.vue";
88
- import FSButton from "./FSButton.vue";
89
- import FSCard from "./FSCard.vue";
90
- import FSCol from "./FSCol.vue";
59
+ import FSButton from "../FSButton.vue";
60
+ import FSCard from "../FSCard.vue";
61
+ import FSCol from "../FSCol.vue";
91
62
 
92
63
  export default defineComponent({
93
64
  name: "FSDateRangeField",
@@ -143,11 +114,13 @@ export default defineComponent({
143
114
  },
144
115
  emits: ["update:modelValue"],
145
116
  setup(props, { emit }) {
117
+ const { validateOn, blurred, getMessages } = useRules();
146
118
  const { epochToShortDateFormat } = useTimeZone();
119
+ const { getColors } = useColors();
147
120
 
148
- const errors = useColors().getColors(ColorEnum.Error);
149
- const lights = useColors().getColors(ColorEnum.Light);
150
- const darks = useColors().getColors(ColorEnum.Dark);
121
+ const errors = getColors(ColorEnum.Error);
122
+ const lights = getColors(ColorEnum.Light);
123
+ const darks = getColors(ColorEnum.Dark);
151
124
 
152
125
  const dialog = ref(false);
153
126
  const innerDateRange = ref(props.modelValue);
@@ -164,34 +137,14 @@ export default defineComponent({
164
137
  };
165
138
  });
166
139
 
167
- const placeholder = computed((): string => {
140
+ const toShortDateFormat = computed((): string => {
168
141
  if (!props.modelValue || !Array.isArray(props.modelValue) || !props.modelValue.length) {
169
142
  return "";
170
143
  }
171
144
  return props.modelValue.map((epoch) => epochToShortDateFormat(epoch)).join(" - ");
172
145
  });
173
146
 
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
- });
147
+ const messages = computed((): string[] => getMessages(props.modelValue, props.rules, true));
195
148
 
196
149
  const onClick = (): void => {
197
150
  if (props.editable) {
@@ -211,10 +164,12 @@ export default defineComponent({
211
164
 
212
165
  return {
213
166
  ColorEnum,
167
+ validateOn,
214
168
  messages,
169
+ blurred,
215
170
  style,
216
171
  dialog,
217
- placeholder,
172
+ toShortDateFormat,
218
173
  innerDateRange,
219
174
  onClick,
220
175
  onClear,
@@ -13,45 +13,16 @@
13
13
  :hideHeader="$props.hideHeader"
14
14
  :required="$props.required"
15
15
  :editable="$props.editable"
16
- :error="messages.length > 0"
17
16
  :readonly="true"
17
+ :rules="$props.rules"
18
+ :messages="messages"
19
+ :validateOn="validateOn"
20
+ :validationValue="$props.modelValue"
18
21
  :modelValue="epochToLongTimeFormat($props.modelValue)"
19
22
  @click:clear="onClear"
23
+ @blur="blurred = true"
20
24
  v-bind="props"
21
25
  >
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
26
  <template #prepend-inner>
56
27
  <slot name="prepend-inner">
57
28
  <FSButton
@@ -115,17 +86,17 @@
115
86
  <script lang="ts">
116
87
  import { computed, defineComponent, PropType, ref, watch } from "vue";
117
88
 
89
+ import { useColors, useRules } from "@dative-gpi/foundation-shared-components/composables";
118
90
  import { ColorBase, ColorEnum } from "@dative-gpi/foundation-shared-components/models";
119
91
  import { useTimeZone } from "@dative-gpi/foundation-shared-services/composables";
120
- import { useColors } from "@dative-gpi/foundation-shared-components/composables";
121
92
 
122
93
  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";
94
+ import FSCalendar from "../FSCalendar.vue";
95
+ import FSWindow from "../FSWindow.vue";
96
+ import FSButton from "../FSButton.vue";
97
+ import FSClock from "../FSClock.vue";
98
+ import FSCard from "../FSCard.vue";
99
+ import FSCol from "../FSCol.vue";
129
100
 
130
101
  export default defineComponent({
131
102
  name: "FSDateTimeField",
@@ -183,10 +154,12 @@ export default defineComponent({
183
154
  emits: ["update:modelValue"],
184
155
  setup(props, { emit }) {
185
156
  const { getUserOffsetMillis, epochToLongTimeFormat } = useTimeZone();
157
+ const { validateOn, blurred, getMessages } = useRules();
158
+ const { getColors } = useColors();
186
159
 
187
- const errors = useColors().getColors(ColorEnum.Error);
188
- const lights = useColors().getColors(ColorEnum.Light);
189
- const darks = useColors().getColors(ColorEnum.Dark);
160
+ const errors = getColors(ColorEnum.Error);
161
+ const lights = getColors(ColorEnum.Light);
162
+ const darks = getColors(ColorEnum.Dark);
190
163
 
191
164
  const menu = ref(false);
192
165
  const tabs = ref(0);
@@ -212,16 +185,7 @@ export default defineComponent({
212
185
  };
213
186
  });
214
187
 
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
- });
188
+ const messages = computed((): string[] => getMessages(props.modelValue, props.rules));
225
189
 
226
190
  const onClear = (): void => {
227
191
  emit("update:modelValue", null);
@@ -244,7 +208,9 @@ export default defineComponent({
244
208
  ColorEnum,
245
209
  innerDate,
246
210
  innerTime,
211
+ validateOn,
247
212
  messages,
213
+ blurred,
248
214
  style,
249
215
  menu,
250
216
  tabs,