9f9723d01c
Ticket MUI-43 : exposer l'état de validité de MalioDate (saisie invalide avalée silencieusement) + portage de la saisie clavier sur MalioDateTime.
## Contenu
**MalioDate**
- Nouvel event `update:valid(boolean)` : `false` sur saisie malformée ou hors min/max (qui n'émet pas `modelValue`), `true` sinon ; émis dès le montage. La validité ne couvre pas `required` (champ vide = valide).
**MalioDateTime**
- Prop `editable` : saisie clavier `JJ/MM/AAAA HH:MM` (masque maska, validation au blur/Entrée, `invalidMessage`) + même `update:valid`.
- Nouveau parseur `parseDisplayToIsoDateTime`.
**Famille Date editable (Date + DateTime)**
- Gabarit fantôme progressif : le format s'affiche en gris et se remplit au fil de la saisie (overlay ghost mirror, texte de l'input transparent).
- Séparateurs (/, espace, :) posés automatiquement (maska `eager`), espace insécable pour éviter le collage `12/12/1999HH:MM`.
- `CalendarField` : prop `placeholderTemplate` (le masque maska en est dérivé).
**Corrections**
- La croix d'effacement réinitialise la saisie clavier même après une date invalide (le v-model restant null, le champ ne se vidait pas).
- Fix d'un test `Date.test.ts` cassé sur develop (`trigger('keydown.enter')` envoie key='enter' ≠ handler `e.key === 'Enter'`).
## Portée
MalioDate seul pour la validité (les cousins DateRange/DateWeek n'ont pas de saisie clavier donc pas le bug). Sémantique `valid` = malformé only.
## Tests
`app/components/malio/date/` : 187/187, ESLint propre. Vérifié visuellement dans le playground (page Date & heure).
## Doc
COMPONENTS.md + CHANGELOG.md à jour.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Reviewed-on: #71
Co-authored-by: tristan <tristan@yuno.malio.fr>
Co-committed-by: tristan <tristan@yuno.malio.fr>
85 lines
2.7 KiB
Vue
85 lines
2.7 KiB
Vue
<template>
|
|
<div class="space-y-6 p-4">
|
|
<h1 class="text-2xl font-bold">MalioDateTime</h1>
|
|
|
|
<div class="flex flex-wrap items-start gap-10">
|
|
<div class="w-[480px] space-y-3">
|
|
<h2 class="font-semibold">Large (480px)</h2>
|
|
<MalioDateTime
|
|
v-model="value"
|
|
label="Date et heure du rendez-vous"
|
|
hint="Choisis un jour puis une heure"
|
|
/>
|
|
<div class="rounded border p-3 text-sm">
|
|
<p>Valeur (ISO naïf) : <code>{{ value ?? 'null' }}</code></p>
|
|
</div>
|
|
<MalioDateTime
|
|
v-model="editableValue"
|
|
label="Date et heure (saisie clavier)"
|
|
editable
|
|
hint="Tape JJ/MM/AAAA HH:MM ou utilise le calendrier"
|
|
@update:valid="editableValid = $event"
|
|
/>
|
|
<div class="rounded border p-3 text-sm">
|
|
<p>Valeur éditable (ISO naïf) : <code>{{ editableValue ?? 'null' }}</code></p>
|
|
<p>
|
|
Saisie valide :
|
|
<code :class="editableValid ? 'text-m-success' : 'text-m-danger'">{{ editableValid }}</code>
|
|
</p>
|
|
</div>
|
|
<div class="flex gap-2">
|
|
<button
|
|
type="button"
|
|
class="rounded bg-m-primary px-3 py-1.5 text-white"
|
|
@click="value = '2026-12-25T09:30:00'"
|
|
>
|
|
Forcer le 25/12/2026 09:30
|
|
</button>
|
|
<button
|
|
type="button"
|
|
class="rounded border px-3 py-1.5"
|
|
@click="value = null"
|
|
>
|
|
Réinitialiser
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="w-[396px] space-y-3">
|
|
<h2 class="font-semibold">ERP (396px)</h2>
|
|
<MalioDateTime
|
|
v-model="erpValue"
|
|
label="Date et heure du rendez-vous"
|
|
hint="Largeur cible ERP"
|
|
/>
|
|
<div class="rounded border p-3 text-sm">
|
|
<p>Valeur (ISO naïf) : <code>{{ erpValue ?? 'null' }}</code></p>
|
|
</div>
|
|
<MalioDateTime
|
|
v-model="bounded"
|
|
label="Créneau borné"
|
|
:min="todayIso"
|
|
:max="maxIso"
|
|
hint="Entre aujourd'hui et +30 jours"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import {ref} from 'vue'
|
|
|
|
const pad = (n: number) => String(n).padStart(2, '0')
|
|
const toIso = (d: Date) => `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T00:00:00`
|
|
const now = new Date()
|
|
const todayIso = toIso(now)
|
|
const maxIso = toIso(new Date(now.getTime() + 30 * 86400000))
|
|
|
|
const value = ref<string | null>(null)
|
|
const erpValue = ref<string | null>(null)
|
|
const bounded = ref<string | null>('2026-05-20T14:30:00')
|
|
const editableValue = ref<string | null>(null)
|
|
const editableValid = ref(true)
|
|
</script>
|