b4841f40ed
## MUI-45 — MalioDate : statut par jour (`markedDates`) + event `@month-change`
Étend la famille `date` du layer de façon **générique** (aucune logique métier dans le layer) pour marquer des jours et exposer le mois affiché. **Bloquant** pour le ticket SIRH « Heures (vue Jour) : calendrier avec jours validés en vert ».
### Changements
- **`MonthGrid.vue`** : prop `markedDates?: Record<string /* ISO yyyy-mm-dd */, 'success' | 'danger'>`. Fond tokenisé par jour (`bg-m-success/15` / `bg-m-danger/15`, par opacité — pas de nouveau token). **Précédence** : sélection (primary) > variante marquée ; le jour courant (`today`) **garde sa bordure ET reçoit le fond marqué**.
- **`CalendarField.vue`** : emit `month-change { month: 0-11, year }` à l'ouverture du popover **et** à chaque navigation de mois.
- **`Date.vue`** : expose `markedDates` (passée à `MonthGrid` via le slot) et réémet `month-change`.
> `success` et `danger` suffisent dans un premier temps (pas de `warning`).
> `month` est **0-11** (état brut de `useCalendarView`).
### Tests
- `MonthGrid.test.ts` (nouveau) : variantes success/danger, précédence sélection, today marqué (bordure + fond) / non marqué.
- `Date.test.ts` (+5) : `month-change` à l'ouverture (mois courant / mois de la valeur), à chaque nav, non ré-émis après fermeture, passthrough `markedDates`.
- Suite complète : **998/998** verts, lint clean.
### Doc / démo
- `COMPONENTS.md` (section MalioDate) + `CHANGELOG.md` (`[#MUI-45]`).
- Story `app/story/date/datePicker.story.vue` + playground `.playground/pages/composant/date/date.vue`.
### Reste à faire (hors PR)
- Publier une version du layer **> 1.4.6** incluant la famille `date` (débloque SIRH).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Reviewed-on: #76
Co-authored-by: tristan <tristan@yuno.malio.fr>
Co-committed-by: tristan <tristan@yuno.malio.fr>
133 lines
4.5 KiB
Vue
133 lines
4.5 KiB
Vue
<template>
|
|
<div class="space-y-6 p-4">
|
|
<h1 class="text-2xl font-bold">MalioDate</h1>
|
|
|
|
<div class="flex flex-wrap items-start gap-10">
|
|
<div class="w-[480px] space-y-3">
|
|
<h2 class="font-semibold">Large (480px)</h2>
|
|
<MalioDate
|
|
v-model="value"
|
|
label="Date de naissance"
|
|
hint="Clique pour ouvrir le calendrier"
|
|
/>
|
|
<div class="rounded border p-3 text-sm">
|
|
<p>Valeur (ISO) : <code>{{ value ?? 'null' }}</code></p>
|
|
</div>
|
|
<MalioDate
|
|
v-model="editableValue"
|
|
label="Date (saisie clavier)"
|
|
editable
|
|
hint="Tape JJ/MM/AAAA ou utilise le calendrier"
|
|
/>
|
|
<div class="rounded border p-3 text-sm">
|
|
<p>Valeur éditable (ISO) : <code>{{ editableValue ?? 'null' }}</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-25'"
|
|
>
|
|
Forcer le 25/12/2026
|
|
</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>
|
|
<MalioDate
|
|
v-model="erpValue"
|
|
label="Date du rendez-vous"
|
|
hint="Largeur cible ERP"
|
|
/>
|
|
<div class="rounded border p-3 text-sm">
|
|
<p>Valeur (ISO) : <code>{{ erpValue ?? 'null' }}</code></p>
|
|
</div>
|
|
<MalioDate
|
|
v-model="bounded"
|
|
label="Date bornée"
|
|
:min="todayIso"
|
|
:max="maxIso"
|
|
hint="Entre aujourd'hui et +30 jours"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex flex-wrap items-start gap-10">
|
|
<div class="w-[396px] space-y-3">
|
|
<h2 class="font-semibold">Readonly (readonly vide)</h2>
|
|
<MalioDate
|
|
label="Date de naissance (readonly vide)"
|
|
:readonly="true"
|
|
/>
|
|
</div>
|
|
|
|
<div class="w-[396px] space-y-3">
|
|
<h2 class="font-semibold">Readonly (readonly rempli)</h2>
|
|
<MalioDate
|
|
v-model="readonlyFilledDate"
|
|
label="Date de naissance (readonly rempli)"
|
|
:readonly="true"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex flex-wrap items-start gap-10">
|
|
<div class="w-[396px] space-y-3">
|
|
<h2 class="font-semibold">markedDates + @month-change</h2>
|
|
<MalioDate
|
|
v-model="markedValue"
|
|
label="Calendrier avec statuts par jour"
|
|
hint="Jours verts = validés, rouges = à corriger"
|
|
:marked-dates="markedDates"
|
|
@month-change="onMonthChange"
|
|
/>
|
|
<div class="rounded border p-3 text-sm">
|
|
<p>Mois affiché : <code>{{ shownMonth }}</code></p>
|
|
<p class="mt-1 text-m-success">● success : {{ successDays.join(', ') }}</p>
|
|
<p class="text-m-danger">● danger : {{ dangerDays.join(', ') }}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import {computed, 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())}`
|
|
const now = new Date()
|
|
const todayIso = toIso(now)
|
|
const maxIso = toIso(new Date(now.getTime() + 30 * 86400000))
|
|
|
|
const readonlyFilledDate = ref<string | null>('2026-06-15')
|
|
const value = ref<string | null>(null)
|
|
const erpValue = ref<string | null>(null)
|
|
const bounded = ref<string | null>(null)
|
|
const editableValue = ref<string | null>(null)
|
|
|
|
// Démo markedDates : quelques jours du mois courant marqués success / danger.
|
|
const ym = `${now.getFullYear()}-${pad(now.getMonth() + 1)}`
|
|
const successDays = [`${ym}-05`, `${ym}-06`, `${ym}-12`]
|
|
const dangerDays = [`${ym}-09`, `${ym}-20`]
|
|
const markedDates = computed<Record<string, 'success' | 'danger'>>(() => ({
|
|
...Object.fromEntries(successDays.map(d => [d, 'success' as const])),
|
|
...Object.fromEntries(dangerDays.map(d => [d, 'danger' as const])),
|
|
}))
|
|
const markedValue = ref<string | null>(null)
|
|
const monthsLong = ['janvier', 'février', 'mars', 'avril', 'mai', 'juin',
|
|
'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre']
|
|
const shownMonth = ref('—')
|
|
const onMonthChange = ({month, year}: {month: number, year: number}) => {
|
|
shownMonth.value = `${monthsLong[month]} ${year} (month=${month})`
|
|
}
|
|
</script>
|