✨ feature: Added Input component
This commit is contained in:
parent
a2b7120257
commit
3e028d04c6
224
src/components/input/VInput.vue
Normal file
224
src/components/input/VInput.vue
Normal file
|
@ -0,0 +1,224 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import InputText from 'primevue/inputtext';
|
||||||
|
import Textarea from 'primevue/textarea';
|
||||||
|
import VHint from '../hint/VHint.vue';
|
||||||
|
import VDivider from '../divider/VDivider.vue';
|
||||||
|
import VLabel from '../label/VLabel.vue';
|
||||||
|
import type IVInput from './IVInput.type';
|
||||||
|
import { computed, useAttrs, useId, ref, watch } from 'vue';
|
||||||
|
import styles from '@visua/typography.module.css';
|
||||||
|
import Password from 'primevue/password';
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<IVInput>(), {
|
||||||
|
id: () => useId(),
|
||||||
|
descriptionId: undefined,
|
||||||
|
hint: '',
|
||||||
|
label: '',
|
||||||
|
modelValue: '',
|
||||||
|
wrapperClass: '',
|
||||||
|
isInvalid: false,
|
||||||
|
isValid: false,
|
||||||
|
isTextarea: false,
|
||||||
|
labelVisible: false,
|
||||||
|
isPassword: false,
|
||||||
|
weakLabel: 'Faible',
|
||||||
|
mediumLabel: 'Moyen',
|
||||||
|
strongLabel: 'Fort',
|
||||||
|
promptLabel: 'Entrez un mot de passe',
|
||||||
|
toggleMask: false,
|
||||||
|
placeholder: '',
|
||||||
|
passwordHint: undefined,
|
||||||
|
})
|
||||||
|
const attrs = useAttrs()
|
||||||
|
|
||||||
|
const isDisabled = computed(() => 'disabled' in attrs)
|
||||||
|
|
||||||
|
const emit = defineEmits([
|
||||||
|
'update:modelValue',
|
||||||
|
'value-change',
|
||||||
|
'change'
|
||||||
|
])
|
||||||
|
|
||||||
|
const localModelValue = ref(props.modelValue);
|
||||||
|
watch(() => props.modelValue, (newVal) => {
|
||||||
|
if(localModelValue.value !== newVal) {
|
||||||
|
localModelValue.value = newVal;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
watch(localModelValue, (newVal) => {
|
||||||
|
if(props.modelValue !== newVal){
|
||||||
|
emit('update:modelValue', newVal);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const labelState = computed(() => {
|
||||||
|
if(!props.isInvalid && !props.isValid && !isDisabled.value) return 'default';
|
||||||
|
else if(!props.isInvalid && props.isValid && !isDisabled.value) return 'success';
|
||||||
|
else if(props.isInvalid && !props.isValid && !isDisabled.value) return 'error';
|
||||||
|
else return undefined
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="main-container">
|
||||||
|
<VLabel
|
||||||
|
v-if="props.labelVisible"
|
||||||
|
:for="props.id"
|
||||||
|
:label="props.label"
|
||||||
|
:required="!isDisabled"
|
||||||
|
:disabled="isDisabled"
|
||||||
|
:type="labelState"
|
||||||
|
:hint="props.hint"
|
||||||
|
>
|
||||||
|
<template #required-type v-if="props.required">
|
||||||
|
<slot name="required-type"/>
|
||||||
|
</template>
|
||||||
|
</VLabel>
|
||||||
|
<!-- Password -->
|
||||||
|
<Password
|
||||||
|
v-if="props.isPassword"
|
||||||
|
:id="props.id"
|
||||||
|
v-bind="attrs"
|
||||||
|
:class="[styles['text-body-MD-standard-text-Regular'], {
|
||||||
|
'p-password': true,
|
||||||
|
'error': props.isInvalid && !props.isValid && !isDisabled,
|
||||||
|
'success': !props.isInvalid && props.isValid && !isDisabled,
|
||||||
|
}]"
|
||||||
|
:disabled="isDisabled"
|
||||||
|
:aria-disabled="isDisabled"
|
||||||
|
:aria-describedby="descriptionId || undefined"
|
||||||
|
:weakLabel="props.weakLabel"
|
||||||
|
:mediumLabel="props.mediumLabel"
|
||||||
|
:strongLabel="props.strongLabel"
|
||||||
|
:promptLabel="props.promptLabel"
|
||||||
|
:toggleMask="props.toggleMask"
|
||||||
|
:placeholder="props.placeholder"
|
||||||
|
:fluid="true"
|
||||||
|
v-model:model-value="localModelValue"
|
||||||
|
@update:model-value="emit('update:modelValue', $event)"
|
||||||
|
@valueChange="emit('value-change', $event)"
|
||||||
|
@change="emit('change', $event)"
|
||||||
|
>
|
||||||
|
<template #header>
|
||||||
|
<div
|
||||||
|
:class="styles['text-body-MD-standard-text-Medium']"
|
||||||
|
style="padding-bottom: 0.5rem;"
|
||||||
|
>Niveau de complexité</div>
|
||||||
|
</template>
|
||||||
|
<template v-if="props.passwordHint !== undefined" #footer>
|
||||||
|
<VDivider/>
|
||||||
|
<VHint title="Votre mot de passe doit contenir au moins :"/>
|
||||||
|
<div
|
||||||
|
role="alert"
|
||||||
|
aria-live="polite"
|
||||||
|
>
|
||||||
|
<template v-if="Array.isArray(props.passwordHint)">
|
||||||
|
<VHint
|
||||||
|
v-for="message in props.passwordHint"
|
||||||
|
:key="`password-hint-${message}`"
|
||||||
|
:id="descriptionId"
|
||||||
|
:data-testid="descriptionId"
|
||||||
|
:title="message"
|
||||||
|
type="info"
|
||||||
|
icon
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<VHint
|
||||||
|
v-else-if="props.passwordHint"
|
||||||
|
:title="props.passwordHint"
|
||||||
|
:id="descriptionId"
|
||||||
|
:data-testid="descriptionId"
|
||||||
|
type="info"
|
||||||
|
icon
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</Password>
|
||||||
|
|
||||||
|
<!-- Textarea -->
|
||||||
|
<Textarea
|
||||||
|
v-else-if="props.isTextarea"
|
||||||
|
:id="props.id"
|
||||||
|
v-bind="attrs"
|
||||||
|
:class="[styles['text-body-MD-standard-text-Regular'], {
|
||||||
|
'p-textarea': true,
|
||||||
|
'error': props.isInvalid && !props.isValid && !isDisabled,
|
||||||
|
'success': !props.isInvalid && props.isValid && !isDisabled,
|
||||||
|
}]"
|
||||||
|
:disabled="isDisabled"
|
||||||
|
:aria-disabled="isDisabled"
|
||||||
|
:aria-describedby="descriptionId || undefined"
|
||||||
|
:placeholder="props.placeholder"
|
||||||
|
@valueChange="emit('value-change', $event)"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- InputText -->
|
||||||
|
<InputText
|
||||||
|
v-else
|
||||||
|
:id="props.id"
|
||||||
|
v-bind="attrs"
|
||||||
|
:class="[styles['text-body-MD-standard-text-Regular'], {
|
||||||
|
'p-inputtext': true,
|
||||||
|
'error': props.isInvalid && !props.isValid && !isDisabled,
|
||||||
|
'success': !props.isInvalid && props.isValid && !isDisabled,
|
||||||
|
}]"
|
||||||
|
:disabled="isDisabled"
|
||||||
|
:aria-disabled="isDisabled"
|
||||||
|
:aria-describedby="descriptionId || undefined"
|
||||||
|
:placeholder="props.placeholder"
|
||||||
|
v-model:model-value="localModelValue"
|
||||||
|
@update:model-value="emit('update:modelValue', $event)"
|
||||||
|
@valueChange="emit('value-change', $event)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="css" scoped>
|
||||||
|
|
||||||
|
.main-container {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: start;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-textarea {
|
||||||
|
min-height: 5.5rem;
|
||||||
|
max-height: fit-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-password,
|
||||||
|
.p-inputtext { height: 2.5rem;}
|
||||||
|
|
||||||
|
.p-password,
|
||||||
|
.p-textarea,
|
||||||
|
.p-inputtext {width: inherit;}
|
||||||
|
|
||||||
|
.p-textarea,
|
||||||
|
.p-inputtext {border: var(--border-width) solid var(--input-border-color);}
|
||||||
|
|
||||||
|
.p-password.success, .p-password.success:focus-visible, .p-password.success:hover,
|
||||||
|
.p-textarea.success, .p-textarea.success:focus-visible, .p-textarea.success:hover,
|
||||||
|
.p-inputtext.success, .p-inputtext.success:focus-visible, .p-inputtext.success:hover {border: var(--large-border-width) solid var(--border-plain-success);}
|
||||||
|
|
||||||
|
.p-password.success, .p-password.success:focus-visible, .p-password.success:hover,
|
||||||
|
.p-textarea.error, .p-textarea.error:focus-visible, .p-textarea.error:hover,
|
||||||
|
.p-inputtext.error, .p-inputtext.error:focus-visible, .p-inputtext.error:hover {border: var(--large-border-width) solid var(--border-plain-error);}
|
||||||
|
|
||||||
|
.p-password:disabled,
|
||||||
|
.p-textarea:disabled,
|
||||||
|
.p-inputtext:disabled {
|
||||||
|
border-color: var(--border-disabled-grey);
|
||||||
|
color: var(--text-disabled-grey);
|
||||||
|
background-color: var(--background-disabled-grey);
|
||||||
|
}
|
||||||
|
|
||||||
|
.label-disabled,
|
||||||
|
.p-password:disabled,
|
||||||
|
.p-textarea:disabled,
|
||||||
|
.p-inputtext:disabled {color: var(--text-disabled-grey);}
|
||||||
|
</style>
|
Loading…
Reference in New Issue
Block a user