laif-ds
Version:
Design System di Laif con componenti React basati su principi di Atomic Design
223 lines (180 loc) • 8.11 kB
Markdown
# Calendar
## Overview
Flexible calendar component built on `react-day-picker`. Supports single, multiple, and range selections, localization, week settings, and rich customization via class names and sub-components.
---
## Props
Props extend `DayPicker` props with a few defaults and additions.
| Prop | Type | Default | Description |
| ---------------- | -------------------------------------------- | ------------ | ------------------------------------------------ |
| `mode` | `"default" | "single" | "multiple" | "range"` | `"default"` | Selection mode. |
| `selected` | `Date | Date[] | DateRange` | `undefined` | Controlled selection value. |
| `defaultMonth` | `Date` | `undefined` | Month to display initially. |
| `fromDate` | `Date` | `undefined` | Minimum selectable date. |
| `toDate` | `Date` | `undefined` | Maximum selectable date. |
| `disabled` | `Matcher | Matcher[]` | `undefined` | Disabled dates. |
| `showOutsideDays`| `boolean` | `true` | Show days from adjacent months. |
| `ISOWeek` | `boolean` | `false` | Use ISO week numbering. |
| `fixedWeeks` | `boolean` | `false` | Always show 6 weeks. |
| `numberOfMonths` | `number` | `1` | Number of months to display. |
| `locale` | `Locale` | `undefined` | Locale object for formatting. |
| `weekStartsOn` | `0 | 1 | 2 | 3 | 4 | 5 | 6` | `0` | Start of the week (0=Sun, 1=Mon, ...). |
| `captionLayout` | `"label" | "dropdown"` | `"label"` | Caption rendering mode. |
| `buttonVariant` | `Button["variant"]` | `"ghost"` | Variant for navigation buttons. |
| `formatters` | `Partial<DayPickerFormatters>` | `{}` | Custom label formatters. |
| `components` | `Partial<DayPickerComponents>` | `{}` | Custom component overrides. |
| `className` | `string` | `""` | Additional container classes. |
| `onSelect` | `(value: Date | Date[] | DateRange | undefined) => void` | `undefined` | Called when selection changes. |
| `onDayClick` | `(day: Date) => void` | `undefined` | Called on day click. |
| `onMonthChange` | `(month: Date) => void` | `undefined` | Called when the displayed month changes. |
---
## Behavior
- **Selection**: Single, multiple, and range selection with visual feedback.
- **Navigation**: Previous/next buttons use `buttonVariant` styling.
- **Localization**: Supply `locale`, `weekStartsOn`, and `formatters` for i18n.
- **Accessibility**: Keyboard navigation and focus management included.
---
## Examples
### Basic
```tsx
import { Calendar } from "laif-ds";
export function BasicCalendar() {
return (
<Calendar
className="border-d-border rounded-md border"
showOutsideDays
onDayClick={(d) => console.log("day clicked", d)}
onMonthChange={(m) => console.log("month", m)}
/>
);
}
```
### Single Selection
```tsx
import { useState } from "react";
import { Calendar } from "laif-ds";
export function SingleSelection() {
const [date, setDate] = useState<Date | undefined>(new Date());
return (
<div className="flex flex-col gap-2">
<Calendar
mode="single"
selected={date}
onSelect={setDate}
className="border-d-border rounded-md border"
/>
<p className="text-sm text-d-secondary-foreground text-center">
{date ? date.toDateString() : "Nessuna data selezionata"}
</p>
</div>
);
}
```
### Multiple Selection
```tsx
import { useState } from "react";
import { Calendar } from "laif-ds";
export function MultipleSelection() {
const [dates, setDates] = useState<Date[] | undefined>([new Date()]);
return (
<div className="flex flex-col gap-2">
<Calendar
mode="multiple"
selected={dates}
onSelect={setDates}
className="border-d-border rounded-md border"
/>
<p className="text-sm text-d-secondary-foreground text-center">
{dates && dates.length > 0 ? `${dates.length} date selezionate` : "Nessuna data selezionata"}
</p>
</div>
);
}
```
### Range Selection
```tsx
import { useState } from "react";
import { Calendar } from "laif-ds";
import type { DateRange } from "react-day-picker";
export function RangeSelection() {
const [range, setRange] = useState<DateRange | undefined>({ from: new Date(), to: new Date() });
return (
<div className="flex flex-col gap-2">
<Calendar
mode="range"
selected={range}
onSelect={setRange}
className="border-d-border rounded-md border"
numberOfMonths={2}
showOutsideDays
/>
<p className="text-sm text-d-secondary-foreground text-center">
{range?.from && range?.to
? `${range.from.toDateString()} - ${range.to.toDateString()}`
: range?.from
? `Da ${range.from.toDateString()}`
: "Seleziona un intervallo"}
</p>
</div>
);
}
```
### Disabled Dates
```tsx
import { useState } from "react";
import { Calendar } from "laif-ds";
import { addDays } from "date-fns";
export function DisabledDates() {
const [date, setDate] = useState<Date | undefined>(new Date());
const disabledDays = [
{ from: addDays(new Date(), 1), to: addDays(new Date(), 5) },
new Date(new Date().setDate(15)),
{ before: addDays(new Date(), -10) },
];
return (
<Calendar
mode="single"
selected={date}
onSelect={setDate}
disabled={disabledDays}
className="border-d-border rounded-md border"
/>
);
}
```
### Localized (Italian) and Week Start
```tsx
import { Calendar } from "laif-ds";
import { it } from "date-fns/locale";
import { format } from "date-fns";
export function LocalizedCalendar() {
return (
<Calendar
className="border-d-border rounded-md border"
locale={it}
weekStartsOn={1}
formatters={{
formatMonthCaption: (date: Date) => format(date, "MMMM yyyy", { locale: it }),
formatWeekdayName: (date: Date) => format(date, "EEEEEE", { locale: it }),
}}
/>
);
}
```
### ISO Week, Fixed Weeks, Multiple Months
```tsx
import { Calendar } from "laif-ds";
export function ISOWeekCalendar() {
return <Calendar className="border-d-border rounded-md border" ISOWeek weekStartsOn={1} />;
}
export function FixedWeeksCalendar() {
return <Calendar className="border-d-border rounded-md border" fixedWeeks showOutsideDays />;
}
export function MultiMonthCalendar() {
return <Calendar className="border-d-border rounded-md border" numberOfMonths={2} showOutsideDays />;
}
```
---
## Notes
- **Customization**: Use `classNames` and `components` to override internal parts.
- **Buttons**: `buttonVariant` controls navigation buttons’ appearance.
- **Range**: Range selection highlights start, middle, and end days with rounded edges.