first commit
This commit is contained in:
105
docs/ui/react/react-ui/src/components/calendar/calendar.md
Normal file
105
docs/ui/react/react-ui/src/components/calendar/calendar.md
Normal file
@@ -0,0 +1,105 @@
|
||||
# Calendar
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs --> - calendar.test-fixtures — Wave-3h local test fixture…
|
||||
- [calendar.test-fixtures](./calendar.test-fixtures.md) — Wave-3h local test fixture that augments the chassis test i18n instance with the `react-ui.calendar.*` keyset. The chas…
|
||||
- [calendar.variants](./calendar.variants.md) — `calendarVariants` is the cva config that powers the outer wrapper of `<Calendar>`. The recipe is intentionally minimal…
|
||||
- calendar.test-fixtures — Wave-3h local test fixture…
|
||||
|
||||
- [calendar.test-fixtures](./calendar.test-fixtures.md) — Wave-3h local test fixture that augments the chassis test i18n instance with the `react-ui.calendar.*` keyset. The chas…
|
||||
- [calendar.variants](./calendar.variants.md) — `calendarVariants` is the cva config that powers the outer wrapper of `<Calendar>`. The recipe is intentionally minimal…
|
||||
|
||||
- calendar.test-fixtures — Wave-3h local test fixture…
|
||||
|
||||
- [calendar.test-fixtures](./calendar.test-fixtures.md) — Wave-3h local test fixture that augments the chassis test i18n instance with the `react-ui.calendar.*` keyset. The chas…
|
||||
- [calendar.variants](./calendar.variants.md) — `calendarVariants` is the cva config that powers the outer wrapper of `<Calendar>`. The recipe is intentionally minimal…
|
||||
|
||||
- calendar.test-fixtures — Wave-3h local test fixture…
|
||||
|
||||
- [calendar.test-fixtures](./calendar.test-fixtures.md) — Wave-3h local test fixture that augments the chassis test i18n instance with the `react-ui.calendar.*` keyset. The chas…
|
||||
- [calendar.variants](./calendar.variants.md) — `calendarVariants` is the cva config that powers the outer wrapper of `<Calendar>`. The recipe is intentionally minimal…
|
||||
- [calendar.test-fixtures](./calendar.test-fixtures.md) — Wave-3h local test fixture that augments the chassis test i18n instance with the `react-ui.calendar.*` keyset. The chas…
|
||||
- [calendar.variants](./calendar.variants.md) — `calendarVariants` is the cva config that powers the outer wrapper of `<Calendar>`. The recipe is intentionally minimal…
|
||||
|
||||
## Purpose
|
||||
|
||||
`<Calendar>` is the chassis date-grid primitive — a thin wrapper over `react-day-picker` (v9) that adds the chassis cva recipe, theme-aware lucide chevrons for previous/next-month navigation, locale-driven `aria-label` overrides, and a labelled outer wrapper. The chassis derives the active locale from `useTranslation()` so date formatting and accessible labels stay in lock-step with the rest of the app surface.
|
||||
|
||||
The chassis exposes the upstream surface verbatim through `Omit<DayPickerProps, "className" | "locale">` — every supported `mode` (`single`, `multiple`, `range`), the `selected` / `onSelect` controlled API, `numberOfMonths`, `showOutsideDays`, `weekStartsOn`, `disabled`, `fromMonth`/`toMonth`, the `modifiers` system, and the rest of the upstream API documented at <https://daypicker.dev>. Two upstream props are intercepted: `className` (so it merges with the chassis recipe via `cn()`) and `locale` (so the chassis can drive it from `useI18n()` rather than the consumer wiring it manually). For the rare case where a single calendar must diverge from the active app locale, pass a `localeOverride` (a `Partial<DayPickerLocale>` per the upstream API).
|
||||
|
||||
## Features
|
||||
|
||||
- Wraps `react-day-picker` v9 with zero additional state — fully controlled or uncontrolled per the upstream API.
|
||||
- Three modes — `single` / `multiple` / `range` — selected via the upstream `mode` prop.
|
||||
- Locale-aware: the chassis reads the active locale from `useTranslation()` so the calendar stays in sync with the app surface.
|
||||
- `aria-label` on the outer wrapper resolves through the active i18n via `labelKey` (defaults to `react-ui.calendar.label`).
|
||||
- Previous / next month navigation buttons get translated `aria-label`s via `previousMonthKey` / `nextMonthKey`.
|
||||
- Lucide-iconography for navigation chevrons (`ChevronLeftIcon` / `ChevronRightIcon`) wired into `react-day-picker`'s `components.Chevron` slot.
|
||||
- Forwards refs to the outer wrapper `<div>`.
|
||||
- All other upstream props pass through unchanged.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```tsx
|
||||
import { Calendar } from "@suaveplan/react-ui";
|
||||
import { useState } from "react";
|
||||
|
||||
export function ScheduleCalendar() {
|
||||
const [date, setDate] = useState<Date | undefined>(new Date());
|
||||
return <Calendar mode="single" selected={date} onSelect={setDate} />;
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```tsx
|
||||
import { Calendar } from "@suaveplan/react-ui";
|
||||
import type { DateRange } from "react-day-picker";
|
||||
import { useState } from "react";
|
||||
|
||||
export function BookingCalendar() {
|
||||
const [range, setRange] = useState<DateRange | undefined>();
|
||||
const today = new Date();
|
||||
return (
|
||||
<Calendar
|
||||
mode="range"
|
||||
selected={range}
|
||||
onSelect={setRange}
|
||||
numberOfMonths={2}
|
||||
showOutsideDays
|
||||
disabled={{ before: today }}
|
||||
weekStartsOn={1}
|
||||
previousMonthKey="react-ui.calendar.previousMonth"
|
||||
nextMonthKey="react-ui.calendar.nextMonth"
|
||||
/>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `<Calendar>`
|
||||
|
||||
`forwardRef<HTMLDivElement, CalendarProps>` — renders an outer wrapper `<div role="group" aria-label={…}>` containing the `<DayPicker>` instance.
|
||||
|
||||
#### `CalendarProps`
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
|---|---|---|---|
|
||||
| `mode` | `"single" \| "multiple" \| "range"` | `undefined` | Selection mode — drives the `selected` / `onSelect` shape per the upstream API. |
|
||||
| `labelKey` | `TranslationKey` | `"react-ui.calendar.label"` | `aria-label` for the outer wrapper. |
|
||||
| `previousMonthKey` | `TranslationKey` | `"react-ui.calendar.previousMonth"` | `aria-label` for the previous-month navigation button. |
|
||||
| `nextMonthKey` | `TranslationKey` | `"react-ui.calendar.nextMonth"` | `aria-label` for the next-month navigation button. |
|
||||
| `localeOverride` | `Partial<DayPickerLocale>` | `undefined` | Override the date-fns locale for this calendar instance. When unset, `react-day-picker` falls back to its bundled `enUS`. |
|
||||
| _every other_ `DayPickerProps` field | _upstream_ | _upstream_ | Forwarded as-is. See <https://daypicker.dev>. |
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- The chassis intentionally does NOT expose the upstream `locale` prop directly — `localeOverride` is a renamed escape hatch that documents the chassis's intent to drive locale from `useTranslation()` by default.
|
||||
- `react-day-picker` ships its own classnames for the grid, day buttons, and navigation chrome via its internal `classNames` map. The chassis only scopes the OUTER container — overriding the inner classnames belongs in a theme variant override.
|
||||
- Keyboard navigation (arrow keys, Home/End, Enter/Space, PageUp/Down) is supplied entirely by `react-day-picker` — the chassis does not wrap or intercept it.
|
||||
- The chevron icons are passed via `components.Chevron` rather than `classNames` so the chassis can swap them for theme-provided lucide / radix icons in a future Wave 5d theme-icon-pack pass.
|
||||
- `react-day-picker` renders its day grid as either a `<table>` (default) or a `[role="grid"]` element depending on the upstream version — the chassis does not assume one or the other in tests, hitting both via the `grid` selector.
|
||||
- When migrating from a previous `<Calendar>` consumer (e.g. an upstream shadcn block), the only required change is to drop the `locale` prop — the chassis derives it automatically.
|
||||
- Per the brief reconciliation note: the chassis casts the unreachable `?? "default"` fallback for `(i18n as { readonly locale: string }).locale` is NOT needed here because the locale is read indirectly via `useTranslation()` rather than from `i18n.locale`.
|
||||
Reference in New Issue
Block a user