feat(ui) : état readonly visuel sur Select et SelectCheckbox

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-03 16:11:13 +02:00
parent f5163f10f1
commit 621077f555
4 changed files with 162 additions and 36 deletions
+35 -18
View File
@@ -8,8 +8,10 @@
:id="buttonId"
ref="buttonRef"
type="button"
class="grow-height peer relative w-full border bg-white pl-3 pr-10 py-1 text-left outline-none focus-visible:border-m-primary"
class="peer relative w-full border bg-white pl-3 pr-10 py-1 text-left outline-none"
:class="[
isReadonly ? '' : 'grow-height',
isReadonly ? '' : 'focus-visible:border-m-primary',
hasError
? isOpen
? openDirection === 'down'
@@ -22,14 +24,16 @@
? 'rounded-b-none !border !border-m-success !border-b-transparent'
: 'rounded-t-none !border !border-m-success !border-t-transparent'
: 'border-m-success'
: isOpen
? openDirection === 'down'
? 'rounded-b-none !border !border-m-primary !border-b-transparent'
: 'rounded-t-none !border !border-m-primary !border-t-transparent'
: isOptionSelected
? 'border-black'
: 'border-m-muted',
disabled ? 'cursor-not-allowed border-m-muted text-black/60' : 'cursor-pointer',
: isReadonly
? 'border-black'
: isOpen
? openDirection === 'down'
? 'rounded-b-none !border !border-m-primary !border-b-transparent'
: 'rounded-t-none !border !border-m-primary !border-t-transparent'
: isOptionSelected
? 'border-black'
: 'border-m-muted',
disabled ? 'cursor-not-allowed border-m-muted text-black/60' : isReadonly ? 'cursor-default' : 'cursor-pointer',
label ? 'min-h-[40px]' : 'h-[40px] py-0',
rounded,
textField,
@@ -39,6 +43,7 @@
:aria-invalid="hasError"
:aria-describedby="describedBy"
:aria-required="required || undefined"
:aria-readonly="readonly || undefined"
:disabled="disabled"
@click="toggle"
>
@@ -51,11 +56,15 @@
? 'text-m-danger'
: hasSuccess
? 'text-m-success'
: isOpen
? 'text-m-primary'
: isOptionSelected
: isReadonly
? isOptionSelected
? 'text-black'
: 'text-m-muted',
: 'text-m-muted'
: isOpen
? 'text-m-primary'
: isOptionSelected
? 'text-black'
: 'text-m-muted',
textLabel,
]"
:style="labelTransformStyle"
@@ -83,11 +92,15 @@
? 'text-m-success'
: disabled
? 'text-m-muted'
: isOpen
? 'text-m-primary'
: isOptionSelected
: isReadonly
? isOptionSelected
? 'text-black'
: 'text-m-muted'
: isOpen
? 'text-m-primary'
: isOptionSelected
? 'text-black'
: 'text-m-muted'
]"
>
<slot name="icon">
@@ -193,6 +206,7 @@ const props = withDefaults(defineProps<{
textLabel?: string
rounded?: string
disabled?: boolean
readonly?: boolean
groupClass?: string
noOptionsText?: string
required?: boolean
@@ -208,6 +222,7 @@ const props = withDefaults(defineProps<{
textLabel: 'text-sm',
rounded: 'rounded-md',
disabled: false,
readonly: false,
groupClass: '',
noOptionsText: 'Aucune option disponible',
required: false,
@@ -238,8 +253,9 @@ const hasSuccess = computed(() => !!props.success && !hasError.value)
const isOptionSelected = computed(() =>
props.options.some(o => o.value === props.modelValue)
)
const isReadonly = computed(() => props.readonly && !props.disabled)
const shouldFloatLabel = computed(() =>
isOpen.value || isOptionSelected.value
isReadonly.value ? isOptionSelected.value : (isOpen.value || isOptionSelected.value)
)
const selectedLabel = computed(() =>
props.options.find(o => o.value === props.modelValue)?.label ?? ''
@@ -267,6 +283,7 @@ function updateOpenDirection() {
}
function open() {
if (props.disabled || props.readonly) return
updateOpenDirection()
isOpen.value = true
@@ -310,7 +327,7 @@ function close() {
}
function toggle() {
if (props.disabled) return
if (props.disabled || props.readonly) return
if (isOpen.value) {
close()
return