feat : ajout composant select checkbox

This commit is contained in:
2026-03-12 15:31:29 +01:00
parent af4dcdfc04
commit c96eafdb23

View File

@@ -25,7 +25,7 @@
? openDirection === 'down' ? openDirection === 'down'
? 'rounded-b-none !border-2 !border-m-primary !border-b-0' ? 'rounded-b-none !border-2 !border-m-primary !border-b-0'
: 'rounded-t-none !border-2 !border-m-primary !border-t-0' : 'rounded-t-none !border-2 !border-m-primary !border-t-0'
: isOptionSelected : isOptionSelected
? 'border-black' ? 'border-black'
: 'border-m-muted', : 'border-m-muted',
disabled ? 'cursor-not-allowed border-m-muted text-black/60' : 'cursor-pointer', disabled ? 'cursor-not-allowed border-m-muted text-black/60' : 'cursor-pointer',
@@ -44,7 +44,7 @@
v-if="label" v-if="label"
class="floating-label pointer-events-none absolute left-3 inline-block origin-left transition-transform duration-150 font-medium" class="floating-label pointer-events-none absolute left-3 inline-block origin-left transition-transform duration-150 font-medium"
:class="[ :class="[
isOpen ? 'top-2 z-30' : 'top-1/2 -translate-y-1/2', shouldFloatLabel ? 'top-2 z-30' : 'top-1/2 -translate-y-1/2',
hasError hasError
? 'text-m-error' ? 'text-m-error'
: hasSuccess : hasSuccess
@@ -61,7 +61,22 @@
{{ label }} {{ label }}
</label> </label>
<div
v-if="displayTags && selectedOptions.length > 0"
class="flex flex-wrap items-center justify-start gap-1 px-1 pr-6"
:class="[label ? 'pt-3 pb-1' : '']"
>
<span
v-for="option in selectedOptions"
:key="String(option.value)"
class="inline-flex max-w-full items-center rounded-md border border-black px-2 text-sm leading-none text-black"
>
<span class="truncate">{{ option.label }}</span>
</span>
</div>
<span <span
v-show="!displayTags"
class="block truncate text-right" class="block truncate text-right"
:class="[ :class="[
textValue, textValue,
@@ -184,6 +199,7 @@ const props = withDefaults(defineProps<{
textValue?: string textValue?: string
textLabel?: string textLabel?: string
rounded?: string rounded?: string
displayTag?: boolean
disabled?: boolean disabled?: boolean
}>(), { }>(), {
options: () => [], options: () => [],
@@ -198,6 +214,7 @@ const props = withDefaults(defineProps<{
textValue: 'text-lg', textValue: 'text-lg',
textLabel: 'text-sm', textLabel: 'text-sm',
rounded: 'rounded-md', rounded: 'rounded-md',
displayTag: false,
disabled: false, disabled: false,
}) })
@@ -219,8 +236,14 @@ const hasSuccess = computed(() => !!props.success && !hasError.value)
const isOptionSelected = computed(() => const isOptionSelected = computed(() =>
props.modelValue.length > 0 props.modelValue.length > 0
) )
const selectedOptions = computed(() =>
normalizedOptions.value.filter(option => props.modelValue.includes(option.value)),
)
const displayTags = computed(() =>
props.displayTag && selectedOptions.value.length > 0,
)
const shouldFloatLabel = computed(() => const shouldFloatLabel = computed(() =>
isOpen.value isOpen.value || displayTags.value
) )
const selectionSummary = computed(() => const selectionSummary = computed(() =>
`${props.modelValue.length}/${normalizedOptions.value.length}` `${props.modelValue.length}/${normalizedOptions.value.length}`
@@ -264,24 +287,18 @@ function open() {
} }
const labelTransformStyle = computed(() => { const labelTransformStyle = computed(() => {
// label non flottant
if (!shouldFloatLabel.value) { if (!shouldFloatLabel.value) {
return { return undefined
transform: 'translateY(-50%)',
}
} }
// fermé ou ouverture vers le bas : comportement classique
if (!isOpen.value || openDirection.value === 'down') { if (!isOpen.value || openDirection.value === 'down') {
return { return {
transform: 'translateY(-1.15rem) scale(0.9)', transform: 'translateY(-1.15rem) scale(0.9)',
} }
} }
// ouverture vers le haut : on remonte en fonction de la hauteur de la liste
const extraOffset = 8 // marge visuelle au-dessus de la liste en px const extraOffset = 8 // marge visuelle au-dessus de la liste en px
const total = 4 +listHeight.value + extraOffset const total = 4 + listHeight.value + extraOffset
// 18 ≈ 1.15rem pour garder la même base que votre flottant actuel
return { return {
transform: `translateY(-${total}px) scale(0.9)`, transform: `translateY(-${total}px) scale(0.9)`,