be3d88ed45
## Problème Sur la famille Date editable, le masque maska n'imposait que la *forme* (`##/##/####`). Une valeur structurellement absurde comme `99/99/9999` était donc **saisissable**, puis rejetée *a posteriori* par la validation. Le métier veut que ce soit **impossible à taper**. ## Solution (masque borné + validation en filet) - `composables/maskTemplate.ts` — `buildBoundedMask(template)` : borne le **premier chiffre de chaque champ** (jour `0-3`, mois `0-1`, heure `0-2`, minute `0-5`). Distingue le mois des minutes (même lettre `M`) selon la présence d'heures dans le gabarit, pour ne pas brider la saisie des minutes du DateTime. - `internal/CalendarField.vue` — branche le builder dans `maskaOptions` (remplace le `replace(/[A-Za-z]/g, '#')`). Les impossibilités plus fines (`31/02`, 29/02 non bissextile, hors `min`/`max`) restent captées par la **validation** (`invalidMessage` + `update:valid=false`). ## Tests - `maskTemplate.test.ts` (5) — bornes par champ, structure du masque, non-confusion mois/minutes. - `Date.test.ts` — test `invalidMessage` adapté (`32/13/2026`, typable→invalide) + garde de non-régression : `99/99/9999` ne s'inscrit jamais et n'émet aucune date. - Suite complète : **1004/1004 verte** (DateTime 36 incluse → saisie d'heure intacte). Doc : `COMPONENTS.md` (MalioDate) + `CHANGELOG.md` (Fixed) à jour. Reviewed-on: #79 Co-authored-by: tristan <tristan@yuno.malio.fr> Co-committed-by: tristan <tristan@yuno.malio.fr>
295 lines
8.6 KiB
Vue
295 lines
8.6 KiB
Vue
<template>
|
|
<div class="space-y-6 p-4">
|
|
<h1 class="text-2xl font-bold">Champs désactivés (disabled)</h1>
|
|
<p class="text-sm text-m-muted">
|
|
Tous les champs de formulaire dans leur état <code>disabled</code>, vides puis remplis.
|
|
Règles : texte + label grisés, <code>cursor-not-allowed</code>, et <strong>aucune affordance
|
|
interactive</strong> (pas de bouton « + », pas de croix « x », pas de chevron, pas d'œil ;
|
|
tags et valeurs grisés).
|
|
</p>
|
|
|
|
<div class="grid grid-cols-1 items-start gap-6 md:grid-cols-2 xl:grid-cols-3">
|
|
<div class="rounded-lg border p-4">
|
|
<h2 class="mb-4 text-xl font-bold">MalioInputText</h2>
|
|
<div class="space-y-4">
|
|
<MalioInputText
|
|
label="Référence (vide)"
|
|
:disabled="true"
|
|
/>
|
|
<MalioInputText
|
|
model-value="Commande #A-2048"
|
|
label="Référence (rempli)"
|
|
icon-name="mdi:lock-outline"
|
|
icon-size="20"
|
|
:disabled="true"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="rounded-lg border p-4">
|
|
<h2 class="mb-4 text-xl font-bold">MalioInputEmail (addable → pas de « + »)</h2>
|
|
<div class="space-y-4">
|
|
<MalioInputEmail
|
|
label="Adresse email (vide)"
|
|
:addable="true"
|
|
:disabled="true"
|
|
/>
|
|
<MalioInputEmail
|
|
model-value="contact@malio.fr"
|
|
label="Adresse email (rempli)"
|
|
:addable="true"
|
|
:disabled="true"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="rounded-lg border p-4">
|
|
<h2 class="mb-4 text-xl font-bold">MalioInputPhone (addable → pas de « + »)</h2>
|
|
<div class="space-y-4">
|
|
<MalioInputPhone
|
|
label="Téléphone (vide)"
|
|
:addable="true"
|
|
:disabled="true"
|
|
/>
|
|
<MalioInputPhone
|
|
model-value="+33 6 12 34 56 78"
|
|
label="Téléphone (rempli)"
|
|
:addable="true"
|
|
:disabled="true"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="rounded-lg border p-4">
|
|
<h2 class="mb-4 text-xl font-bold">MalioInputPassword (pas d'œil)</h2>
|
|
<div class="space-y-4">
|
|
<MalioInputPassword
|
|
label="Mot de passe (vide)"
|
|
:disabled="true"
|
|
/>
|
|
<MalioInputPassword
|
|
model-value="motdepasse123"
|
|
label="Mot de passe (rempli)"
|
|
:disabled="true"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="rounded-lg border p-4">
|
|
<h2 class="mb-4 text-xl font-bold">MalioInputAmount</h2>
|
|
<div class="space-y-4">
|
|
<MalioInputAmount
|
|
label="Montant (vide)"
|
|
:disabled="true"
|
|
/>
|
|
<MalioInputAmount
|
|
model-value="1250.00"
|
|
label="Montant (rempli)"
|
|
:disabled="true"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="rounded-lg border p-4">
|
|
<h2 class="mb-4 text-xl font-bold">MalioInputNumber</h2>
|
|
<div class="space-y-4">
|
|
<MalioInputNumber
|
|
label="Quantité (vide)"
|
|
:disabled="true"
|
|
/>
|
|
<MalioInputNumber
|
|
model-value="42"
|
|
label="Quantité (rempli)"
|
|
:disabled="true"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="rounded-lg border p-4">
|
|
<h2 class="mb-4 text-xl font-bold">MalioInputTextArea</h2>
|
|
<div class="space-y-4">
|
|
<MalioInputTextArea
|
|
label="Description (vide)"
|
|
:size="3"
|
|
:disabled="true"
|
|
/>
|
|
<MalioInputTextArea
|
|
model-value="Ce texte est désactivé et ne peut pas être modifié."
|
|
label="Description (rempli)"
|
|
:size="3"
|
|
:disabled="true"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="rounded-lg border p-4">
|
|
<h2 class="mb-4 text-xl font-bold">MalioInputUpload (pas de croix)</h2>
|
|
<div class="space-y-4">
|
|
<MalioInputUpload
|
|
label="Fichier (vide)"
|
|
:disabled="true"
|
|
/>
|
|
<MalioInputUpload
|
|
model-value="document.pdf"
|
|
label="Fichier (rempli)"
|
|
:disabled="true"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="rounded-lg border p-4">
|
|
<h2 class="mb-4 text-xl font-bold">MalioInputAutocomplete (pas de chevron)</h2>
|
|
<div class="space-y-4">
|
|
<MalioInputAutocomplete
|
|
label="Pays (vide)"
|
|
:options="countryOptions"
|
|
:disabled="true"
|
|
/>
|
|
<MalioInputAutocomplete
|
|
model-value="de"
|
|
label="Pays (rempli)"
|
|
:options="countryOptions"
|
|
:disabled="true"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="rounded-lg border p-4">
|
|
<h2 class="mb-4 text-xl font-bold">MalioSelect (pas de chevron)</h2>
|
|
<div class="space-y-4">
|
|
<MalioSelect
|
|
label="Catégorie (vide)"
|
|
:options="categoryOptions"
|
|
empty-option-label="Aucune sélection"
|
|
:disabled="true"
|
|
/>
|
|
<MalioSelect
|
|
:model-value="'a'"
|
|
label="Catégorie (rempli)"
|
|
:options="categoryOptions"
|
|
empty-option-label="Aucune sélection"
|
|
:disabled="true"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="rounded-lg border p-4">
|
|
<h2 class="mb-4 text-xl font-bold">MalioSelectCheckbox — version tags (grisés)</h2>
|
|
<div class="space-y-4">
|
|
<MalioSelectCheckbox
|
|
label="Catégories (vide)"
|
|
:options="categoryOptions"
|
|
:display-tag="true"
|
|
:disabled="true"
|
|
/>
|
|
<MalioSelectCheckbox
|
|
:model-value="['a', 'b', 'c']"
|
|
label="Catégories (rempli)"
|
|
:options="categoryOptions"
|
|
:display-tag="true"
|
|
:disabled="true"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="rounded-lg border p-4">
|
|
<h2 class="mb-4 text-xl font-bold">MalioDate (pas de croix)</h2>
|
|
<div class="space-y-4">
|
|
<MalioDate
|
|
label="Date de naissance (vide)"
|
|
:disabled="true"
|
|
/>
|
|
<MalioDate
|
|
model-value="2026-06-15"
|
|
label="Date de naissance (rempli)"
|
|
:disabled="true"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="rounded-lg border p-4">
|
|
<h2 class="mb-4 text-xl font-bold">MalioDateTime</h2>
|
|
<div class="space-y-4">
|
|
<MalioDateTime
|
|
label="Date et heure (vide)"
|
|
:disabled="true"
|
|
/>
|
|
<MalioDateTime
|
|
model-value="2026-12-25T09:30:00"
|
|
label="Date et heure (rempli)"
|
|
:disabled="true"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="rounded-lg border p-4">
|
|
<h2 class="mb-4 text-xl font-bold">MalioDateRange</h2>
|
|
<div class="space-y-4">
|
|
<MalioDateRange
|
|
label="Période (vide)"
|
|
:disabled="true"
|
|
/>
|
|
<MalioDateRange
|
|
:model-value="rangeValue"
|
|
label="Période (rempli)"
|
|
:disabled="true"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="rounded-lg border p-4">
|
|
<h2 class="mb-4 text-xl font-bold">MalioDateWeek</h2>
|
|
<div class="space-y-4">
|
|
<MalioDateWeek
|
|
label="Semaine (vide)"
|
|
:disabled="true"
|
|
/>
|
|
<MalioDateWeek
|
|
model-value="2026-W52"
|
|
label="Semaine (rempli)"
|
|
:disabled="true"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="rounded-lg border p-4">
|
|
<h2 class="mb-4 text-xl font-bold">MalioTimePicker (pas de croix)</h2>
|
|
<div class="space-y-4">
|
|
<MalioTimePicker
|
|
label="Heure (vide)"
|
|
:disabled="true"
|
|
/>
|
|
<MalioTimePicker
|
|
model-value="14:30"
|
|
label="Heure (rempli)"
|
|
:disabled="true"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import {ref} from 'vue'
|
|
|
|
type Option = {label: string; value: string | number}
|
|
|
|
const countryOptions: Option[] = [
|
|
{label: 'France', value: 'fr'},
|
|
{label: 'Belgique', value: 'be'},
|
|
{label: 'Canada', value: 'ca'},
|
|
{label: 'Suisse', value: 'ch'},
|
|
{label: 'Luxembourg', value: 'lu'},
|
|
{label: 'Allemagne', value: 'de'},
|
|
]
|
|
|
|
const categoryOptions: Option[] = [
|
|
{label: 'Catégorie A', value: 'a'},
|
|
{label: 'Catégorie B', value: 'b'},
|
|
{label: 'Catégorie C', value: 'c'},
|
|
]
|
|
|
|
const rangeValue = ref<{start: string; end: string}>({start: '2026-12-20', end: '2026-12-31'})
|
|
</script>
|