fix(date) : borne la saisie clavier pour empêcher les dates absurdes (99/99/9999) (#79)
## 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>
This commit was merged in pull request #79.
This commit is contained in:
@@ -65,15 +65,17 @@
|
||||
? 'text-m-danger'
|
||||
: hasSuccess
|
||||
? 'text-m-success'
|
||||
: isReadonly
|
||||
? isOptionSelected
|
||||
? 'text-black'
|
||||
: 'text-m-muted'
|
||||
: isOpen
|
||||
? 'text-m-primary'
|
||||
: isOptionSelected
|
||||
: disabled
|
||||
? 'text-m-muted'
|
||||
: isReadonly
|
||||
? isOptionSelected
|
||||
? 'text-black'
|
||||
: 'text-m-muted',
|
||||
: 'text-m-muted'
|
||||
: isOpen
|
||||
? 'text-m-primary'
|
||||
: isOptionSelected
|
||||
? 'text-black'
|
||||
: 'text-m-muted',
|
||||
textLabel,
|
||||
]"
|
||||
:style="labelTransformStyle"
|
||||
@@ -89,7 +91,8 @@
|
||||
<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"
|
||||
class="inline-flex max-w-full items-center rounded-md border px-2 text-sm leading-none"
|
||||
:class="disabled ? 'border-black/40 text-black/60' : 'border-black text-black'"
|
||||
>
|
||||
<span class="truncate pb-[2px]">{{ option.label }}</span>
|
||||
</span>
|
||||
@@ -113,13 +116,14 @@
|
||||
:class="[
|
||||
textValue,
|
||||
label ? 'pl-24' : '',
|
||||
isOptionSelected ? 'text-black' : 'text-m-muted'
|
||||
disabled ? 'text-black/60' : isOptionSelected ? 'text-black' : 'text-m-muted'
|
||||
]"
|
||||
>
|
||||
{{ selectionSummary }}
|
||||
</span>
|
||||
|
||||
<span
|
||||
v-if="!disabled"
|
||||
data-test="chevron"
|
||||
class="absolute right-3 top-1/2 -translate-y-1/2"
|
||||
:class="[
|
||||
|
||||
Reference in New Issue
Block a user