✨ 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