✨ feature: Select component added
This commit is contained in:
parent
0197ba5df2
commit
961e15ed50
177
src/components/select/VSelect.vue
Normal file
177
src/components/select/VSelect.vue
Normal file
|
@ -0,0 +1,177 @@
|
|||
<script setup lang="ts">
|
||||
import Select from 'primevue/select';
|
||||
import type IVSelect from './IVSelect.type';
|
||||
import { useId, computed, watch, ref } from 'vue';
|
||||
import VLabel from '../label/VLabel.vue';
|
||||
import VHint from '../hint/VHint.vue';
|
||||
import styles from '@visua/typography.module.css';
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
})
|
||||
|
||||
const props = withDefaults(defineProps<IVSelect>(), {
|
||||
hint: '',
|
||||
successMessage: '',
|
||||
errorMessage: '',
|
||||
selectId: () => `select-${useId()}`,
|
||||
label: '',
|
||||
required: false,
|
||||
disabled: false,
|
||||
options: undefined,
|
||||
name: '',
|
||||
defaultUnselectedText: 'Sélectionner une option',
|
||||
filter: false,
|
||||
editable: false,
|
||||
optionLabel: undefined,
|
||||
optionValue: undefined,
|
||||
filterMessage: 'Les résultats sont disponibles',
|
||||
selectionMessage: 'Elements sélectionnés',
|
||||
emptySelectionMessage: 'Aucun élément sélectionné',
|
||||
emptyFilterMessage: 'Aucun résultat trouvé',
|
||||
emptyMessage: 'Aucune option disponible',
|
||||
optionTemplate: false,
|
||||
|
||||
})
|
||||
|
||||
const emit = defineEmits([
|
||||
'update:modelValue',
|
||||
'value-change',
|
||||
'change',
|
||||
'focus',
|
||||
'blur',
|
||||
'before-show',
|
||||
'before-hide',
|
||||
'show',
|
||||
'hide',
|
||||
'filter',
|
||||
])
|
||||
|
||||
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 message = computed(() => {
|
||||
return props.errorMessage || props.successMessage
|
||||
})
|
||||
const messageState = computed(() => {
|
||||
return props.errorMessage ? 'error' : 'valid'
|
||||
})
|
||||
|
||||
const typeMessage = computed(() => {
|
||||
if (props.errorMessage) return 'alert';
|
||||
else if (props.successMessage) return 'success';
|
||||
else return undefined;
|
||||
});
|
||||
|
||||
const labelState = computed(() => {
|
||||
if(!props.errorMessage && !props.successMessage && !props.disabled) return 'default';
|
||||
else if(!props.errorMessage && props.successMessage && !props.disabled) return 'success';
|
||||
else if(props.errorMessage && !props.successMessage && !props.disabled) return 'error';
|
||||
else return undefined
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="main-container">
|
||||
<VLabel
|
||||
:for="props.selectId"
|
||||
:label="props.label"
|
||||
:required="!props.disabled"
|
||||
:disabled="props.disabled"
|
||||
:type="labelState"
|
||||
:hint="props.hint"
|
||||
>
|
||||
<template #required-type v-if="props.required">
|
||||
<slot name="required-type"/>
|
||||
</template>
|
||||
</VLabel>
|
||||
<Select
|
||||
:name="props.name || props.selectId"
|
||||
:options="props.options"
|
||||
:optionLabel="props.optionLabel"
|
||||
:optionValue="props.optionValue"
|
||||
:disabled="props.disabled"
|
||||
:aria-disabled="props.disabled"
|
||||
:filter="props.filter"
|
||||
:editable="props.editable"
|
||||
:placeholder="props.placeholder"
|
||||
:filter-message="props.filterMessage"
|
||||
:selection-message="props.selectionMessage"
|
||||
:empty-selection-message="props.emptySelectionMessage"
|
||||
:empty-filter-message="props.emptyFilterMessage"
|
||||
:empty-message="props.emptyMessage"
|
||||
v-bind="$attrs"
|
||||
v-model:model-value="localModelValue"
|
||||
@update:model-value="emit('update:modelValue', $event)"
|
||||
@change="emit('change', $event)"
|
||||
@blur="emit('blur', $event)"
|
||||
@focus="emit('focus', $event)"
|
||||
@value-change="emit('value-change', $event)"
|
||||
@before-hide="emit('before-hide', $event)"
|
||||
@before-show="emit('before-show', $event)"
|
||||
@show="emit('show', $event)"
|
||||
@hide="emit('hide', $event)"
|
||||
@filter="emit('filter', $event)"
|
||||
class="p-select"
|
||||
:class="[
|
||||
styles['text-body-MD-standard-text-Regular'],
|
||||
{
|
||||
'disabled': props.disabled,
|
||||
'error': props.errorMessage && !props.successMessage && !props.disabled,
|
||||
'success': !props.errorMessage && props.successMessage && !props.disabled,
|
||||
}
|
||||
]"
|
||||
>
|
||||
<template v-if="props.optionTemplate" #option="{option, selected, index}">
|
||||
<slot name="option" :option="option" :selected="selected" :index="index"/>
|
||||
</template>
|
||||
</Select>
|
||||
<div
|
||||
:id="`select-${messageState}-desc-${messageState}`"
|
||||
role="alert"
|
||||
aria-live="assertive"
|
||||
>
|
||||
<VHint :title="message" :type="typeMessage" icon/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.main-container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: start;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.p-select{
|
||||
width: 100%;
|
||||
height: 2.5rem;
|
||||
}
|
||||
|
||||
.p-select.disabled{
|
||||
--p-select-border-color: var(--border-disabled-grey);
|
||||
--p-select-dropdown-color: var(--text-disabled-grey);
|
||||
}
|
||||
|
||||
.p-select.error{
|
||||
--p-select-border-color: var(--border-plain-error);
|
||||
--p-select-hover-border-color: var(--border-plain-error);
|
||||
--p-select-focus-border-color: var(--border-plain-error);
|
||||
}
|
||||
.p-select.success{
|
||||
--p-select-border-color: var(--border-plain-success);
|
||||
--p-select-hover-border-color: var(--border-plain-success);
|
||||
--p-select-focus-border-color: var(--border-plain-success);
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue
Block a user