feat(ui) : MalioDate — markedDates (statut par jour) + event month-change (#MUI-45) (#76)
## 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>
This commit was merged in pull request #76.
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
import {afterEach, beforeEach, describe, expect, it, vi} from 'vitest'
|
||||
import {mount} from '@vue/test-utils'
|
||||
import type {DefineComponent} from 'vue'
|
||||
import MonthGrid from './MonthGrid.vue'
|
||||
|
||||
type MonthGridProps = {
|
||||
month: number
|
||||
year: number
|
||||
selectedDate?: string | null
|
||||
markedDates?: Record<string, 'success' | 'danger'>
|
||||
min?: string
|
||||
max?: string
|
||||
}
|
||||
|
||||
const Grid = MonthGrid as DefineComponent<MonthGridProps>
|
||||
const mountGrid = (props: MonthGridProps) => mount(Grid, {props, attachTo: document.body})
|
||||
|
||||
// Récupère la pastille (span rond) qui porte les classes de `cellClass` pour un jour donné.
|
||||
const pill = (wrapper: ReturnType<typeof mountGrid>, iso: string) =>
|
||||
wrapper.get(`[data-iso="${iso}"]`).get('span.rounded-full')
|
||||
|
||||
describe('MalioDateMonthGrid — markedDates', () => {
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers()
|
||||
vi.setSystemTime(new Date(2026, 4, 19)) // 19 mai 2026
|
||||
})
|
||||
afterEach(() => vi.useRealTimers())
|
||||
|
||||
it('applique un fond success sur un jour marqué', () => {
|
||||
const wrapper = mountGrid({month: 4, year: 2026, markedDates: {'2026-05-20': 'success'}})
|
||||
expect(pill(wrapper, '2026-05-20').classes()).toContain('bg-m-success/15')
|
||||
})
|
||||
|
||||
it('applique un fond danger sur un jour marqué', () => {
|
||||
const wrapper = mountGrid({month: 4, year: 2026, markedDates: {'2026-05-21': 'danger'}})
|
||||
expect(pill(wrapper, '2026-05-21').classes()).toContain('bg-m-danger/15')
|
||||
})
|
||||
|
||||
it('ne marque pas les jours absents de markedDates', () => {
|
||||
const wrapper = mountGrid({month: 4, year: 2026, markedDates: {'2026-05-20': 'success'}})
|
||||
const classes = pill(wrapper, '2026-05-22').classes()
|
||||
expect(classes).not.toContain('bg-m-success/15')
|
||||
expect(classes).not.toContain('bg-m-danger/15')
|
||||
})
|
||||
|
||||
it('précédence : la sélection (primary) prime sur la variante marquée', () => {
|
||||
const wrapper = mountGrid({
|
||||
month: 4,
|
||||
year: 2026,
|
||||
selectedDate: '2026-05-22',
|
||||
markedDates: {'2026-05-22': 'success'},
|
||||
})
|
||||
const classes = pill(wrapper, '2026-05-22').classes()
|
||||
expect(classes).toContain('bg-m-primary')
|
||||
expect(classes).toContain('text-white')
|
||||
expect(classes).not.toContain('bg-m-success/15')
|
||||
})
|
||||
|
||||
it('today marqué : garde sa bordure ET reçoit le fond marqué', () => {
|
||||
const wrapper = mountGrid({month: 4, year: 2026, markedDates: {'2026-05-19': 'success'}})
|
||||
const classes = pill(wrapper, '2026-05-19').classes()
|
||||
expect(classes).toContain('border-m-primary')
|
||||
expect(classes).toContain('bg-m-success/15')
|
||||
})
|
||||
|
||||
it('today non marqué : bordure sans fond marqué', () => {
|
||||
const wrapper = mountGrid({month: 4, year: 2026, markedDates: {'2026-05-20': 'success'}})
|
||||
const classes = pill(wrapper, '2026-05-19').classes()
|
||||
expect(classes).toContain('border-m-primary')
|
||||
expect(classes).not.toContain('bg-m-success/15')
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user