@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.
Files changed (202) hide show
  1. package/README.md +51 -14
  2. package/dist/citrus-ui.cdn.css +1 -0
  3. package/dist/citrus-ui.css +1 -0
  4. package/dist/colors/colors.d.ts +31 -0
  5. package/dist/colors/theme.d.ts +3 -0
  6. package/dist/colors/util-classes.d.ts +11 -0
  7. package/dist/components/CAccordion.vue.d.ts +34 -0
  8. package/dist/components/CAccordionItem.vue.d.ts +39 -0
  9. package/dist/components/CAppBar.vue.d.ts +59 -0
  10. package/dist/components/CBadge.vue.d.ts +35 -0
  11. package/dist/components/CBottomSheet.vue.d.ts +90 -0
  12. package/dist/components/CButton/CButton.vue.d.ts +97 -0
  13. package/dist/components/CButton/types.d.ts +5 -0
  14. package/dist/components/CButtonStack.vue.d.ts +27 -0
  15. package/dist/components/CCard.vue.d.ts +53 -0
  16. package/dist/components/CCardFooter.vue.d.ts +20 -0
  17. package/dist/components/CCardHeader.vue.d.ts +22 -0
  18. package/dist/components/CCardSection.vue.d.ts +26 -0
  19. package/dist/components/CCheckbox.vue.d.ts +62 -0
  20. package/dist/components/CCol.vue.d.ts +30 -0
  21. package/dist/components/CDivider.vue.d.ts +9 -0
  22. package/dist/components/CDobField.vue.d.ts +60 -0
  23. package/dist/components/CDobSelect.vue.d.ts +50 -0
  24. package/dist/components/CEmailField.vue.d.ts +48 -0
  25. package/dist/components/CExpandTransition.vue.d.ts +29 -0
  26. package/dist/components/CFadeTransition.vue.d.ts +20 -0
  27. package/dist/components/CFileInput.vue.d.ts +50 -0
  28. package/dist/components/CFixedPageFooter.vue.d.ts +153 -0
  29. package/dist/components/CForm.vue.d.ts +44 -0
  30. package/dist/components/CFormFieldCounter.vue.d.ts +15 -0
  31. package/dist/components/CIconButton.vue.d.ts +97 -0
  32. package/dist/components/CLabel.vue.d.ts +36 -0
  33. package/dist/components/CListItem.vue.d.ts +56 -0
  34. package/dist/components/CListItemContent.vue.d.ts +27 -0
  35. package/dist/components/CListItemIcon.vue.d.ts +28 -0
  36. package/dist/components/CLoader.vue.d.ts +23 -0
  37. package/dist/components/CLogo.vue.d.ts +9 -0
  38. package/dist/components/CMaskedTextField.vue.d.ts +511 -0
  39. package/dist/components/CMenu.vue.d.ts +17 -0
  40. package/dist/components/CMenuItem.vue.d.ts +37 -0
  41. package/dist/components/CMenuLabel.vue.d.ts +20 -0
  42. package/dist/components/CModal.vue.d.ts +59 -0
  43. package/dist/components/CModalLoading.vue.d.ts +36 -0
  44. package/dist/components/CNotification.vue.d.ts +64 -0
  45. package/dist/components/CPhoneField.vue.d.ts +792 -0
  46. package/dist/components/CPill.vue.d.ts +41 -0
  47. package/dist/components/CPillGroup.vue.d.ts +39 -0
  48. package/dist/components/CPopup.vue.d.ts +37 -0
  49. package/dist/components/CProgressLinear.vue.d.ts +21 -0
  50. package/dist/components/CProgressRing.vue.d.ts +48 -0
  51. package/dist/components/CRadio.vue.d.ts +40 -0
  52. package/dist/components/CRadioGroup.vue.d.ts +54 -0
  53. package/dist/components/CRebrand.vue.d.ts +28 -0
  54. package/dist/components/CRow.vue.d.ts +41 -0
  55. package/dist/components/CSafeArea.vue.d.ts +18 -0
  56. package/dist/components/CSectionHeader.vue.d.ts +29 -0
  57. package/dist/components/CSelect.vue.d.ts +96 -0
  58. package/dist/components/CSkeleton.vue.d.ts +3 -0
  59. package/dist/components/CSkeletonLoaderCard.vue.d.ts +9 -0
  60. package/dist/components/CSkeletonLoaderCircle.vue.d.ts +3 -0
  61. package/dist/components/CSkeletonLoaderText.vue.d.ts +16 -0
  62. package/dist/components/CSlideFadeTransition.vue.d.ts +36 -0
  63. package/dist/components/CSplitInput.vue.d.ts +56 -0
  64. package/dist/components/CSquaredIcon.vue.d.ts +33 -0
  65. package/dist/components/CSsnField.vue.d.ts +798 -0
  66. package/dist/components/CStatusDot.vue.d.ts +10 -0
  67. package/dist/components/CSwitch.vue.d.ts +39 -0
  68. package/dist/components/CSwitchListItem.vue.d.ts +48 -0
  69. package/dist/components/CTextArea.vue.d.ts +96 -0
  70. package/dist/components/CTextField.vue.d.ts +129 -0
  71. package/dist/components/CTextLink.vue.d.ts +36 -0
  72. package/dist/components/CThirdPartyLogo.vue.d.ts +22 -0
  73. package/dist/components/CTimeago.vue.d.ts +12 -0
  74. package/dist/components/CToast.vue.d.ts +69 -0
  75. package/dist/components/CToastsList.vue.d.ts +3 -0
  76. package/dist/components/CValidationMessage.vue.d.ts +37 -0
  77. package/dist/components/CZipcodeField.vue.d.ts +796 -0
  78. package/dist/components/index.d.ts +66 -0
  79. package/dist/components/internal/CCloseButton.vue.d.ts +14 -0
  80. package/dist/composables/accessibility.d.ts +1 -0
  81. package/dist/composables/animation.d.ts +12 -0
  82. package/dist/composables/binding.d.ts +19 -0
  83. package/dist/composables/colors.d.ts +13 -0
  84. package/dist/composables/elements.d.ts +3 -0
  85. package/dist/composables/fields.d.ts +10 -0
  86. package/dist/composables/gestures.d.ts +53 -0
  87. package/dist/composables/i18n.d.ts +3 -0
  88. package/dist/composables/id.d.ts +11 -0
  89. package/dist/composables/input-mask.d.ts +18 -0
  90. package/dist/composables/router.d.ts +30 -0
  91. package/dist/composables/slots.d.ts +2 -0
  92. package/dist/composables/toast.d.ts +21 -0
  93. package/dist/composables/validations.d.ts +77 -0
  94. package/dist/icons.cdn.mjs +3 -0
  95. package/dist/icons.cdn.mjs.map +1 -0
  96. package/dist/icons.d.ts +1 -0
  97. package/dist/icons.mjs +6 -0
  98. package/dist/icons.mjs.map +1 -0
  99. package/dist/index.cdn.mjs +9328 -12875
  100. package/dist/index.cdn.mjs.map +1 -1
  101. package/dist/index.cdn2.mjs +55255 -0
  102. package/dist/index.cdn2.mjs.map +1 -0
  103. package/dist/index.d.ts +8 -0
  104. package/dist/index.mjs +3946 -0
  105. package/dist/index.mjs.map +1 -0
  106. package/dist/plugin.d.ts +3 -0
  107. package/dist/services/animation.d.ts +17 -0
  108. package/dist/services/directives/index.d.ts +2 -0
  109. package/dist/services/directives/scroll-into-view.d.ts +7 -0
  110. package/dist/services/directives/tap-animation.d.ts +6 -0
  111. package/dist/services/id.d.ts +22 -0
  112. package/dist/services/injections/accordions.d.ts +3 -0
  113. package/dist/services/injections/animations.d.ts +2 -0
  114. package/dist/services/injections/buttons.d.ts +4 -0
  115. package/dist/services/injections/forms.d.ts +6 -0
  116. package/dist/services/injections/icon-buttons.d.ts +3 -0
  117. package/dist/services/injections/pills.d.ts +4 -0
  118. package/dist/services/injections/radio.d.ts +10 -0
  119. package/dist/{styles/main.css → styles.css} +40 -2
  120. package/dist/theme/icons.d.ts +36 -0
  121. package/dist/types/CForm.d.ts +12 -0
  122. package/dist/types/font-awesome.d.ts +5 -0
  123. package/dist/types.d.ts +13 -0
  124. package/package.json +11 -4
  125. package/src/colors/colors.ts +8 -3
  126. package/src/components/CAccordion.vue +31 -24
  127. package/src/components/CAccordionItem.vue +46 -45
  128. package/src/components/CAppBar.vue +108 -101
  129. package/src/components/CBadge.vue +33 -25
  130. package/src/components/CBottomSheet.vue +212 -199
  131. package/src/components/CButton/CButton.vue +135 -147
  132. package/src/components/CButtonStack.vue +21 -13
  133. package/src/components/CCard.vue +72 -69
  134. package/src/components/CCardFooter.vue +5 -5
  135. package/src/components/CCardHeader.vue +9 -7
  136. package/src/components/CCardSection.vue +15 -8
  137. package/src/components/CCheckbox.vue +68 -69
  138. package/src/components/CCol.vue +21 -22
  139. package/src/components/CDivider.vue +9 -8
  140. package/src/components/CDobField.vue +114 -105
  141. package/src/components/CDobSelect.vue +162 -164
  142. package/src/components/CEmailField.vue +39 -27
  143. package/src/components/CExpandTransition.vue +14 -17
  144. package/src/components/CFadeTransition.vue +3 -3
  145. package/src/components/CFileInput.vue +57 -50
  146. package/src/components/CFixedPageFooter.vue +23 -17
  147. package/src/components/CForm.vue +67 -60
  148. package/src/components/CFormFieldCounter.vue +25 -28
  149. package/src/components/CIconButton.vue +84 -65
  150. package/src/components/CLabel.vue +19 -13
  151. package/src/components/CListItem.vue +67 -66
  152. package/src/components/CListItemContent.vue +14 -16
  153. package/src/components/CListItemIcon.vue +18 -14
  154. package/src/components/CLoader.vue +47 -56
  155. package/src/components/CLogo.vue +13 -12
  156. package/src/components/CMaskedTextField.vue +80 -64
  157. package/src/components/CMenu.vue +14 -6
  158. package/src/components/CMenuItem.vue +28 -22
  159. package/src/components/CMenuLabel.vue +6 -5
  160. package/src/components/CModal.vue +76 -71
  161. package/src/components/CModalLoading.vue +24 -15
  162. package/src/components/CNotification.vue +77 -28
  163. package/src/components/CPhoneField.vue +34 -25
  164. package/src/components/CPill.vue +92 -88
  165. package/src/components/CPillGroup.vue +30 -21
  166. package/src/components/CPopup.vue +46 -37
  167. package/src/components/CProgressLinear.vue +17 -11
  168. package/src/components/CProgressRing.vue +33 -33
  169. package/src/components/CRadio.vue +57 -57
  170. package/src/components/CRadioGroup.vue +85 -72
  171. package/src/components/CRow.vue +22 -20
  172. package/src/components/CSectionHeader.vue +20 -12
  173. package/src/components/CSelect.vue +89 -73
  174. package/src/components/CSkeletonLoaderCard.vue +9 -15
  175. package/src/components/CSkeletonLoaderCircle.vue +1 -9
  176. package/src/components/CSkeletonLoaderText.vue +17 -18
  177. package/src/components/CSlideFadeTransition.vue +12 -34
  178. package/src/components/CSplitInput.vue +46 -45
  179. package/src/components/CSquaredIcon.vue +39 -29
  180. package/src/components/CSsnField.vue +48 -36
  181. package/src/components/CStatusDot.vue +16 -16
  182. package/src/components/CSwitch.vue +31 -22
  183. package/src/components/CSwitchListItem.vue +27 -28
  184. package/src/components/CTextArea.vue +116 -83
  185. package/src/components/CTextField.vue +194 -198
  186. package/src/components/CTextLink.vue +28 -25
  187. package/src/components/CThirdPartyLogo.vue +30 -59
  188. package/src/components/CToast.vue +135 -132
  189. package/src/components/CToastsList.vue +2 -15
  190. package/src/components/CValidationMessage.vue +31 -24
  191. package/src/components/CZipcodeField.vue +40 -27
  192. package/src/composables/elements.ts +1 -1
  193. package/src/composables/fields.ts +4 -4
  194. package/src/composables/router.ts +6 -5
  195. package/src/icons.ts +6 -0
  196. package/src/services/injections/buttons.ts +1 -1
  197. package/src/styles/_core.scss +1 -2
  198. package/src/styles/_reset.scss +1 -1
  199. package/src/styles/main.scss +2 -0
  200. package/src/types.ts +2 -0
  201. package/dist/index.cdn.css +0 -1
  202. package/dist/styles/utils.css +0 -2709
