41010060ff
## Sélecteur d'année dans le calendrier (3ᵉ niveau de navigation) Ajoute un 3ᵉ niveau de navigation à la famille de composants date, et corrige le bornage min/max du sélecteur de mois. ### Comportement - Clic sur le champ → calendrier (vue **jours**) - Clic sur l'en-tête → **sélecteur de mois** - **Re-clic sur l'en-tête → sélecteur d'année** (grille de 12 ans, chevrons paginant par pas de 12 ans, fenêtre centrée sur l'année courante − 5) - Clic sur une année → retour au sélecteur de mois ; clic sur un mois → retour à la grille de jours - Les props `min`/`max` **grisent les mois ET les années** hors plage (corrige l'asymétrie : le `MonthPicker` affichait jusqu'ici tous les mois) En-tête contextuel : « Mai 2026 » (jours) / « 2026 » (mois) / « 2020 – 2031 » (années). ### Périmètre - Shell partagé `internal/CalendarField.vue` → bénéficie aux 4 composants publics `Date`, `DateRange`, `DateTime`, `DateWeek` - **Aucune API publique modifiée** - Nouveau composant `internal/YearPicker.vue` (calqué sur `MonthPicker`) - Helpers purs `isMonthInRange` / `isYearInRange` (comparaison par préfixe ISO, bornes inclusives) - State machine `viewMode` à 3 niveaux (`useCalendarPopover` / `useCalendarView`) ### Tests - Suite date **246/246 verte**, ESLint propre - Unitaires : helpers, `YearPicker`, `MonthPicker` (grisage), composables (pagination ±12, recentrage, `selectYear`) - e2e `Date.test.ts` : flux complet jours→mois→années→mois→jours + grisage min/max ### Process Développé en brainstorming → spec → plan → exécution TDD (un commit par étape). Spec et plan inclus sous `docs/superpowers/`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Reviewed-on: #83 Co-authored-by: tristan <tristan@yuno.malio.fr> Co-committed-by: tristan <tristan@yuno.malio.fr>
49 lines
1.4 KiB
Vue
49 lines
1.4 KiB
Vue
<template>
|
|
<div
|
|
data-test="month-picker"
|
|
class="grid grid-cols-3 gap-3"
|
|
>
|
|
<button
|
|
v-for="(name, index) in months"
|
|
:key="name"
|
|
type="button"
|
|
data-test="month"
|
|
:data-month="index"
|
|
:disabled="!isMonthInRange(currentYear, index, min, max)"
|
|
:aria-disabled="!isMonthInRange(currentYear, index, min, max)"
|
|
class="flex h-[45px] w-full items-center justify-center"
|
|
:class="isMonthInRange(currentYear, index, min, max) ? 'cursor-pointer' : 'cursor-not-allowed'"
|
|
@click="emit('select', index)"
|
|
>
|
|
<span
|
|
class="flex h-[30px] w-full items-center justify-center rounded text-sm transition-colors duration-100"
|
|
:class="index === selectedMonth
|
|
? 'bg-m-primary text-white'
|
|
: isMonthInRange(currentYear, index, min, max)
|
|
? 'text-black hover:bg-m-primary/10'
|
|
: 'text-m-muted/30'"
|
|
>
|
|
{{ name }}
|
|
</span>
|
|
</button>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import {isMonthInRange} from '../composables/dateFormat'
|
|
|
|
defineOptions({name: 'MalioDateMonthPicker'})
|
|
|
|
defineProps<{
|
|
currentYear: number
|
|
selectedMonth?: number
|
|
min?: string
|
|
max?: string
|
|
}>()
|
|
|
|
const emit = defineEmits<{(e: 'select', month: number): void}>()
|
|
|
|
const months = ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin',
|
|
'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre']
|
|
</script>
|