feat(ui) : cohérence du mode disabled sur la famille formulaire

Calqué sur InputText (texte + label grisés, cursor-not-allowed, aucune affordance
interactive). Quand disabled :
- bouton « + » d'ajout masqué (InputPhone, InputEmail)
- œil de révélation masqué (InputPassword)
- chevron masqué (Select, SelectCheckbox, InputAutocomplete)
- croix d'effacement déjà masquée (date, upload, time)
- label en text-m-muted (Select, SelectCheckbox, CalendarField → famille Date, TimePicker, InputNumber aligné)
- tags du SelectCheckbox + valeur du Select grisés ; icône horloge (TimePicker) et icône calendrier (date, même rempli) grisées

Playground : page « Champs disabled » (DIVERS) en miroir de la page readonly,
avec le SelectCheckbox en version tags. Tests par composant ajoutés/adaptés.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-19 14:53:13 +02:00
parent 0558d8c58a
commit ac1d6e7df3
20 changed files with 408 additions and 60 deletions
+17
View File
@@ -238,6 +238,23 @@ describe('MalioDate', () => {
expect(wrapper.find('[data-test="popover"]').exists()).toBe(false)
})
it('disabled : label grisé', () => {
const wrapper = mountDate({disabled: true, label: 'Date'})
expect(wrapper.get('label').classes()).toContain('text-m-muted')
})
it('disabled : pas de croix d\'effacement même avec une valeur', () => {
const wrapper = mountDate({disabled: true, modelValue: '2026-05-19'})
expect(wrapper.find('[data-test="clear"]').exists()).toBe(false)
})
it('disabled + rempli : icône calendrier grisée (pas noire)', () => {
const wrapper = mountDate({disabled: true, modelValue: '2026-05-19'})
const icon = wrapper.get('[data-test="calendar-icon"]')
expect(icon.classes()).toContain('text-m-muted')
expect(icon.classes()).not.toContain('text-black')
})
it('does not open when readonly', async () => {
const wrapper = mountDate({readonly: true, modelValue: '2026-05-19'})
await wrapper.get('[data-test="date-input"]').trigger('click')
@@ -358,11 +358,13 @@ const mergedLabelClass = computed(() =>
? 'text-m-danger'
: hasSuccess.value
? 'text-m-success'
: isReadonly.value
? isFilled.value ? 'text-black' : 'text-m-muted'
: isOpen.value
? 'text-m-primary'
: 'peer-placeholder-shown:text-m-muted text-black',
: props.disabled
? 'text-m-muted'
: isReadonly.value
? isFilled.value ? 'text-black' : 'text-m-muted'
: isOpen.value
? 'text-m-primary'
: 'peer-placeholder-shown:text-m-muted text-black',
props.labelClass,
),
)
@@ -370,6 +372,7 @@ const mergedLabelClass = computed(() =>
const iconStateClass = computed(() => {
if (hasError.value) return 'text-m-danger'
if (hasSuccess.value) return 'text-m-success'
if (props.disabled) return 'text-m-muted'
if (isReadonly.value) return isFilled.value ? 'text-black' : 'text-m-muted'
if (isOpen.value) return 'text-m-primary'
if (isFilled.value) return 'text-black'