first commit
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
# calendar-grid
|
||||
|
||||
## Purpose
|
||||
|
||||
`calendar-grid` provides `getCalendarMonth`, which builds a full calendar month grid for use in UI calendar components and scheduling displays. It returns a `CalendarMonth` value containing one `CalendarDay` entry per day in the month, each annotated with its day-of-week index, whether it is a weekend, and whether it represents today (driven by an injectable `Clock`).
|
||||
|
||||
The module is intentionally narrow: it answers "what are the days in this month and which one is today?" — layout concerns (week rows, leading/trailing days from adjacent months) are left to the consumer.
|
||||
|
||||
## Features
|
||||
|
||||
- `getCalendarMonth` — builds a `CalendarMonth` grid for a given year and 1-indexed month
|
||||
- Each `CalendarDay` includes `date`, `dayOfWeek` (0=Sun … 6=Sat), `isWeekend`, and `isToday`
|
||||
- Injectable `Clock` for deterministic rendering in tests and server-side snapshots
|
||||
- Zero side effects; all computation is local
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { getCalendarMonth } from "@suaveplan/datetime";
|
||||
|
||||
const march = getCalendarMonth(2024, 3);
|
||||
console.log(march.days.length); // 31
|
||||
console.log(march.days[0]?.dayOfWeek); // 5 (Friday — Mar 1 2024)
|
||||
const weekends = march.days.filter((d) => d.isWeekend);
|
||||
console.log(weekends.length); // 10
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { getCalendarMonth } from "@suaveplan/datetime";
|
||||
|
||||
// Deterministic "today" for SSR or snapshot tests
|
||||
const fakeClock = () => new Date(2024, 2, 15).getTime(); // Mar 15 2024
|
||||
const march = getCalendarMonth(2024, 3, { clock: fakeClock });
|
||||
|
||||
const today = march.days.find((d) => d.isToday);
|
||||
console.log(today?.date.getDate()); // 15
|
||||
|
||||
// Render a simple ASCII calendar header
|
||||
for (const day of march.days) {
|
||||
const marker = day.isToday ? "*" : day.isWeekend ? "W" : " ";
|
||||
process.stdout.write(`${marker}${String(day.date.getDate()).padStart(2)} `);
|
||||
if (day.dayOfWeek === 6) process.stdout.write("\n");
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `CalendarMonthOptions`
|
||||
|
||||
```ts
|
||||
interface CalendarMonthOptions {
|
||||
clock?: Clock;
|
||||
}
|
||||
```
|
||||
|
||||
- `clock` — injectable `Clock` (returns epoch ms). Defaults to `Date.now`.
|
||||
|
||||
### `getCalendarMonth(year: number, month: number, opts?: CalendarMonthOptions): CalendarMonth`
|
||||
|
||||
Build a `CalendarMonth` for the given `year` and 1-indexed `month`.
|
||||
|
||||
**Params:**
|
||||
|
||||
- `year` — full calendar year (e.g. 2024)
|
||||
- `month` — 1-indexed month (1 = January, 12 = December)
|
||||
- `opts.clock` — optional injectable clock
|
||||
|
||||
**Returns:** `{ year, month, days: CalendarDay[] }` where each `CalendarDay` is:
|
||||
|
||||
```ts
|
||||
{ date: Date; dayOfWeek: Weekday; isWeekend: boolean; isToday: boolean }
|
||||
```
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
`isToday` is computed by comparing a `"year-month-date"` string derived from `clock()` to the same string for each grid day. This string comparison avoids UTC/local timezone confusion that would arise from comparing epoch timestamps directly. The `clock` default (`Date.now`) is captured once per call to ensure consistent "today" across all days in the grid.
|
||||
Reference in New Issue
Block a user