@propelinc/citrus-ui 1.0.4 → 1.3.0
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.
- package/README.md +51 -14
- package/dist/citrus-ui.cdn.css +1 -0
- package/dist/citrus-ui.css +1 -0
- package/dist/colors/colors.d.ts +31 -0
- package/dist/colors/theme.d.ts +3 -0
- package/dist/colors/util-classes.d.ts +11 -0
- package/dist/components/CAccordion.vue.d.ts +34 -0
- package/dist/components/CAccordionItem.vue.d.ts +39 -0
- package/dist/components/CAppBar.vue.d.ts +59 -0
- package/dist/components/CBadge.vue.d.ts +35 -0
- package/dist/components/CBottomSheet.vue.d.ts +90 -0
- package/dist/components/CButton/CButton.vue.d.ts +97 -0
- package/dist/components/CButton/types.d.ts +5 -0
- package/dist/components/CButtonStack.vue.d.ts +27 -0
- package/dist/components/CCard.vue.d.ts +53 -0
- package/dist/components/CCardFooter.vue.d.ts +20 -0
- package/dist/components/CCardHeader.vue.d.ts +22 -0
- package/dist/components/CCardSection.vue.d.ts +26 -0
- package/dist/components/CCheckbox.vue.d.ts +62 -0
- package/dist/components/CCol.vue.d.ts +30 -0
- package/dist/components/CDivider.vue.d.ts +9 -0
- package/dist/components/CDobField.vue.d.ts +60 -0
- package/dist/components/CDobSelect.vue.d.ts +50 -0
- package/dist/components/CEmailField.vue.d.ts +48 -0
- package/dist/components/CExpandTransition.vue.d.ts +29 -0
- package/dist/components/CFadeTransition.vue.d.ts +20 -0
- package/dist/components/CFileInput.vue.d.ts +50 -0
- package/dist/components/CFixedPageFooter.vue.d.ts +153 -0
- package/dist/components/CForm.vue.d.ts +44 -0
- package/dist/components/CFormFieldCounter.vue.d.ts +15 -0
- package/dist/components/CIconButton.vue.d.ts +97 -0
- package/dist/components/CLabel.vue.d.ts +36 -0
- package/dist/components/CListItem.vue.d.ts +56 -0
- package/dist/components/CListItemContent.vue.d.ts +27 -0
- package/dist/components/CListItemIcon.vue.d.ts +28 -0
- package/dist/components/CLoader.vue.d.ts +23 -0
- package/dist/components/CLogo.vue.d.ts +9 -0
- package/dist/components/CMaskedTextField.vue.d.ts +511 -0
- package/dist/components/CMenu.vue.d.ts +17 -0
- package/dist/components/CMenuItem.vue.d.ts +37 -0
- package/dist/components/CMenuLabel.vue.d.ts +20 -0
- package/dist/components/CModal.vue.d.ts +59 -0
- package/dist/components/CModalLoading.vue.d.ts +36 -0
- package/dist/components/CNotification.vue.d.ts +64 -0
- package/dist/components/CPhoneField.vue.d.ts +792 -0
- package/dist/components/CPill.vue.d.ts +41 -0
- package/dist/components/CPillGroup.vue.d.ts +39 -0
- package/dist/components/CPopup.vue.d.ts +37 -0
- package/dist/components/CProgressLinear.vue.d.ts +21 -0
- package/dist/components/CProgressRing.vue.d.ts +48 -0
- package/dist/components/CRadio.vue.d.ts +40 -0
- package/dist/components/CRadioGroup.vue.d.ts +54 -0
- package/dist/components/CRebrand.vue.d.ts +28 -0
- package/dist/components/CRow.vue.d.ts +41 -0
- package/dist/components/CSafeArea.vue.d.ts +18 -0
- package/dist/components/CSectionHeader.vue.d.ts +29 -0
- package/dist/components/CSelect.vue.d.ts +96 -0
- package/dist/components/CSkeleton.vue.d.ts +3 -0
- package/dist/components/CSkeletonLoaderCard.vue.d.ts +9 -0
- package/dist/components/CSkeletonLoaderCircle.vue.d.ts +3 -0
- package/dist/components/CSkeletonLoaderText.vue.d.ts +16 -0
- package/dist/components/CSlideFadeTransition.vue.d.ts +36 -0
- package/dist/components/CSplitInput.vue.d.ts +56 -0
- package/dist/components/CSquaredIcon.vue.d.ts +33 -0
- package/dist/components/CSsnField.vue.d.ts +798 -0
- package/dist/components/CStatusDot.vue.d.ts +10 -0
- package/dist/components/CSwitch.vue.d.ts +39 -0
- package/dist/components/CSwitchListItem.vue.d.ts +48 -0
- package/dist/components/CTextArea.vue.d.ts +96 -0
- package/dist/components/CTextField.vue.d.ts +129 -0
- package/dist/components/CTextLink.vue.d.ts +36 -0
- package/dist/components/CThirdPartyLogo.vue.d.ts +22 -0
- package/dist/components/CTimeago.vue.d.ts +12 -0
- package/dist/components/CToast.vue.d.ts +69 -0
- package/dist/components/CToastsList.vue.d.ts +3 -0
- package/dist/components/CValidationMessage.vue.d.ts +37 -0
- package/dist/components/CZipcodeField.vue.d.ts +796 -0
- package/dist/components/index.d.ts +66 -0
- package/dist/components/internal/CCloseButton.vue.d.ts +14 -0
- package/dist/composables/accessibility.d.ts +1 -0
- package/dist/composables/animation.d.ts +12 -0
- package/dist/composables/binding.d.ts +19 -0
- package/dist/composables/colors.d.ts +13 -0
- package/dist/composables/elements.d.ts +3 -0
- package/dist/composables/fields.d.ts +10 -0
- package/dist/composables/gestures.d.ts +53 -0
- package/dist/composables/i18n.d.ts +3 -0
- package/dist/composables/id.d.ts +11 -0
- package/dist/composables/input-mask.d.ts +18 -0
- package/dist/composables/router.d.ts +30 -0
- package/dist/composables/slots.d.ts +2 -0
- package/dist/composables/toast.d.ts +21 -0
- package/dist/composables/validations.d.ts +77 -0
- package/dist/icons.cdn.mjs +3 -0
- package/dist/icons.cdn.mjs.map +1 -0
- package/dist/icons.d.ts +1 -0
- package/dist/icons.mjs +6 -0
- package/dist/icons.mjs.map +1 -0
- package/dist/index.cdn.mjs +9328 -12875
- package/dist/index.cdn.mjs.map +1 -1
- package/dist/index.cdn2.mjs +55255 -0
- package/dist/index.cdn2.mjs.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.mjs +3946 -0
- package/dist/index.mjs.map +1 -0
- package/dist/plugin.d.ts +3 -0
- package/dist/services/animation.d.ts +17 -0
- package/dist/services/directives/index.d.ts +2 -0
- package/dist/services/directives/scroll-into-view.d.ts +7 -0
- package/dist/services/directives/tap-animation.d.ts +6 -0
- package/dist/services/id.d.ts +22 -0
- package/dist/services/injections/accordions.d.ts +3 -0
- package/dist/services/injections/animations.d.ts +2 -0
- package/dist/services/injections/buttons.d.ts +4 -0
- package/dist/services/injections/forms.d.ts +6 -0
- package/dist/services/injections/icon-buttons.d.ts +3 -0
- package/dist/services/injections/pills.d.ts +4 -0
- package/dist/services/injections/radio.d.ts +10 -0
- package/dist/{styles/main.css → styles.css} +40 -2
- package/dist/theme/icons.d.ts +36 -0
- package/dist/types/CForm.d.ts +12 -0
- package/dist/types/font-awesome.d.ts +5 -0
- package/dist/types.d.ts +13 -0
- package/package.json +11 -4
- package/src/colors/colors.ts +8 -3
- package/src/components/CAccordion.vue +31 -24
- package/src/components/CAccordionItem.vue +46 -45
- package/src/components/CAppBar.vue +108 -101
- package/src/components/CBadge.vue +33 -25
- package/src/components/CBottomSheet.vue +212 -199
- package/src/components/CButton/CButton.vue +135 -147
- package/src/components/CButtonStack.vue +21 -13
- package/src/components/CCard.vue +72 -69
- package/src/components/CCardFooter.vue +5 -5
- package/src/components/CCardHeader.vue +9 -7
- package/src/components/CCardSection.vue +15 -8
- package/src/components/CCheckbox.vue +68 -69
- package/src/components/CCol.vue +21 -22
- package/src/components/CDivider.vue +9 -8
- package/src/components/CDobField.vue +114 -105
- package/src/components/CDobSelect.vue +162 -164
- package/src/components/CEmailField.vue +39 -27
- package/src/components/CExpandTransition.vue +14 -17
- package/src/components/CFadeTransition.vue +3 -3
- package/src/components/CFileInput.vue +57 -50
- package/src/components/CFixedPageFooter.vue +23 -17
- package/src/components/CForm.vue +67 -60
- package/src/components/CFormFieldCounter.vue +25 -28
- package/src/components/CIconButton.vue +84 -65
- package/src/components/CLabel.vue +19 -13
- package/src/components/CListItem.vue +67 -66
- package/src/components/CListItemContent.vue +14 -16
- package/src/components/CListItemIcon.vue +18 -14
- package/src/components/CLoader.vue +47 -56
- package/src/components/CLogo.vue +13 -12
- package/src/components/CMaskedTextField.vue +80 -64
- package/src/components/CMenu.vue +14 -6
- package/src/components/CMenuItem.vue +28 -22
- package/src/components/CMenuLabel.vue +6 -5
- package/src/components/CModal.vue +76 -71
- package/src/components/CModalLoading.vue +24 -15
- package/src/components/CNotification.vue +77 -28
- package/src/components/CPhoneField.vue +34 -25
- package/src/components/CPill.vue +92 -88
- package/src/components/CPillGroup.vue +30 -21
- package/src/components/CPopup.vue +46 -37
- package/src/components/CProgressLinear.vue +17 -11
- package/src/components/CProgressRing.vue +33 -33
- package/src/components/CRadio.vue +57 -57
- package/src/components/CRadioGroup.vue +85 -72
- package/src/components/CRow.vue +22 -20
- package/src/components/CSectionHeader.vue +20 -12
- package/src/components/CSelect.vue +89 -73
- package/src/components/CSkeletonLoaderCard.vue +9 -15
- package/src/components/CSkeletonLoaderCircle.vue +1 -9
- package/src/components/CSkeletonLoaderText.vue +17 -18
- package/src/components/CSlideFadeTransition.vue +12 -34
- package/src/components/CSplitInput.vue +46 -45
- package/src/components/CSquaredIcon.vue +39 -29
- package/src/components/CSsnField.vue +48 -36
- package/src/components/CStatusDot.vue +16 -16
- package/src/components/CSwitch.vue +31 -22
- package/src/components/CSwitchListItem.vue +27 -28
- package/src/components/CTextArea.vue +116 -83
- package/src/components/CTextField.vue +194 -198
- package/src/components/CTextLink.vue +28 -25
- package/src/components/CThirdPartyLogo.vue +30 -59
- package/src/components/CToast.vue +135 -132
- package/src/components/CToastsList.vue +2 -15
- package/src/components/CValidationMessage.vue +31 -24
- package/src/components/CZipcodeField.vue +40 -27
- package/src/composables/elements.ts +1 -1
- package/src/composables/fields.ts +4 -4
- package/src/composables/router.ts +6 -5
- package/src/icons.ts +6 -0
- package/src/services/injections/buttons.ts +1 -1
- package/src/styles/_core.scss +1 -2
- package/src/styles/_reset.scss +1 -1
- package/src/styles/main.scss +2 -0
- package/src/types.ts +2 -0
- package/dist/index.cdn.css +0 -1
- package/dist/styles/utils.css +0 -2709
|
@@ -40,90 +40,89 @@
|
|
|
40
40
|
</div>
|
|
41
41
|
</template>
|
|
42
42
|
|
|
43
|
-
<script lang="ts">
|
|
43
|
+
<script setup lang="ts">
|
|
44
44
|
import { faCheck } from '@fortawesome/pro-regular-svg-icons';
|
|
45
45
|
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
|
|
46
|
-
import type {
|
|
47
|
-
import {
|
|
46
|
+
import type { VNode } from 'vue';
|
|
47
|
+
import { ref, toRefs } from 'vue';
|
|
48
48
|
|
|
49
49
|
import CValidationMessage from '@propelinc/citrus-ui/src/components/CValidationMessage.vue';
|
|
50
50
|
import { useInternalValue } from '@propelinc/citrus-ui/src/composables/binding';
|
|
51
51
|
import { useId } from '@propelinc/citrus-ui/src/composables/id';
|
|
52
52
|
import { useValidations } from '@propelinc/citrus-ui/src/composables/validations';
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
components: { FontAwesomeIcon, CValidationMessage },
|
|
57
|
-
props: {
|
|
58
|
-
/** Assigns the checkbox's id */
|
|
59
|
-
id: { type: String as PropType<string | null>, default: null },
|
|
60
|
-
/** The label text for the checkbox. */
|
|
61
|
-
label: { type: String, default: undefined },
|
|
62
|
-
/** Whether the checkbox is checked */
|
|
63
|
-
value: { type: Boolean, default: false },
|
|
54
|
+
const props = withDefaults(
|
|
55
|
+
defineProps<{
|
|
64
56
|
/** A custom data-test selector */
|
|
65
|
-
dataTest
|
|
57
|
+
dataTest?: string;
|
|
58
|
+
/** Hides the validation message area. */
|
|
59
|
+
hideDetails?: boolean | 'auto';
|
|
60
|
+
/** Assigns the checkbox's id */
|
|
61
|
+
id?: string | null;
|
|
62
|
+
/** The label text for the checkbox */
|
|
63
|
+
label?: string;
|
|
66
64
|
/**
|
|
67
65
|
* An array of functions that either return either true / false or a string
|
|
68
66
|
* containing an error message. The component passes the input value as an
|
|
69
67
|
* argument. The input field will enter an error state if a function does
|
|
70
68
|
* not return true.
|
|
71
|
-
|
|
72
|
-
rules:
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
const onChange = (event: Event): void => {
|
|
111
|
-
const target = event.target as HTMLInputElement;
|
|
112
|
-
internalValue.value = !!target.checked;
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
return {
|
|
116
|
-
checkbox,
|
|
117
|
-
faCheck,
|
|
118
|
-
idWithFallback,
|
|
119
|
-
internalValue,
|
|
120
|
-
onChange,
|
|
121
|
-
validationMessage,
|
|
122
|
-
isValidationValid,
|
|
123
|
-
validationListeners,
|
|
124
|
-
};
|
|
125
|
-
},
|
|
69
|
+
*/
|
|
70
|
+
rules?: ((value: boolean) => string | boolean)[];
|
|
71
|
+
/** Whether the checkbox is checked */
|
|
72
|
+
value?: boolean;
|
|
73
|
+
/**
|
|
74
|
+
* Controls the appearance of the checkbox.
|
|
75
|
+
* @default 'contained'
|
|
76
|
+
*/
|
|
77
|
+
variant?: 'contained' | 'minimal';
|
|
78
|
+
}>(),
|
|
79
|
+
{
|
|
80
|
+
dataTest: 'checkbox',
|
|
81
|
+
hideDetails: false,
|
|
82
|
+
id: null,
|
|
83
|
+
label: undefined,
|
|
84
|
+
rules: () => [],
|
|
85
|
+
value: false,
|
|
86
|
+
variant: 'contained',
|
|
87
|
+
}
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
const emit = defineEmits<{
|
|
91
|
+
(e: 'change', value: boolean): void;
|
|
92
|
+
(e: 'focus'): void;
|
|
93
|
+
(e: 'blur'): void;
|
|
94
|
+
}>();
|
|
95
|
+
|
|
96
|
+
defineSlots<{
|
|
97
|
+
label?: () => VNode[];
|
|
98
|
+
message?: () => VNode[];
|
|
99
|
+
}>();
|
|
100
|
+
|
|
101
|
+
const { value, rules, id } = toRefs(props);
|
|
102
|
+
const idWithFallback = useId(id);
|
|
103
|
+
|
|
104
|
+
const internalValue = useInternalValue(value, {
|
|
105
|
+
onChange: (value) => emit('change', value),
|
|
126
106
|
});
|
|
107
|
+
|
|
108
|
+
const checkbox = ref<HTMLInputElement | null>(null);
|
|
109
|
+
|
|
110
|
+
const {
|
|
111
|
+
message: validationMessage,
|
|
112
|
+
valid: isValidationValid,
|
|
113
|
+
listeners: validationListeners,
|
|
114
|
+
} = useValidations({
|
|
115
|
+
id: idWithFallback,
|
|
116
|
+
value: internalValue,
|
|
117
|
+
rules,
|
|
118
|
+
validateOn: 'change',
|
|
119
|
+
field: checkbox,
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
const onChange = (event: Event): void => {
|
|
123
|
+
const target = event.target as HTMLInputElement;
|
|
124
|
+
internalValue.value = !!target.checked;
|
|
125
|
+
};
|
|
127
126
|
</script>
|
|
128
127
|
|
|
129
128
|
<style lang="scss" scoped>
|
package/src/components/CCol.vue
CHANGED
|
@@ -4,28 +4,27 @@
|
|
|
4
4
|
</div>
|
|
5
5
|
</template>
|
|
6
6
|
|
|
7
|
-
<script lang="ts">
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
});
|
|
7
|
+
<script setup lang="ts">
|
|
8
|
+
import type { VNode } from 'vue';
|
|
9
|
+
|
|
10
|
+
type Cols = 'auto' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10' | '11' | '12';
|
|
11
|
+
|
|
12
|
+
withDefaults(
|
|
13
|
+
defineProps<{
|
|
14
|
+
/**
|
|
15
|
+
* Sets the default number of columns the component extends.
|
|
16
|
+
* Available options are: 1 -> 12 and auto.
|
|
17
|
+
*/
|
|
18
|
+
cols?: Cols | null;
|
|
19
|
+
}>(),
|
|
20
|
+
{
|
|
21
|
+
cols: null,
|
|
22
|
+
}
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
defineSlots<{
|
|
26
|
+
default?: () => VNode[];
|
|
27
|
+
}>();
|
|
29
28
|
</script>
|
|
30
29
|
|
|
31
30
|
<style lang="scss" scoped>
|
|
@@ -6,15 +6,16 @@
|
|
|
6
6
|
/>
|
|
7
7
|
</template>
|
|
8
8
|
|
|
9
|
-
<script lang="ts">
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
export default defineComponent({
|
|
13
|
-
props: {
|
|
9
|
+
<script setup lang="ts">
|
|
10
|
+
withDefaults(
|
|
11
|
+
defineProps<{
|
|
14
12
|
/** Displays dividers vertically. */
|
|
15
|
-
vertical
|
|
16
|
-
},
|
|
17
|
-
|
|
13
|
+
vertical?: boolean;
|
|
14
|
+
}>(),
|
|
15
|
+
{
|
|
16
|
+
vertical: false,
|
|
17
|
+
}
|
|
18
|
+
);
|
|
18
19
|
</script>
|
|
19
20
|
|
|
20
21
|
<style lang="scss" scoped>
|
|
@@ -28,10 +28,10 @@
|
|
|
28
28
|
</CMaskedTextField>
|
|
29
29
|
</template>
|
|
30
30
|
|
|
31
|
-
<script lang="ts">
|
|
31
|
+
<script setup lang="ts">
|
|
32
32
|
import dayjs from 'dayjs';
|
|
33
|
-
import {
|
|
34
|
-
import
|
|
33
|
+
import type { VNode } from 'vue';
|
|
34
|
+
import { computed, ref, watch } from 'vue';
|
|
35
35
|
|
|
36
36
|
import CMaskedTextField from '@propelinc/citrus-ui/src/components/CMaskedTextField.vue';
|
|
37
37
|
import { useTranslation } from '@propelinc/citrus-ui/src/composables/i18n';
|
|
@@ -41,113 +41,122 @@ import {
|
|
|
41
41
|
minLengthRule as createMinLengthRule,
|
|
42
42
|
} from '@propelinc/shared-utils';
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
components: { CMaskedTextField },
|
|
47
|
-
props: {
|
|
44
|
+
const props = withDefaults(
|
|
45
|
+
defineProps<{
|
|
48
46
|
/** A custom data-test attribute for the input. */
|
|
49
|
-
dataTest
|
|
47
|
+
dataTest?: string;
|
|
50
48
|
/** A unique id for the input. */
|
|
51
|
-
id
|
|
49
|
+
id?: string;
|
|
52
50
|
/** The input's label text. */
|
|
53
|
-
label
|
|
51
|
+
label?: string | null;
|
|
54
52
|
/** The input's placeholder. */
|
|
55
|
-
placeholder
|
|
53
|
+
placeholder?: string;
|
|
56
54
|
/** Additional validation rules. */
|
|
57
|
-
rules
|
|
55
|
+
rules?: Rules<string>;
|
|
58
56
|
/** The value of the input, must have the format YYYY-MM-DD or YYYY. */
|
|
59
|
-
value
|
|
60
|
-
/**
|
|
61
|
-
*
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
const computedLabel = computed(() => props.label || defaultLabel.value);
|
|
137
|
-
const computedPlaceholder = computed(() => props.placeholder || defaultPlaceholder.value);
|
|
138
|
-
const computedRules = computed(() => [...defaultRules.value, ...props.rules]);
|
|
139
|
-
const dateLength = computed(() => (props.yearOnly ? 4 : 8));
|
|
140
|
-
const mask = computed(() => (props.yearOnly ? '####' : '##/##/####'));
|
|
141
|
-
|
|
142
|
-
return {
|
|
143
|
-
computedLabel,
|
|
144
|
-
computedPlaceholder,
|
|
145
|
-
computedRules,
|
|
146
|
-
emitIsoDate,
|
|
147
|
-
formattedDate,
|
|
148
|
-
dateLength,
|
|
149
|
-
mask,
|
|
150
|
-
};
|
|
151
|
-
},
|
|
57
|
+
value?: string;
|
|
58
|
+
/**
|
|
59
|
+
* Toggles the field's year only variant. Changes default label, placeholder,
|
|
60
|
+
* mask and validation behavior
|
|
61
|
+
*/
|
|
62
|
+
yearOnly?: boolean;
|
|
63
|
+
}>(),
|
|
64
|
+
{
|
|
65
|
+
dataTest: 'dob-field',
|
|
66
|
+
id: undefined,
|
|
67
|
+
label: null,
|
|
68
|
+
placeholder: '',
|
|
69
|
+
rules: () => [],
|
|
70
|
+
value: '',
|
|
71
|
+
yearOnly: false,
|
|
72
|
+
}
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
const emit = defineEmits<{
|
|
76
|
+
(e: 'input', value: string): void;
|
|
77
|
+
(e: 'blur', event: Event): void;
|
|
78
|
+
(e: 'focus', event: Event): void;
|
|
79
|
+
(e: 'change', event: Event): void;
|
|
80
|
+
}>();
|
|
81
|
+
|
|
82
|
+
defineSlots<{
|
|
83
|
+
label?: () => VNode[];
|
|
84
|
+
message?: () => VNode[];
|
|
85
|
+
}>();
|
|
86
|
+
|
|
87
|
+
const { t } = useTranslation();
|
|
88
|
+
|
|
89
|
+
const parseDate = (value: string): string => {
|
|
90
|
+
if (props.yearOnly) {
|
|
91
|
+
return value;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (!value) {
|
|
95
|
+
return '';
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const [year, month, day] = value.split('-');
|
|
99
|
+
if (!year || !month || !day) {
|
|
100
|
+
console.warn(`Invalid date format. Expected YYYY-MM-DD, received: ${value}.`);
|
|
101
|
+
return '';
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return `${month}${day}${year}`;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const formattedDate = ref<string>(parseDate(props.value));
|
|
108
|
+
|
|
109
|
+
let lastEmittedValue = props.value;
|
|
110
|
+
|
|
111
|
+
watch(
|
|
112
|
+
() => props.value,
|
|
113
|
+
(newValue: string) => {
|
|
114
|
+
if (newValue !== lastEmittedValue) {
|
|
115
|
+
formattedDate.value = props.yearOnly ? newValue : parseDate(newValue);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
const emitIsoDate = (value: string): void => {
|
|
121
|
+
if (props.yearOnly) {
|
|
122
|
+
emit('input', value);
|
|
123
|
+
} else {
|
|
124
|
+
const month = value.substring(0, 2);
|
|
125
|
+
const day = value.substring(2, 4);
|
|
126
|
+
const year = value.substring(4, 8);
|
|
127
|
+
lastEmittedValue = year && month && day ? `${year}-${month}-${day}` : '';
|
|
128
|
+
emit('input', lastEmittedValue);
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const defaultLabel = computed(() => {
|
|
133
|
+
return props.yearOnly ? t('Year of birth') : t('Date of birth');
|
|
152
134
|
});
|
|
135
|
+
|
|
136
|
+
const defaultPlaceholder = computed(() => {
|
|
137
|
+
return props.yearOnly ? t('YYYY') : t('MM/DD/YYYY');
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
const validationMessage = computed(() => {
|
|
141
|
+
const inputLabel = props.yearOnly ? t('year of birth') : t('date of birth');
|
|
142
|
+
return t('Please enter a valid {inputLabel}', { inputLabel });
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
const defaultRules = computed(() => {
|
|
146
|
+
const minLengthRule = createMinLengthRule(props.yearOnly ? 4 : 10, validationMessage.value);
|
|
147
|
+
const maxAgeRule = (v: string): boolean | string =>
|
|
148
|
+
isValidDateInAgeRange(0, 125)(v) || validationMessage.value;
|
|
149
|
+
const validDateRule = (v: string): boolean | string =>
|
|
150
|
+
dayjs(v, 'MM/DD/YYYY', true).isValid() || validationMessage.value;
|
|
151
|
+
|
|
152
|
+
return [minLengthRule, maxAgeRule, !props.yearOnly ? validDateRule : undefined].filter(
|
|
153
|
+
Boolean
|
|
154
|
+
) as Rules<string>;
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
const computedLabel = computed(() => props.label || defaultLabel.value);
|
|
158
|
+
const computedPlaceholder = computed(() => props.placeholder || defaultPlaceholder.value);
|
|
159
|
+
const computedRules = computed(() => [...defaultRules.value, ...props.rules]);
|
|
160
|
+
const dateLength = computed(() => (props.yearOnly ? 4 : 8));
|
|
161
|
+
const mask = computed(() => (props.yearOnly ? '####' : '##/##/####'));
|
|
153
162
|
</script>
|