@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
|
@@ -125,17 +125,24 @@
|
|
|
125
125
|
</template>
|
|
126
126
|
|
|
127
127
|
<script lang="ts">
|
|
128
|
+
// NOTE(slanden): These rules do not properly handle multiple script tags in Vue
|
|
129
|
+
// eslint-disable-next-line import/order, import/no-duplicates
|
|
130
|
+
import type { Ref } from 'vue';
|
|
131
|
+
|
|
132
|
+
export interface CTextFieldExposed {
|
|
133
|
+
input: Ref<HTMLInputElement | null>;
|
|
134
|
+
focus: () => void;
|
|
135
|
+
blur: () => void;
|
|
136
|
+
startValidating: () => void;
|
|
137
|
+
}
|
|
138
|
+
</script>
|
|
139
|
+
|
|
140
|
+
<script setup lang="ts">
|
|
141
|
+
// eslint-disable-next-line import/order
|
|
128
142
|
import { faEye, faEyeSlash, faXmark } from '@fortawesome/pro-regular-svg-icons';
|
|
129
|
-
import
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
type StyleValue,
|
|
133
|
-
computed,
|
|
134
|
-
defineComponent,
|
|
135
|
-
onMounted,
|
|
136
|
-
ref,
|
|
137
|
-
toRefs,
|
|
138
|
-
} from 'vue';
|
|
143
|
+
// eslint-disable-next-line import/no-duplicates
|
|
144
|
+
import type { StyleValue, VNode } from 'vue';
|
|
145
|
+
import { computed, onMounted, ref, toRefs, useAttrs, useSlots } from 'vue';
|
|
139
146
|
|
|
140
147
|
import CFormFieldCounter from '@propelinc/citrus-ui/src/components/CFormFieldCounter.vue';
|
|
141
148
|
import CIconButton from '@propelinc/citrus-ui/src/components/CIconButton.vue';
|
|
@@ -147,203 +154,192 @@ import { useSlotHasContent } from '@propelinc/citrus-ui/src/composables/slots';
|
|
|
147
154
|
import type { Rules } from '@propelinc/citrus-ui/src/composables/validations';
|
|
148
155
|
import { useValidations } from '@propelinc/citrus-ui/src/composables/validations';
|
|
149
156
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
hideable: { type: Boolean, default: false },
|
|
185
|
-
hideLabel: { type: Boolean, default: false },
|
|
186
|
-
hideDetails: { type: [Boolean, String] as PropType<boolean | 'auto'>, default: false },
|
|
187
|
-
value: { type: String, default: '' },
|
|
188
|
-
dataTest: { type: String, default: 'text-field' },
|
|
189
|
-
counter: { type: Number as PropType<number | null>, default: null },
|
|
190
|
-
counterValue: {
|
|
191
|
-
type: [Number, Function] as PropType<number | (() => number | null)>,
|
|
192
|
-
default: null,
|
|
193
|
-
},
|
|
194
|
-
rules: { type: Array as PropType<Rules<string>>, default: () => [] },
|
|
195
|
-
validateOnBlur: { type: Boolean, default: true },
|
|
196
|
-
required: { type: Boolean, default: false },
|
|
157
|
+
defineOptions({ inheritAttrs: false });
|
|
158
|
+
|
|
159
|
+
const props = withDefaults(
|
|
160
|
+
defineProps<{
|
|
161
|
+
id?: string | null;
|
|
162
|
+
label?: string | null;
|
|
163
|
+
ariaLabel?: string | null;
|
|
164
|
+
placeholder?: string;
|
|
165
|
+
type?:
|
|
166
|
+
| 'text'
|
|
167
|
+
| 'password'
|
|
168
|
+
| 'email'
|
|
169
|
+
| 'tel'
|
|
170
|
+
| 'url'
|
|
171
|
+
| 'search'
|
|
172
|
+
| 'number'
|
|
173
|
+
| 'decimal'
|
|
174
|
+
| 'numeric';
|
|
175
|
+
clearable?: boolean;
|
|
176
|
+
size?: 'medium' | 'large';
|
|
177
|
+
inputmode?: 'text' | 'search' | 'none' | 'tel' | 'url' | 'email' | 'numeric' | 'decimal';
|
|
178
|
+
minlength?: number | string;
|
|
179
|
+
maxlength?: number | string;
|
|
180
|
+
disabled?: boolean;
|
|
181
|
+
hideable?: boolean;
|
|
182
|
+
hideLabel?: boolean;
|
|
183
|
+
hideDetails?: boolean | 'auto';
|
|
184
|
+
value?: string;
|
|
185
|
+
dataTest?: string;
|
|
186
|
+
counter?: number | null;
|
|
187
|
+
counterValue?: number | (() => number | null) | null;
|
|
188
|
+
rules?: Rules<string>;
|
|
189
|
+
validateOnBlur?: boolean;
|
|
190
|
+
required?: boolean;
|
|
197
191
|
/**
|
|
198
192
|
* Overrides the default validation message. If provided, this error message will always
|
|
199
193
|
* be shown, regardless of any other failing validation rules.
|
|
200
194
|
*/
|
|
201
|
-
errorMessage
|
|
202
|
-
},
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
'
|
|
208
|
-
'
|
|
209
|
-
|
|
210
|
-
'
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
195
|
+
errorMessage?: string;
|
|
196
|
+
}>(),
|
|
197
|
+
{
|
|
198
|
+
id: null,
|
|
199
|
+
label: null,
|
|
200
|
+
ariaLabel: null,
|
|
201
|
+
placeholder: '',
|
|
202
|
+
type: 'text',
|
|
203
|
+
clearable: false,
|
|
204
|
+
size: 'medium',
|
|
205
|
+
inputmode: undefined,
|
|
206
|
+
minlength: undefined,
|
|
207
|
+
maxlength: undefined,
|
|
208
|
+
disabled: false,
|
|
209
|
+
hideable: false,
|
|
210
|
+
hideLabel: false,
|
|
211
|
+
hideDetails: false,
|
|
212
|
+
value: '',
|
|
213
|
+
dataTest: 'text-field',
|
|
214
|
+
counter: null,
|
|
215
|
+
counterValue: null,
|
|
216
|
+
rules: () => [],
|
|
217
|
+
validateOnBlur: true,
|
|
218
|
+
required: false,
|
|
219
|
+
errorMessage: undefined,
|
|
220
|
+
}
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
const emit = defineEmits<{
|
|
224
|
+
'keyup': [event: KeyboardEvent];
|
|
225
|
+
'keydown': [event: KeyboardEvent];
|
|
226
|
+
'keypress': [event: KeyboardEvent];
|
|
227
|
+
'input': [value: string];
|
|
228
|
+
'focus': [event: Event];
|
|
229
|
+
'blur': [event: Event];
|
|
230
|
+
'change': [value: string];
|
|
231
|
+
'click': [event: MouseEvent];
|
|
232
|
+
'click:hide': [hidden: boolean];
|
|
233
|
+
}>();
|
|
234
|
+
|
|
235
|
+
defineSlots<{
|
|
236
|
+
'label'?: () => VNode[];
|
|
237
|
+
'prepend-inner'?: () => VNode[];
|
|
238
|
+
'append'?: () => VNode[];
|
|
239
|
+
'message'?: () => VNode[];
|
|
240
|
+
}>();
|
|
241
|
+
|
|
242
|
+
const attrs = useAttrs();
|
|
243
|
+
const slots = useSlots();
|
|
244
|
+
const { t } = useTranslation();
|
|
245
|
+
|
|
246
|
+
const isFocused = ref(false);
|
|
247
|
+
const inputHidden = ref(true);
|
|
248
|
+
const inputType = computed(() => (props.hideable && inputHidden.value ? 'password' : props.type));
|
|
249
|
+
const hideToggleAriaLabel = computed(() => {
|
|
250
|
+
return props.hideable && inputHidden.value ? t('Show input value') : t('Hide input value');
|
|
251
|
+
});
|
|
225
252
|
|
|
226
|
-
|
|
253
|
+
const { id, value, rules, required } = toRefs(props);
|
|
227
254
|
|
|
228
|
-
|
|
255
|
+
const idWithFallback = useId(id);
|
|
229
256
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
},
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
const input: Ref<HTMLInputElement | null> = ref(null);
|
|
237
|
-
const {
|
|
238
|
-
message: validationMessage,
|
|
239
|
-
valid: isValidationValid,
|
|
240
|
-
listeners: validationListeners,
|
|
241
|
-
startValidating,
|
|
242
|
-
} = useValidations({
|
|
243
|
-
id: idWithFallback,
|
|
244
|
-
value: inputValue,
|
|
245
|
-
rules,
|
|
246
|
-
required,
|
|
247
|
-
validateOn: computed(() => (props.validateOnBlur ? 'blur' : 'input')),
|
|
248
|
-
field: input,
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
const isInvalid = computed(() => !isValidationValid.value || !!props.errorMessage);
|
|
252
|
-
|
|
253
|
-
const prefixSlotHasContent = useSlotHasContent('prepend-inner');
|
|
254
|
-
const suffixSlotHasContent = useSlotHasContent('append');
|
|
255
|
-
const messageSlotHasContent = useSlotHasContent('message');
|
|
256
|
-
|
|
257
|
-
const toggleHidden = (): void => {
|
|
258
|
-
inputHidden.value = !inputHidden.value;
|
|
259
|
-
emit('click:hide', inputHidden.value);
|
|
260
|
-
};
|
|
261
|
-
|
|
262
|
-
const onInput = (event: Event): void => {
|
|
263
|
-
const target = event.target as HTMLInputElement;
|
|
264
|
-
if (target.value !== inputValue.value) {
|
|
265
|
-
inputValue.value = target.value;
|
|
266
|
-
validationListeners.input(event);
|
|
267
|
-
}
|
|
268
|
-
};
|
|
269
|
-
|
|
270
|
-
const onChange = (event: Event): void => {
|
|
271
|
-
validationListeners.change(event);
|
|
272
|
-
const target = event.target as HTMLInputElement;
|
|
273
|
-
emit('change', target.value);
|
|
274
|
-
};
|
|
275
|
-
|
|
276
|
-
const onFocus = (event: Event): void => {
|
|
277
|
-
isFocused.value = true;
|
|
278
|
-
emit('focus', event);
|
|
279
|
-
};
|
|
280
|
-
|
|
281
|
-
const onBlur = (event: Event): void => {
|
|
282
|
-
isFocused.value = false;
|
|
283
|
-
validationListeners.blur(event);
|
|
284
|
-
emit('blur', event);
|
|
285
|
-
};
|
|
286
|
-
|
|
287
|
-
const clearInput = (): void => {
|
|
288
|
-
emit('input', '');
|
|
289
|
-
};
|
|
290
|
-
|
|
291
|
-
const focus = (): void => {
|
|
292
|
-
input.value?.focus();
|
|
293
|
-
};
|
|
294
|
-
|
|
295
|
-
const blur = (): void => {
|
|
296
|
-
input.value?.blur();
|
|
297
|
-
};
|
|
298
|
-
|
|
299
|
-
onMounted(() => {
|
|
300
|
-
if (!props.label && !slots.label && !props.ariaLabel) {
|
|
301
|
-
console.error(
|
|
302
|
-
'Missing CTextField label. Please provide a label prop, an ariaLabel prop or pass a label via the label slot.'
|
|
303
|
-
);
|
|
304
|
-
}
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
const exposedAPI: CTextFieldExposed = { input, focus, blur, startValidating };
|
|
308
|
-
expose(exposedAPI);
|
|
309
|
-
|
|
310
|
-
const fallthroughAttrs = computed(() => {
|
|
311
|
-
const { class: _, style: __, ...rest } = attrs;
|
|
312
|
-
return rest;
|
|
313
|
-
});
|
|
314
|
-
|
|
315
|
-
// Need to compute these to cast the type to avoid type errors
|
|
316
|
-
const rootStyles = computed(() => attrs.style as StyleValue);
|
|
317
|
-
|
|
318
|
-
return {
|
|
319
|
-
faXmark,
|
|
320
|
-
faEye,
|
|
321
|
-
faEyeSlash,
|
|
322
|
-
|
|
323
|
-
fallthroughAttrs,
|
|
324
|
-
hideToggleAriaLabel,
|
|
325
|
-
idWithFallback,
|
|
326
|
-
input,
|
|
327
|
-
inputHidden,
|
|
328
|
-
inputType,
|
|
329
|
-
inputValue,
|
|
330
|
-
isFocused,
|
|
331
|
-
messageSlotHasContent,
|
|
332
|
-
prefixSlotHasContent,
|
|
333
|
-
rootStyles,
|
|
334
|
-
suffixSlotHasContent,
|
|
335
|
-
isInvalid,
|
|
336
|
-
validationMessage,
|
|
337
|
-
|
|
338
|
-
clearInput,
|
|
339
|
-
onBlur,
|
|
340
|
-
onChange,
|
|
341
|
-
onFocus,
|
|
342
|
-
onInput,
|
|
343
|
-
toggleHidden,
|
|
344
|
-
};
|
|
257
|
+
const inputValue = useInternalValue(value, {
|
|
258
|
+
onChange: (newValue) => {
|
|
259
|
+
emit('input', newValue);
|
|
345
260
|
},
|
|
346
261
|
});
|
|
262
|
+
|
|
263
|
+
const input = ref<HTMLInputElement | null>(null);
|
|
264
|
+
const {
|
|
265
|
+
message: validationMessage,
|
|
266
|
+
valid: isValidationValid,
|
|
267
|
+
listeners: validationListeners,
|
|
268
|
+
startValidating,
|
|
269
|
+
} = useValidations({
|
|
270
|
+
id: idWithFallback,
|
|
271
|
+
value: inputValue,
|
|
272
|
+
rules,
|
|
273
|
+
required,
|
|
274
|
+
validateOn: computed(() => (props.validateOnBlur ? 'blur' : 'input')),
|
|
275
|
+
field: input,
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
const isInvalid = computed(() => !isValidationValid.value || !!props.errorMessage);
|
|
279
|
+
|
|
280
|
+
const prefixSlotHasContent = useSlotHasContent('prepend-inner');
|
|
281
|
+
const suffixSlotHasContent = useSlotHasContent('append');
|
|
282
|
+
const messageSlotHasContent = useSlotHasContent('message');
|
|
283
|
+
|
|
284
|
+
const toggleHidden = (): void => {
|
|
285
|
+
inputHidden.value = !inputHidden.value;
|
|
286
|
+
emit('click:hide', inputHidden.value);
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
const onInput = (event: Event): void => {
|
|
290
|
+
const target = event.target as HTMLInputElement;
|
|
291
|
+
if (target.value !== inputValue.value) {
|
|
292
|
+
inputValue.value = target.value;
|
|
293
|
+
validationListeners.input(event);
|
|
294
|
+
}
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
const onChange = (event: Event): void => {
|
|
298
|
+
validationListeners.change(event);
|
|
299
|
+
const target = event.target as HTMLInputElement;
|
|
300
|
+
emit('change', target.value);
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
const onFocus = (event: Event): void => {
|
|
304
|
+
isFocused.value = true;
|
|
305
|
+
emit('focus', event);
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
const onBlur = (event: Event): void => {
|
|
309
|
+
isFocused.value = false;
|
|
310
|
+
validationListeners.blur(event);
|
|
311
|
+
emit('blur', event);
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
const clearInput = (): void => {
|
|
315
|
+
emit('input', '');
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
const focus = (): void => {
|
|
319
|
+
input.value?.focus();
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
const blur = (): void => {
|
|
323
|
+
input.value?.blur();
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
onMounted(() => {
|
|
327
|
+
if (!props.label && !slots.label && !props.ariaLabel) {
|
|
328
|
+
console.error(
|
|
329
|
+
'Missing CTextField label. Please provide a label prop, an ariaLabel prop or pass a label via the label slot.'
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
const exposedAPI: CTextFieldExposed = { input, focus, blur, startValidating };
|
|
335
|
+
defineExpose(exposedAPI);
|
|
336
|
+
|
|
337
|
+
const fallthroughAttrs = computed(() => {
|
|
338
|
+
const { class: _, style: __, ...rest } = attrs;
|
|
339
|
+
return rest;
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
const rootStyles = computed(() => attrs.style as StyleValue);
|
|
347
343
|
</script>
|
|
348
344
|
|
|
349
345
|
<style lang="scss" scoped>
|
|
@@ -13,39 +13,42 @@
|
|
|
13
13
|
</a>
|
|
14
14
|
</template>
|
|
15
15
|
|
|
16
|
-
<script lang="ts">
|
|
17
|
-
import type {
|
|
18
|
-
import { computed
|
|
16
|
+
<script setup lang="ts">
|
|
17
|
+
import type { VNode } from 'vue';
|
|
18
|
+
import { computed } from 'vue';
|
|
19
19
|
import type { RouteLocationRaw } from 'vue-router';
|
|
20
20
|
|
|
21
21
|
import { useRouterLink } from '@propelinc/citrus-ui/src/composables/router';
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
const props = withDefaults(
|
|
24
|
+
defineProps<{
|
|
25
25
|
/** Controls whether the text link functions as a router-link */
|
|
26
|
-
to
|
|
26
|
+
to?: RouteLocationRaw;
|
|
27
27
|
/** Designates the text link as an anchor and applies the href attribute */
|
|
28
|
-
href
|
|
28
|
+
href?: string;
|
|
29
29
|
/** Designates the target attribute. Only use with the href prop. */
|
|
30
|
-
target
|
|
30
|
+
target?: string;
|
|
31
31
|
/** Toggles whether the link should have an underline */
|
|
32
|
-
underline
|
|
33
|
-
},
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
32
|
+
underline?: boolean;
|
|
33
|
+
}>(),
|
|
34
|
+
{
|
|
35
|
+
to: undefined,
|
|
36
|
+
href: undefined,
|
|
37
|
+
target: undefined,
|
|
38
|
+
underline: true,
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
defineSlots<{
|
|
43
|
+
default?: () => VNode[];
|
|
44
|
+
}>();
|
|
45
|
+
|
|
46
|
+
const to = computed(() => props.to);
|
|
47
|
+
const { href: routerDestination, navigate } = useRouterLink(to);
|
|
48
|
+
const routerDestinationOrHref = computed(() => routerDestination.value ?? props.href);
|
|
49
|
+
|
|
50
|
+
const isRoleButton = computed(() => {
|
|
51
|
+
return !props.to && !props.href;
|
|
49
52
|
});
|
|
50
53
|
</script>
|
|
51
54
|
|
|
@@ -19,8 +19,9 @@
|
|
|
19
19
|
</div>
|
|
20
20
|
</template>
|
|
21
21
|
|
|
22
|
-
<script lang="ts">
|
|
23
|
-
import
|
|
22
|
+
<script setup lang="ts">
|
|
23
|
+
import type { IconDefinition } from '@fortawesome/fontawesome-svg-core';
|
|
24
|
+
import { ref } from 'vue';
|
|
24
25
|
|
|
25
26
|
import CSquaredIcon from '@propelinc/citrus-ui/src/components/CSquaredIcon.vue';
|
|
26
27
|
|
|
@@ -28,71 +29,41 @@ type Size = 'medium' | 'large';
|
|
|
28
29
|
|
|
29
30
|
type ImageState = 'loading' | 'loaded' | 'failed';
|
|
30
31
|
|
|
31
|
-
const SIZES = new Set<Size>(['medium', 'large']);
|
|
32
|
-
|
|
33
32
|
const SIZE_TO_VALUE: Record<Size, `${number}px`> = {
|
|
34
33
|
medium: '40px',
|
|
35
34
|
large: '56px',
|
|
36
35
|
};
|
|
37
36
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
*/
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
color: CSquaredIcon.props.color,
|
|
59
|
-
/**
|
|
60
|
-
* The Font Awesome icon to display as a fallback
|
|
61
|
-
*/
|
|
62
|
-
icon: CSquaredIcon.props.icon,
|
|
63
|
-
/**
|
|
64
|
-
* The size of the logo. Defaults to `medium`.
|
|
65
|
-
*/
|
|
66
|
-
size: {
|
|
67
|
-
type: String as PropType<Size>,
|
|
68
|
-
required: false,
|
|
69
|
-
default: 'medium',
|
|
70
|
-
validator: (value: string) => SIZES.has(value as Size),
|
|
71
|
-
},
|
|
72
|
-
/**
|
|
73
|
-
* The URL of the logo image
|
|
74
|
-
*/
|
|
75
|
-
src: { type: String, required: false, default: '' },
|
|
76
|
-
},
|
|
77
|
-
setup() {
|
|
78
|
-
const imageState = ref<ImageState>('loading');
|
|
37
|
+
withDefaults(
|
|
38
|
+
defineProps<{
|
|
39
|
+
/** The alt text for the logo. */
|
|
40
|
+
alt: string;
|
|
41
|
+
/** The color of the fallback icon logo */
|
|
42
|
+
color?: string;
|
|
43
|
+
/** The Font Awesome icon to display as a fallback */
|
|
44
|
+
icon?: string | string[] | IconDefinition | null;
|
|
45
|
+
/** The size of the logo. Defaults to `medium`. */
|
|
46
|
+
size?: Size;
|
|
47
|
+
/** The URL of the logo image */
|
|
48
|
+
src?: string;
|
|
49
|
+
}>(),
|
|
50
|
+
{
|
|
51
|
+
color: 'gray-100',
|
|
52
|
+
icon: null,
|
|
53
|
+
size: 'medium',
|
|
54
|
+
src: '',
|
|
55
|
+
}
|
|
56
|
+
);
|
|
79
57
|
|
|
80
|
-
|
|
81
|
-
imageState.value = 'failed';
|
|
82
|
-
};
|
|
58
|
+
const imageState = ref<ImageState>('loading');
|
|
83
59
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
60
|
+
const handleImageError = (): void => {
|
|
61
|
+
imageState.value = 'failed';
|
|
62
|
+
};
|
|
87
63
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
imageState,
|
|
92
|
-
SIZE_TO_VALUE,
|
|
93
|
-
};
|
|
94
|
-
},
|
|
95
|
-
});
|
|
64
|
+
const handleImageLoad = (): void => {
|
|
65
|
+
imageState.value = 'loaded';
|
|
66
|
+
};
|
|
96
67
|
</script>
|
|
97
68
|
|
|
98
69
|
<style scoped>
|