@@ -71,9 +71,10 @@
71
71
  </div>
72
72
  </template>
73
73
 
74
- <script lang="ts">
74
+ <script setup lang="ts">
75
75
  import dayjs from 'dayjs';
76
- import { type PropType, computed, defineComponent, ref, watch } from 'vue';
76
+ import type { VNode } from 'vue';
77
+ import { computed, ref, watch } from 'vue';
77
78
 
78
79
  import CSelect from '@propelinc/citrus-ui/src/components/CSelect.vue';
79
80
  import CValidationMessage from '@propelinc/citrus-ui/src/components/CValidationMessage.vue';
@@ -83,169 +84,166 @@ import {
83
84
  useFormValidationSupport,
84
85
  } from '@propelinc/citrus-ui/src/composables/validations';
85
86
 
86
- export default defineComponent({
87
- name: 'CDobSelect',
88
- components: { CSelect, CValidationMessage },
89
- props: {
90
- dataTest: { type: String, default: 'dob-select' },
91
- id: { type: String, default: undefined },
92
- label: { type: String as PropType<string | null>, default: null },
93
- required: { type: Boolean, default: false },
94
- rules: { type: Array as PropType<Rules<string>>, default: () => [] },
95
- hideLabel: { type: Boolean, default: false },
96
- hideDetails: { type: Boolean, default: false },
97
- value: { type: String, default: '' },
98
- disabled: { type: Boolean, default: false },
99
- },
100
- emits: ['input', 'focus', 'blur'],
101
- setup(props, { emit }) {
102
- const { t } = useTranslation();
103
-
104
- const computedLabel = computed(() => props.label ?? t('Date of birth'));
105
-
106
- const localMonth = ref('');
107
- const localDay = ref('');
108
- const localYear = ref('');
109
-
110
- const hasError = ref(props.required && props.value === '');
111
- const messages = ref<string[]>([]);
112
-
113
- const localValue = computed(() => {
114
- if (localDay.value && localMonth.value && localYear.value) {
115
- return `${localYear.value}-${localMonth.value}-${localDay.value}`;
116
- }
117
- return '';
118
- });
119
-
120
- const monthRules = computed(() => {
121
- if (!props.required && !localMonth.value) {
122
- return [];
123
- }
124
- return [(): boolean => localMonth.value !== ''];
125
- });
126
- const dayRules = computed(() => {
127
- if (!props.required && !localDay.value) {
128
- return [];
129
- }
130
- return [(): boolean => localDay.value !== ''];
131
- });
132
- const yearRules = computed(() => {
133
- if (!props.required && !localYear.value) {
134
- return [];
135
- }
136
- return [(): boolean => localYear.value !== ''];
137
- });
138
- const message = computed(() => messages.value[0] ?? '');
139
-
140
- const monthOptions = Array.from({ length: 12 }, (_, i) => ({
141
- value: (i + 1).toString().padStart(2, '0'),
142
- label: dayjs().set('month', i).format('MMM'),
143
- }));
144
-
145
- const dayOptions = computed(() => {
146
- const year = Number(localYear.value) || 2000;
147
- const month = Number(localMonth.value) - 1 || 0;
148
- const daysInMonth = dayjs().year(year).month(month).daysInMonth();
149
- return Array.from({ length: daysInMonth }, (_, i) => {
150
- const day = (i + 1).toString();
151
- return { value: day.padStart(2, '0'), label: day };
152
- });
153
- });
154
-
155
- const currentYear = dayjs().year();
156
- const yearOptions = Array.from({ length: 120 }, (_, age) => {
157
- const year = (currentYear - age).toString();
158
- return { value: year, label: year };
159
- });
160
-
161
- const validationMessage = t('Please enter a valid {inputLabel}', {
162
- inputLabel: t('date of birth'),
163
- });
164
-
165
- const localRules = computed(() => {
166
- if (!props.required && !localValue.value) {
167
- return [];
168
- }
169
- const validDateRule = (v: string): boolean | string =>
170
- dayjs(v, 'YYYY-MM-DD', true).isValid() || validationMessage;
171
- return [validDateRule, ...props.rules];
172
- });
173
-
174
- const valid = computed(() => !hasError.value);
175
-
176
- const validate = (): boolean => {
177
- messages.value = localRules.value
178
- .map((validation) => {
179
- const validationResult = validation(localValue.value);
180
- return typeof validationResult === 'string' ? validationResult : '';
181
- })
182
- .filter((message) => message !== '');
183
-
184
- hasError.value = (props.required && localValue.value === '') || messages.value.length > 0;
185
- return !hasError.value;
186
- };
187
-
188
- const emitDate = (): void => {
189
- if (!localValue.value) {
190
- return;
191
- }
192
-
193
- if (!validate()) {
194
- // NOTE(ram): An invalid date can only be caused by the day being invalid.
195
- localDay.value = '';
196
- emit('input', '');
197
- return;
198
- }
199
-
200
- emit('input', localValue.value);
201
- };
202
-
203
- watch(
204
- () => props.value,
205
- (value) => {
206
- if (!value || value === localValue.value) {
207
- return;
208
- }
209
-
210
- const date = dayjs(value, 'YYYY-MM-DD', true);
211
- if (!date.isValid()) {
212
- console.error('Invalid date in CDobSelect', value);
213
- return;
214
- }
215
-
216
- localMonth.value = date.format('MM');
217
- localDay.value = date.format('DD');
218
- localYear.value = date.format('YYYY');
219
- },
220
- { immediate: true }
221
- );
222
-
223
- useFormValidationSupport({
224
- id: props.id,
225
- valid,
226
- validate,
227
- });
228
-
229
- return {
230
- localDay,
231
- localMonth,
232
- localYear,
233
- dayRules,
234
- monthRules,
235
- yearRules,
236
- dayOptions,
237
- monthOptions,
238
- yearOptions,
239
-
240
- computedLabel,
241
- hasError,
242
- messages,
243
- localValue,
244
- message,
245
-
246
- emitDate,
247
- };
87
+ const props = withDefaults(
88
+ defineProps<{
89
+ dataTest?: string;
90
+ id?: string;
91
+ label?: string | null;
92
+ required?: boolean;
93
+ rules?: Rules<string>;
94
+ hideLabel?: boolean;
95
+ hideDetails?: boolean;
96
+ value?: string;
97
+ disabled?: boolean;
98
+ }>(),
99
+ {
100
+ dataTest: 'dob-select',
101
+ id: undefined,
102
+ label: null,
103
+ required: false,
104
+ rules: () => [],
105
+ hideLabel: false,
106
+ hideDetails: false,
107
+ value: '',
108
+ disabled: false,
109
+ }
110
+ );
111
+
112
+ const emit = defineEmits<{
113
+ (e: 'input', value: string): void;
114
+ (e: 'focus'): void;
115
+ (e: 'blur'): void;
116
+ }>();
117
+
118
+ defineSlots<{
119
+ label?: () => VNode[];
120
+ }>();
121
+
122
+ const { t } = useTranslation();
123
+
124
+ const computedLabel = computed(() => props.label ?? t('Date of birth'));
125
+
126
+ const localMonth = ref('');
127
+ const localDay = ref('');
128
+ const localYear = ref('');
129
+
130
+ const hasError = ref(props.required && props.value === '');
131
+ const messages = ref<string[]>([]);
132
+
133
+ const localValue = computed(() => {
134
+ if (localDay.value && localMonth.value && localYear.value) {
135
+ return `${localYear.value}-${localMonth.value}-${localDay.value}`;
136
+ }
137
+ return '';
138
+ });
139
+
140
+ const monthRules = computed(() => {
141
+ if (!props.required && !localMonth.value) {
142
+ return [];
143
+ }
144
+ return [(): boolean => localMonth.value !== ''];
145
+ });
146
+ const dayRules = computed(() => {
147
+ if (!props.required && !localDay.value) {
148
+ return [];
149
+ }
150
+ return [(): boolean => localDay.value !== ''];
151
+ });
152
+ const yearRules = computed(() => {
153
+ if (!props.required && !localYear.value) {
154
+ return [];
155
+ }
156
+ return [(): boolean => localYear.value !== ''];
157
+ });
158
+ const message = computed(() => messages.value[0] ?? '');
159
+
160
+ const monthOptions = Array.from({ length: 12 }, (_, i) => ({
161
+ value: (i + 1).toString().padStart(2, '0'),
162
+ label: dayjs().set('month', i).format('MMM'),
163
+ }));
164
+
165
+ const dayOptions = computed(() => {
166
+ const year = Number(localYear.value) || 2000;
167
+ const month = Number(localMonth.value) - 1 || 0;
168
+ const daysInMonth = dayjs().year(year).month(month).daysInMonth();
169
+ return Array.from({ length: daysInMonth }, (_, i) => {
170
+ const day = (i + 1).toString();
171
+ return { value: day.padStart(2, '0'), label: day };
172
+ });
173
+ });
174
+
175
+ const currentYear = dayjs().year();
176
+ const yearOptions = Array.from({ length: 120 }, (_, age) => {
177
+ const year = (currentYear - age).toString();
178
+ return { value: year, label: year };
179
+ });
180
+
181
+ const validationMessage = t('Please enter a valid {inputLabel}', {
182
+ inputLabel: t('date of birth'),
183
+ });
184
+
185
+ const localRules = computed(() => {
186
+ if (!props.required && !localValue.value) {
187
+ return [];
188
+ }
189
+ const validDateRule = (v: string): boolean | string =>
190
+ dayjs(v, 'YYYY-MM-DD', true).isValid() || validationMessage;
191
+ return [validDateRule, ...props.rules];
192
+ });
193
+
194
+ const valid = computed(() => !hasError.value);
195
+
196
+ const validate = (): boolean => {
197
+ messages.value = localRules.value
198
+ .map((validation) => {
199
+ const validationResult = validation(localValue.value);
200
+ return typeof validationResult === 'string' ? validationResult : '';
201
+ })
202
+ .filter((message) => message !== '');
203
+
204
+ hasError.value = (props.required && localValue.value === '') || messages.value.length > 0;
205
+ return !hasError.value;
206
+ };
207
+
208
+ const emitDate = (): void => {
209
+ if (!localValue.value) {
210
+ return;
211
+ }
212
+
213
+ if (!validate()) {
214
+ // NOTE(ram): An invalid date can only be caused by the day being invalid.
215
+ localDay.value = '';
216
+ emit('input', '');
217
+ return;
218
+ }
219
+
220
+ emit('input', localValue.value);
221
+ };
222
+
223
+ watch(
224
+ () => props.value,
225
+ (value) => {
226
+ if (!value || value === localValue.value) {
227
+ return;
228
+ }
229
+
230
+ const date = dayjs(value, 'YYYY-MM-DD', true);
231
+ if (!date.isValid()) {
232
+ console.error('Invalid date in CDobSelect', value);
233
+ return;
234
+ }
235
+
236
+ localMonth.value = date.format('MM');
237
+ localDay.value = date.format('DD');
238
+ localYear.value = date.format('YYYY');
248
239
  },
240
+ { immediate: true }
241
+ );
242
+
243
+ useFormValidationSupport({
244
+ id: props.id,
245
+ valid,
246
+ validate,
249
247
  });
250
248
  </script>
251
249
 
@@ -23,39 +23,51 @@
23
23
  </CTextField>
24
24
  </template>
25
25
 
26
- <script lang="ts">
27
- import { type PropType, defineComponent } from 'vue';
26
+ <script setup lang="ts">
27
+ import type { VNode } from 'vue';
28
28
 
29
29
  import CTextField from '@propelinc/citrus-ui/src/components/CTextField.vue';
30
30
  import { useTranslation } from '@propelinc/citrus-ui/src/composables/i18n';
31
31
  import type { Rules } from '@propelinc/citrus-ui/src/composables/validations';
32
32
  import { isValidEmail } from '@propelinc/shared-utils';
33
33
 
34
- export default defineComponent({
35
- name: 'CEmailField',
36
- components: { CTextField },
37
- props: {
38
- dataTest: { type: String, default: 'email-field' },
39
- id: { type: String, default: undefined },
40
- label: { type: String as PropType<string | null>, default: null },
41
- placeholder: { type: String as PropType<string | null>, default: null },
42
- rules: { type: Array as PropType<Rules<string>>, default: () => [] },
43
- value: { type: String, default: '' },
44
- },
45
- emits: ['input', 'focus', 'blur', 'change'],
46
- setup() {
47
- const { t } = useTranslation();
34
+ withDefaults(
35
+ defineProps<{
36
+ dataTest?: string;
37
+ id?: string;
38
+ label?: string | null;
39
+ placeholder?: string | null;
40
+ rules?: Rules<string>;
41
+ value?: string;
42
+ }>(),
43
+ {
44
+ dataTest: 'email-field',
45
+ id: undefined,
46
+ label: null,
47
+ placeholder: null,
48
+ rules: (): Rules<string> => [],
49
+ value: '',
50
+ }
51
+ );
48
52
 
49
- const defaultRules = [
50
- (v: string): string | boolean =>
51
- !v || isValidEmail(v)
52
- ? true
53
- : t('Please enter a valid {inputLabel}', { inputLabel: t('email') }),
54
- ];
53
+ defineEmits<{
54
+ input: [value: string];
55
+ focus: [event: Event];
56
+ blur: [event: Event];
57
+ change: [value: string];
58
+ }>();
55
59
 
56
- return {
57
- defaultRules,
58
- };
59
- },
60
- });
60
+ defineSlots<{
61
+ label?: () => VNode[];
62
+ message?: () => VNode[];
63
+ }>();
64
+
65
+ const { t } = useTranslation();
66
+
67
+ const defaultRules = [
68
+ (v: string): string | boolean =>
69
+ !v || isValidEmail(v)
70
+ ? true
71
+ : t('Please enter a valid {inputLabel}', { inputLabel: t('email') }),
72
+ ];
61
73
  </script>
@@ -11,27 +11,24 @@
11
11
  </div>
12
12
  </template>
13
13
 
14
- <script lang="ts">
15
- import { computed, defineComponent, inject, ref } from 'vue';
14
+ <script setup lang="ts">
15
+ import type { VNode } from 'vue';
16
+ import { computed, inject, ref } from 'vue';
16
17
 
17
18
  import { useResizeObserver } from '@propelinc/citrus-ui/src/composables/elements';
18
19
  import { ANIMATIONS_DISABLED } from '@propelinc/citrus-ui/src/services/injections/animations';
19
20
 
20
- export default defineComponent({
21
- name: 'CExpandTransition',
22
- props: { disabled: { type: Boolean, default: false } },
23
- setup(props) {
24
- const injectedDisabled = inject(ANIMATIONS_DISABLED, ref(false));
25
- const isDisabled = computed(() => props.disabled || injectedDisabled.value);
26
- const content = ref<HTMLElement | null>(null);
27
- const height = ref<string>('auto');
28
-
29
- useResizeObserver(content, ([entry]) => {
30
- height.value = `${entry.contentRect.height}px`;
31
- });
32
-
33
- return { content, height, isDisabled };
34
- },
21
+ defineSlots<{ default: () => VNode[] }>();
22
+
23
+ const props = withDefaults(defineProps<{ disabled?: boolean }>(), { disabled: false });
24
+
25
+ const injectedDisabled = inject(ANIMATIONS_DISABLED, ref(false));
26
+ const isDisabled = computed(() => props.disabled || injectedDisabled.value);
27
+ const content = ref<HTMLElement | null>(null);
28
+ const height = ref<string>('auto');
29
+
30
+ useResizeObserver(content, ([entry]) => {
31
+ height.value = `${entry.contentRect.height}px`;
35
32
  });
36
33
  </script>
37
34
 
@@ -4,10 +4,10 @@
4
4
  </Transition>
5
5
  </template>
6
6
 
7
- <script lang="ts">
8
- import { defineComponent } from 'vue';
7
+ <script setup lang="ts">
8
+ import type { VNode } from 'vue';
9
9
 
10
- export default defineComponent({});
10
+ defineSlots<{ default: () => VNode[] }>();
11
11
  </script>
12
12
 
13
13
  <style lang="scss" scoped>
@@ -35,65 +35,72 @@
35
35
  </label>
36
36
  </template>
37
37
 
38
- <script lang="ts">
39
- import { type PropType, computed, defineComponent, toRefs } from 'vue';
38
+ <script setup lang="ts">
39
+ import type { VNode } from 'vue';
40
+ import { computed, toRefs } from 'vue';
40
41
 
41
42
  import { useInternalValue } from '@propelinc/citrus-ui/src/composables/binding';
42
43
  import { useId } from '@propelinc/citrus-ui/src/composables/id';
43
44
 
44
- export default defineComponent({
45
- name: 'CFileInput',
46
- props: {
47
- /** The input's label, both visual and screenreader-only */
48
- label: { type: String, required: true },
49
- /** Placholder text to display before a user has selected any files */
50
- prompt: { type: String, required: true },
51
- /** The input's value. Either one file or an array of files */
52
- value: { type: [Array, Object, null] as PropType<File[] | File | null>, default: null },
45
+ const props = withDefaults(
46
+ defineProps<{
47
+ /** A custom data-test string applied to the form field, text field and hide icon */
48
+ dataTest?: string;
49
+ /** Controls whether the input is disabled */
50
+ disabled?: boolean;
53
51
  /** A unique id for the input */
54
- id: { type: String, required: true },
52
+ id: string;
53
+ /** The input's label, both visual and screenreader-only */
54
+ label: string;
55
55
  /** Allow the user to upload multiple files */
56
- multiple: { type: Boolean, default: false },
57
- /** Controls whether the input is disabled */
58
- disabled: { type: Boolean, default: false },
56
+ multiple?: boolean;
57
+ /** Placholder text to display before a user has selected any files */
58
+ prompt: string;
59
59
  /** Controls whether the input is required */
60
- required: { type: Boolean, default: false },
61
- /** A custom data-test string applied to the form field, text field and hide icon */
62
- dataTest: { type: String, default: 'file-input' },
63
- },
64
- emits: ['input'],
65
- setup(props, { emit }) {
66
- const { id, value } = toRefs(props);
67
- const idWithFallback = useId(id);
68
- const inputValue = useInternalValue(value, {
69
- onChange: (newValue) => {
70
- emit('input', newValue);
71
- },
72
- });
73
- const hasValue = computed(() => {
74
- if (Array.isArray(inputValue.value)) {
75
- return inputValue.value.length > 0;
76
- }
77
- return !!inputValue.value;
78
- });
79
-
80
- function onFileChange(event: Event): void {
81
- const files = (event.target as HTMLInputElement).files;
82
- if (!files) {
83
- inputValue.value = null;
84
- } else {
85
- inputValue.value = props.multiple ? Array.from(files) : files[0];
86
- }
87
- }
88
-
89
- return {
90
- idWithFallback,
91
- inputValue,
92
- hasValue,
93
- onFileChange,
94
- };
60
+ required?: boolean;
61
+ /** The input's value. Either one file or an array of files */
62
+ value?: File[] | File | null;
63
+ }>(),
64
+ {
65
+ dataTest: 'file-input',
66
+ disabled: false,
67
+ multiple: false,
68
+ required: false,
69
+ value: null,
70
+ }
71
+ );
72
+
73
+ const emit = defineEmits<{
74
+ (e: 'input', value: File[] | File | null): void;
75
+ }>();
76
+
77
+ defineSlots<{
78
+ label?: () => VNode[];
79
+ prompt?: () => VNode[];
80
+ }>();
81
+
82
+ const { id, value } = toRefs(props);
83
+ const idWithFallback = useId(id);
84
+ const inputValue = useInternalValue(value, {
85
+ onChange: (newValue) => {
86
+ emit('input', newValue);
95
87
  },
96
88
  });
89
+ const hasValue = computed(() => {
90
+ if (Array.isArray(inputValue.value)) {
91
+ return inputValue.value.length > 0;
92
+ }
93
+ return !!inputValue.value;
94
+ });
95
+
96
+ function onFileChange(event: Event): void {
97
+ const files = (event.target as HTMLInputElement).files;
98
+ if (!files) {
99
+ inputValue.value = null;
100
+ } else {
101
+ inputValue.value = props.multiple ? Array.from(files) : files[0];
102
+ }
103
+ }
97
104
  </script>
98
105
 
99
106
  <style lang="scss" scoped>
@@ -12,29 +12,35 @@
12
12
  </CButtonStack>
13
13
  </template>
14
14
 
15
- <script lang="ts">
16
- import { computed, defineComponent, onBeforeUnmount, ref } from 'vue';
15
+ <script setup lang="ts">
16
+ import type { VNode } from 'vue';
17
+ import { computed, onBeforeUnmount, ref } from 'vue';
17
18
 
18
19
  import CButtonStack from '@propelinc/citrus-ui/src/components/CButtonStack.vue';
19
20
  import { useResizeObserver } from '@propelinc/citrus-ui/src/composables/elements';
20
21
 
21
- export default defineComponent({
22
- name: 'CFixedPageFooter',
23
- components: { CButtonStack },
24
- props: {
22
+ withDefaults(
23
+ defineProps<{
25
24
  /** The HTML tag to render as. Avoid changing this if possible. */
26
- tag: { type: String, default: 'footer' },
27
- },
28
- emits: ['change:height'],
29
- setup(_, { emit }) {
30
- const footer = ref<InstanceType<typeof CButtonStack> | null>(null);
31
- const footerElement = computed(() => (footer.value?.$el as HTMLElement) ?? null);
32
- useResizeObserver(footerElement, ([entry]) => emit('change:height', entry.contentRect.height));
33
- onBeforeUnmount(() => emit('change:height', 0));
25
+ tag?: string;
26
+ }>(),
27
+ {
28
+ tag: 'footer',
29
+ }
30
+ );
31
+
32
+ const emit = defineEmits<{
33
+ 'change:height': [height: number];
34
+ }>();
35
+
36
+ defineSlots<{
37
+ default?: () => VNode[];
38
+ }>();
34
39
 
35
- return { footer };
36
- },
37
- });
40
+ const footer = ref<InstanceType<typeof CButtonStack> | null>(null);
41
+ const footerElement = computed(() => (footer.value?.$el as HTMLElement) ?? null);
42
+ useResizeObserver(footerElement, ([entry]) => emit('change:height', entry.contentRect.height));
43
+ onBeforeUnmount(() => emit('change:height', 0));
38
44
  </script>
39
45
 
40
46
  <style lang="scss" scoped>