feat : ajout composant select checkbox
This commit is contained in:
@@ -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)`,
|
||||||
|
|||||||
Reference in New Issue
Block a user