feat(ui) : MalioDate — markedDates (statut par jour) + event month-change (#MUI-45)

MonthGrid : prop markedDates (Record<ISO, 'success'|'danger'>) appliquant un fond
tokenisé par jour (bg-m-success/15 / bg-m-danger/15). Précédence : sélection (primary)
> variante marquée ; today garde sa bordure ET reçoit le fond marqué.

CalendarField : emit month-change { month: 0-11, year } à l'ouverture du popover et
à chaque navigation de mois (watch sur isOpen + currentMonth/currentYear).

Date : expose markedDates (passée à MonthGrid via le slot) et réémet month-change.

Tests MonthGrid (variantes + précédence today/sélection) et Date (month-change à
l'ouverture/nav + passthrough markedDates). Doc COMPONENTS.md + CHANGELOG + story +
playground. Sert l'écran Heures de SIRH (jours validés en vert, chargement du mois visible).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-16 11:38:58 +02:00
parent cca15524f4
commit f2c1845ea1
9 changed files with 225 additions and 2 deletions
+8
View File
@@ -20,12 +20,14 @@
v-bind="$attrs"
@clear="onClear"
@commit="onCommit"
@month-change="(payload) => emit('month-change', payload)"
>
<template #default="{ currentMonth, currentYear, close }">
<MonthGrid
:month="currentMonth"
:year="currentYear"
:selected-date="modelValue ?? null"
:marked-dates="markedDates"
:min="min"
:max="max"
@select="(iso) => onSelect(iso, close)"
@@ -57,6 +59,9 @@ const props = withDefaults(
success?: string
min?: string
max?: string
// Statut générique par jour, ISO yyyy-mm-dd → variante de fond. Aucune
// logique métier dans le layer : le consommateur fournit la liste.
markedDates?: Record<string, 'success' | 'danger'>
clearable?: boolean
editable?: boolean
invalidMessage?: string
@@ -78,6 +83,7 @@ const props = withDefaults(
success: '',
min: undefined,
max: undefined,
markedDates: undefined,
clearable: true,
editable: false,
invalidMessage: 'Date invalide',
@@ -94,6 +100,8 @@ const emit = defineEmits<{
// tel que tapé sur saisie non parsable/hors plage, '' sinon. Ne JAMAIS transiter
// par modelValue, qui doit rester ISO|null pour l'affichage et le round-trip.
(e: 'update:rawValue', value: string): void
// Mois affiché dans le popover (month 0-11) : à l'ouverture et à chaque nav.
(e: 'month-change', value: {month: number, year: number}): void
}>()
const displayValue = computed(() => formatIsoToDisplay(props.modelValue ?? null))