Date Components
Our own dayjs-based calendar — single date and range, one or two months, with shortcuts — and the two field pickers built on it, InputDatePicker and InputDateRangePicker.
Calendar — single date
A self-contained, dayjs-based month calendar — no react-day-picker / date-fns. Locale-aware : month / weekday names and the first day of week follow the language (switch 🇫🇷 / 🇬🇧). Click the month or year in the header to jump quickly (month grid → year grid → back to days).
Selected : Fri Aug 07 2026
clearable — click the selected day again, or press Esc, to clear.
No value selected — the view starts on January 2030 via defaultMonth.
Independent of the locale : weekStartsOn="sun" starts weeks on Sunday even in 🇫🇷 (which is Monday by default). Accepts 0–6 or 'sun'…'sat'.
Calendar — range
The same calendar in range mode, over one or two months, with a live hover preview and optional shortcuts (presets).
Shortcut labels follow the language. On mobile they become a swipeable strip.
From — to —
The 10th and the 18th–22nd are blocked (struck through, inert). By default a range stops before a blocked day; the second calendar sets allowDisabledInRange so a range may span them.
Each shortcut carries an Icon; a { divider: true } item splits the list (a vertical rule in the mobile strip, a horizontal one in the column).
Input date picker
The masked field and the calendar share one value : typing updates the calendar, picking a day fills the field and closes. The popover opens as a dropdown anchored to the field on desktop and as a centered modal on mobile — force either with display="dropdown" | "modal".
Type or pick; × to clear.
Out-of-range days are disabled
Selected (responsive) : —
Custom mode + separator
Input date range picker
The range mirror : it maps the field's { start, end } to the calendar's { from, to } and only closes once both endpoints are picked. Same responsive popover, with a wider dual-month dropdown on desktop.
Type or pick two days; × to clear.
Out-of-range days are disabled
Selected (responsive) : —
rangeSeparator=' → '
With a footer, picking is deferred : the field commits on Apply and reverts on Cancel / Esc. Choose where it shows : "always", "mobile" (below md only), or "desktop" (md+ only). Resize the window to see the mobile / desktop ones toggle.
Footer only below md
Footer only at md+
Both fields get an onDate / onDateRange arrow recreated on every render, whose setState is never idempotent (a counter plus a fresh object). The emit counters must settle — one emit on mount, one per real change. If they run away (« Maximum update depth exceeded »), the parse effect is looping again.
onDate emits : 0 · last : —
onDateRange emits : 0 · last : —
Input date-time picker
A date field + a time field sharing one popover that hosts the calendar and the time columns. The value is the combined string (e.g. 25/12/2026 14:30); the parsed Date comes via onDateTime. The popover stays open and closes on outside-click / Esc — or via the optional footer.
Pick a day then a time; × to clear.
Picks are deferred until Apply
Selected : —
The Popover panel portals into the host dialog[open](body-level content under a modal dialog is inert and paints below the top layer). Escape closes the topmost surface only : the picker when open, then « Éditer ».
Date : — · Heure : — · Date-heure : —