@super-calendar/core 2.0.0 → 2.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,56 @@
1
+ # @super-calendar/core
2
+
3
+ [![JSR](https://jsr.io/badges/@super-calendar/core)](https://jsr.io/@super-calendar/core) [![JSR score](https://jsr.io/badges/@super-calendar/core/score)](https://jsr.io/@super-calendar/core)
4
+
5
+ The render-agnostic core of [super-calendar](https://github.com/afonsojramos/react-native-super-calendar): date math, the selection model, event layout, the month-grid builder, the headless hooks, and the neutral theme tokens.
6
+
7
+ It imports nothing from React Native, react-dom, Reanimated, Gesture Handler, or Legend List, so it bundles into any renderer. Use it to drive your own UI, or pair it with [`@super-calendar/dom`](https://jsr.io/@super-calendar/dom) (react-dom) or [`@super-calendar/native`](https://jsr.io/@super-calendar/native) (React Native).
8
+
9
+ ## Install
10
+
11
+ ```sh
12
+ # Deno
13
+ deno add jsr:@super-calendar/core
14
+
15
+ # npm / pnpm / yarn / bun
16
+ npx jsr add @super-calendar/core
17
+ pnpm dlx jsr add @super-calendar/core
18
+ bunx jsr add @super-calendar/core
19
+ ```
20
+
21
+ Peer dependencies: `date-fns` (>=3) and `react` (>=19).
22
+
23
+ ## Usage
24
+
25
+ Build a fully custom month grid from the headless `useMonthGrid` hook. It returns the weeks, the weekday headers, and per-day state for you to render however you like.
26
+
27
+ ```tsx
28
+ import { useMonthGrid } from "@super-calendar/core";
29
+
30
+ function MyGrid({ month }: { month: Date }) {
31
+ const { weeks, weekdays } = useMonthGrid(month, { weekStartsOn: 1 });
32
+
33
+ return weeks.map((week) =>
34
+ week.days.map((day) => (
35
+ // day carries isToday / isSelected / isInRange / isDisabled / isCurrentMonth
36
+ <DayCell key={day.date.toISOString()} day={day} />
37
+ )),
38
+ );
39
+ }
40
+ ```
41
+
42
+ Manage single, multiple, or range selection with `useDateRange`:
43
+
44
+ ```ts
45
+ import { useDateRange } from "@super-calendar/core";
46
+
47
+ const range = useDateRange({ mode: "range" });
48
+ ```
49
+
50
+ ## Documentation
51
+
52
+ See the [full documentation](https://super-calendar.afonsojramos.me) and the [API reference](https://super-calendar.afonsojramos.me/reference/api).
53
+
54
+ ## License
55
+
56
+ MIT
package/dist/index.d.mts CHANGED
@@ -1,6 +1,8 @@
1
1
  import { Locale } from "date-fns";
2
+ import { Dispatch, SetStateAction } from "react";
2
3
 
3
4
  //#region src/types.d.ts
5
+ /** The view the calendar renders: a day-column grid (`day`, `3days`, `week`, `custom`), the `month` grid, or the `schedule` list. */
4
6
  type CalendarMode = "day" | "3days" | "week" | "custom" | "month" | "schedule";
5
7
  /** The time-grid modes (day-column views, excluding month and schedule). */
6
8
  type TimeGridMode = Exclude<CalendarMode, "month" | "schedule">;
@@ -11,8 +13,11 @@ type TimeGridMode = Exclude<CalendarMode, "month" | "schedule">;
11
13
  * threaded through untouched via the `T` generic.
12
14
  */
13
15
  interface ICalendarEvent {
16
+ /** When the event begins. */
14
17
  start: Date;
18
+ /** When the event ends. */
15
19
  end: Date;
20
+ /** Display label, shown by the built-in default renderer. */
16
21
  title?: string;
17
22
  /**
18
23
  * Force this event into the all-day lane (above the time grid) instead of the
@@ -33,6 +38,7 @@ interface ICalendarEvent {
33
38
  type RecurrenceFrequency = "daily" | "weekly" | "monthly" | "yearly";
34
39
  /** A simple, RRULE-inspired repeat rule expanded by `expandRecurringEvents`. */
35
40
  interface RecurrenceRule {
41
+ /** How often the event repeats. */
36
42
  freq: RecurrenceFrequency;
37
43
  /** Repeat every N periods. Default 1. */
38
44
  interval?: number;
@@ -68,6 +74,7 @@ type BusinessHours = (date: Date) => {
68
74
  } | null;
69
75
  //#endregion
70
76
  //#region src/tokens.d.ts
77
+ /** The shared colour palette both renderers derive their themes from. */
71
78
  interface CalendarColors {
72
79
  /** Hour lines, day separators and month-cell borders. */
73
80
  gridLine: string;
@@ -100,7 +107,9 @@ interface CalendarColors {
100
107
  /** Default event chip text. */
101
108
  eventText: string;
102
109
  }
110
+ /** The default light-theme colour palette. */
103
111
  declare const lightColors: CalendarColors;
112
+ /** The default dark-theme colour palette. */
104
113
  declare const darkColors: CalendarColors;
105
114
  //#endregion
106
115
  //#region src/presentation.d.ts
@@ -130,7 +139,9 @@ declare function dayBadgeKind(day: {
130
139
  //#region src/utils/dateRange.d.ts
131
140
  /** A selected span. `end` is `null` while only the first endpoint has been picked. */
132
141
  interface DateRange {
142
+ /** The first endpoint. */
133
143
  start: Date;
144
+ /** The second endpoint, or `null` while only the first has been picked. */
134
145
  end: Date | null;
135
146
  }
136
147
  /** Limits applied before a date can be selected. */
@@ -166,7 +177,9 @@ interface DaySelectionState {
166
177
  isSelected: boolean;
167
178
  /** Inside a complete range, endpoints included (and not disabled). */
168
179
  isInRange: boolean;
180
+ /** The range's start endpoint (and not disabled). */
169
181
  isRangeStart: boolean;
182
+ /** The range's end endpoint (and not disabled). */
170
183
  isRangeEnd: boolean;
171
184
  }
172
185
  /**
@@ -184,7 +197,9 @@ declare function daySelectionState(date: Date, selection: {
184
197
  * cached/virtualized day cells still repaint when any of it changes.
185
198
  */
186
199
  interface CalendarSelection extends DateSelectionConstraints {
200
+ /** Selected discrete days (single or multiple). */
187
201
  selectedDates?: Date[];
202
+ /** Selected span. */
188
203
  selectedRange?: DateRange;
189
204
  }
190
205
  /**
@@ -193,12 +208,26 @@ interface CalendarSelection extends DateSelectionConstraints {
193
208
  * the virtualized list has cached (and so won't re-render) their page.
194
209
  */
195
210
  declare const CalendarSelectionProvider: import("react").Provider<CalendarSelection>;
211
+ /** Reads the active selection provided by {@link CalendarSelectionProvider}. */
196
212
  declare const useCalendarSelection: () => CalendarSelection;
197
213
  /** Options for {@link useDateRange}. */
198
214
  interface UseDateRangeOptions extends DateSelectionConstraints {
199
215
  /** Pre-select a range on mount. */
200
216
  initialRange?: DateRange | null;
201
217
  }
218
+ /** The state and handlers returned by {@link useDateRange}. */
219
+ interface UseDateRangeResult {
220
+ /** The current selection; `null` until the first endpoint is picked. */
221
+ range: DateRange | null;
222
+ /** Wire to `onPressDay`: advances the range (start, then end, then restarts). */
223
+ onPressDate: (date: Date) => void;
224
+ /** Set both endpoints at once (ordered); ignored if either isn't selectable. */
225
+ selectRange: (a: Date, b: Date) => void;
226
+ /** Clear the selection. */
227
+ reset: () => void;
228
+ /** The raw state setter, for full control. */
229
+ setRange: Dispatch<SetStateAction<DateRange | null>>;
230
+ }
202
231
  /**
203
232
  * Controlled-ish range selection state for the month view. Returns the current
204
233
  * `range` plus an `onPressDate` handler to wire to `Calendar`'s `onPressDay`, a
@@ -209,13 +238,7 @@ interface UseDateRangeOptions extends DateSelectionConstraints {
209
238
  * <Calendar mode="month" selectedRange={range ?? undefined} onPressDay={onPressDate} … />
210
239
  * ```
211
240
  */
212
- declare function useDateRange(options?: UseDateRangeOptions): {
213
- range: DateRange | null;
214
- onPressDate: (date: Date) => void;
215
- selectRange: (a: Date, b: Date) => void;
216
- reset: () => void;
217
- setRange: import("react").Dispatch<import("react").SetStateAction<DateRange | null>>;
218
- };
241
+ declare function useDateRange(options?: UseDateRangeOptions): UseDateRangeResult;
219
242
  //#endregion
220
243
  //#region src/utils/dates.d.ts
221
244
  /** The seven dates of the week containing `date`, starting on `weekStartsOn`. */
@@ -247,8 +270,11 @@ declare const buildMonthWeeks: (month: Date, weekStartsOn: WeekStartsOn, {
247
270
  showSixWeeks?: boolean;
248
271
  isRTL?: boolean;
249
272
  }) => Date[][];
273
+ /** True when `date` is a Saturday or Sunday. */
250
274
  declare const isWeekend: (date: Date) => boolean;
275
+ /** True when `date` falls on the current calendar day. */
251
276
  declare const getIsToday: (date: Date) => boolean;
277
+ /** True when `a` and `b` are the same calendar day (ignoring the time of day). */
252
278
  declare const isSameCalendarDay: (a: Date, b: Date) => boolean;
253
279
  /** Minutes elapsed since midnight (0–1439). */
254
280
  declare const minutesIntoDay: (date: Date) => number;
@@ -393,8 +419,9 @@ declare function monthEventCapacity(availableHeightPx: number, chipRowHeightPx:
393
419
  declare function monthVisibleCount(total: number, capacity: MonthEventCapacity): number;
394
420
  //#endregion
395
421
  //#region src/utils/layout.d.ts
422
+ /** An event placed on a single day's time grid by {@link layoutDayEvents}, with its vertical span and overlap column. */
396
423
  type PositionedEvent<T> = {
397
- event: CalendarEvent<T>; /** Hours from midnight to the event's segment start on this day (fractional). */
424
+ /** The source event for this segment. */event: CalendarEvent<T>; /** Hours from midnight to the event's segment start on this day (fractional). */
398
425
  startHours: number; /** Segment duration in hours on this day (clamped to a small minimum). */
399
426
  durationHours: number; /** Zero-based column index within its overlap cluster. */
400
427
  column: number; /** Total columns in this event's overlap cluster. */
@@ -450,35 +477,51 @@ declare function closedHourBands(day: Date, businessHours: BusinessHours | undef
450
477
  //#region src/utils/monthGrid.d.ts
451
478
  /** A single day in the grid, with all the state a custom cell needs to render. */
452
479
  interface MonthGridDay {
480
+ /** The day this cell represents. */
453
481
  date: Date;
454
482
  /** Stable `yyyy-MM-dd` id, handy as a React key. */
455
483
  id: string;
456
484
  /** Day-of-month, e.g. "1". */
457
485
  label: string;
486
+ /** False for days bleeding in from the previous or next month. */
458
487
  isCurrentMonth: boolean;
488
+ /** The day is today. */
459
489
  isToday: boolean;
490
+ /** The day is a Saturday or Sunday. */
460
491
  isWeekend: boolean;
492
+ /** The day fails the min/max/disabled constraints. */
461
493
  isDisabled: boolean;
494
+ /** The day is a `selectedDates` day or a range endpoint (and not disabled). */
462
495
  isSelected: boolean;
496
+ /** The day is the range's start endpoint. */
463
497
  isRangeStart: boolean;
498
+ /** The day is the range's end endpoint. */
464
499
  isRangeEnd: boolean;
465
500
  /** Inside a complete range (endpoints included). */
466
501
  isInRange: boolean;
467
502
  }
468
503
  /** One week row. */
469
504
  interface MonthGridWeek {
505
+ /** Stable id for the week row, handy as a React key. */
470
506
  id: string;
507
+ /** The seven days of the row, in display order. */
471
508
  days: MonthGridDay[];
472
509
  }
473
510
  /** A weekday header cell (e.g. "Mon"). */
474
511
  interface MonthGridWeekday {
512
+ /** A representative date for the column, used to derive the label. */
475
513
  date: Date;
514
+ /** The short weekday name (e.g. "Mon"), localised via `locale`. */
476
515
  label: string;
477
516
  }
517
+ /** The full grid for one month: the week rows and the weekday header cells. */
478
518
  interface MonthGrid {
519
+ /** The week rows, padded to whole weeks. */
479
520
  weeks: MonthGridWeek[];
521
+ /** The weekday header cells, in display order. */
480
522
  weekdays: MonthGridWeekday[];
481
523
  }
524
+ /** Options for {@link buildMonthGrid} and {@link useMonthGrid}. */
482
525
  interface UseMonthGridOptions extends DateSelectionConstraints {
483
526
  /** First day of the week. Sunday = 0 (default) … Saturday = 6. */
484
527
  weekStartsOn?: WeekStartsOn;
@@ -539,4 +582,4 @@ declare function toZonedTime(date: Date, timeZone: string): Date;
539
582
  */
540
583
  declare function eventsInTimeZone<T>(events: CalendarEvent<T>[], timeZone: string): CalendarEvent<T>[];
541
584
  //#endregion
542
- export { BusinessHours, CalendarColors, CalendarEvent, CalendarMode, CalendarSelection, CalendarSelectionProvider, DateRange, DateSelectionConstraints, DayBadgeKind, DaySelectionState, EventChipLayout, EventKeyExtractor, ICalendarEvent, MIN_BOX_HEIGHT_FOR_TIME, MonthEventCapacity, MonthGrid, MonthGridDay, MonthGridWeek, MonthGridWeekday, PositionedEvent, RangeBandKind, RecurrenceFrequency, RecurrenceRule, TimeGridMode, UseDateRangeOptions, UseMonthGridOptions, WeekStartsOn, bandRounding, buildMonthGrid, buildMonthWeeks, cellRangeFromDrag, closedHourBands, compareDayEvents, darkColors, dayBadgeKind, daySelectionState, eventAccessibilityLabel, eventChipLayout, eventDayKeys, eventTimeLabel, eventsInTimeZone, expandRecurringEvents, formatHour, getIsToday, getViewDays, getWeekDays, groupEventsByDay, isAllDayEvent, isDateSelectable, isRangeEndpoint, isSameCalendarDay, isTimeVisibleAtHeight, isWeekend, isWithinDateRange, layoutDayEvents, lightColors, minutesIntoDay, monthEventCapacity, monthVisibleCount, nextDateRange, rangeBandKind, resolveDraggedBounds, shiftMinutes, snapDeltaMinutes, titleEllipsizeMode, titleNumberOfLines, toZonedTime, useCalendarSelection, useDateRange, useMonthGrid, viewDayCount, weekDaysCount };
585
+ export { BusinessHours, CalendarColors, CalendarEvent, CalendarMode, CalendarSelection, CalendarSelectionProvider, DateRange, DateSelectionConstraints, DayBadgeKind, DaySelectionState, EventChipLayout, EventKeyExtractor, ICalendarEvent, MIN_BOX_HEIGHT_FOR_TIME, MonthEventCapacity, MonthGrid, MonthGridDay, MonthGridWeek, MonthGridWeekday, PositionedEvent, RangeBandKind, RecurrenceFrequency, RecurrenceRule, TimeGridMode, UseDateRangeOptions, UseDateRangeResult, UseMonthGridOptions, WeekStartsOn, bandRounding, buildMonthGrid, buildMonthWeeks, cellRangeFromDrag, closedHourBands, compareDayEvents, darkColors, dayBadgeKind, daySelectionState, eventAccessibilityLabel, eventChipLayout, eventDayKeys, eventTimeLabel, eventsInTimeZone, expandRecurringEvents, formatHour, getIsToday, getViewDays, getWeekDays, groupEventsByDay, isAllDayEvent, isDateSelectable, isRangeEndpoint, isSameCalendarDay, isTimeVisibleAtHeight, isWeekend, isWithinDateRange, layoutDayEvents, lightColors, minutesIntoDay, monthEventCapacity, monthVisibleCount, nextDateRange, rangeBandKind, resolveDraggedBounds, shiftMinutes, snapDeltaMinutes, titleEllipsizeMode, titleNumberOfLines, toZonedTime, useCalendarSelection, useDateRange, useMonthGrid, viewDayCount, weekDaysCount };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
+ import { Dispatch, SetStateAction } from "react";
1
2
  import { Locale } from "date-fns";
2
3
 
3
4
  //#region src/types.d.ts
5
+ /** The view the calendar renders: a day-column grid (`day`, `3days`, `week`, `custom`), the `month` grid, or the `schedule` list. */
4
6
  type CalendarMode = "day" | "3days" | "week" | "custom" | "month" | "schedule";
5
7
  /** The time-grid modes (day-column views, excluding month and schedule). */
6
8
  type TimeGridMode = Exclude<CalendarMode, "month" | "schedule">;
@@ -11,8 +13,11 @@ type TimeGridMode = Exclude<CalendarMode, "month" | "schedule">;
11
13
  * threaded through untouched via the `T` generic.
12
14
  */
13
15
  interface ICalendarEvent {
16
+ /** When the event begins. */
14
17
  start: Date;
18
+ /** When the event ends. */
15
19
  end: Date;
20
+ /** Display label, shown by the built-in default renderer. */
16
21
  title?: string;
17
22
  /**
18
23
  * Force this event into the all-day lane (above the time grid) instead of the
@@ -33,6 +38,7 @@ interface ICalendarEvent {
33
38
  type RecurrenceFrequency = "daily" | "weekly" | "monthly" | "yearly";
34
39
  /** A simple, RRULE-inspired repeat rule expanded by `expandRecurringEvents`. */
35
40
  interface RecurrenceRule {
41
+ /** How often the event repeats. */
36
42
  freq: RecurrenceFrequency;
37
43
  /** Repeat every N periods. Default 1. */
38
44
  interval?: number;
@@ -68,6 +74,7 @@ type BusinessHours = (date: Date) => {
68
74
  } | null;
69
75
  //#endregion
70
76
  //#region src/tokens.d.ts
77
+ /** The shared colour palette both renderers derive their themes from. */
71
78
  interface CalendarColors {
72
79
  /** Hour lines, day separators and month-cell borders. */
73
80
  gridLine: string;
@@ -100,7 +107,9 @@ interface CalendarColors {
100
107
  /** Default event chip text. */
101
108
  eventText: string;
102
109
  }
110
+ /** The default light-theme colour palette. */
103
111
  declare const lightColors: CalendarColors;
112
+ /** The default dark-theme colour palette. */
104
113
  declare const darkColors: CalendarColors;
105
114
  //#endregion
106
115
  //#region src/presentation.d.ts
@@ -130,7 +139,9 @@ declare function dayBadgeKind(day: {
130
139
  //#region src/utils/dateRange.d.ts
131
140
  /** A selected span. `end` is `null` while only the first endpoint has been picked. */
132
141
  interface DateRange {
142
+ /** The first endpoint. */
133
143
  start: Date;
144
+ /** The second endpoint, or `null` while only the first has been picked. */
134
145
  end: Date | null;
135
146
  }
136
147
  /** Limits applied before a date can be selected. */
@@ -166,7 +177,9 @@ interface DaySelectionState {
166
177
  isSelected: boolean;
167
178
  /** Inside a complete range, endpoints included (and not disabled). */
168
179
  isInRange: boolean;
180
+ /** The range's start endpoint (and not disabled). */
169
181
  isRangeStart: boolean;
182
+ /** The range's end endpoint (and not disabled). */
170
183
  isRangeEnd: boolean;
171
184
  }
172
185
  /**
@@ -184,7 +197,9 @@ declare function daySelectionState(date: Date, selection: {
184
197
  * cached/virtualized day cells still repaint when any of it changes.
185
198
  */
186
199
  interface CalendarSelection extends DateSelectionConstraints {
200
+ /** Selected discrete days (single or multiple). */
187
201
  selectedDates?: Date[];
202
+ /** Selected span. */
188
203
  selectedRange?: DateRange;
189
204
  }
190
205
  /**
@@ -193,12 +208,26 @@ interface CalendarSelection extends DateSelectionConstraints {
193
208
  * the virtualized list has cached (and so won't re-render) their page.
194
209
  */
195
210
  declare const CalendarSelectionProvider: import("react").Provider<CalendarSelection>;
211
+ /** Reads the active selection provided by {@link CalendarSelectionProvider}. */
196
212
  declare const useCalendarSelection: () => CalendarSelection;
197
213
  /** Options for {@link useDateRange}. */
198
214
  interface UseDateRangeOptions extends DateSelectionConstraints {
199
215
  /** Pre-select a range on mount. */
200
216
  initialRange?: DateRange | null;
201
217
  }
218
+ /** The state and handlers returned by {@link useDateRange}. */
219
+ interface UseDateRangeResult {
220
+ /** The current selection; `null` until the first endpoint is picked. */
221
+ range: DateRange | null;
222
+ /** Wire to `onPressDay`: advances the range (start, then end, then restarts). */
223
+ onPressDate: (date: Date) => void;
224
+ /** Set both endpoints at once (ordered); ignored if either isn't selectable. */
225
+ selectRange: (a: Date, b: Date) => void;
226
+ /** Clear the selection. */
227
+ reset: () => void;
228
+ /** The raw state setter, for full control. */
229
+ setRange: Dispatch<SetStateAction<DateRange | null>>;
230
+ }
202
231
  /**
203
232
  * Controlled-ish range selection state for the month view. Returns the current
204
233
  * `range` plus an `onPressDate` handler to wire to `Calendar`'s `onPressDay`, a
@@ -209,13 +238,7 @@ interface UseDateRangeOptions extends DateSelectionConstraints {
209
238
  * <Calendar mode="month" selectedRange={range ?? undefined} onPressDay={onPressDate} … />
210
239
  * ```
211
240
  */
212
- declare function useDateRange(options?: UseDateRangeOptions): {
213
- range: DateRange | null;
214
- onPressDate: (date: Date) => void;
215
- selectRange: (a: Date, b: Date) => void;
216
- reset: () => void;
217
- setRange: import("react").Dispatch<import("react").SetStateAction<DateRange | null>>;
218
- };
241
+ declare function useDateRange(options?: UseDateRangeOptions): UseDateRangeResult;
219
242
  //#endregion
220
243
  //#region src/utils/dates.d.ts
221
244
  /** The seven dates of the week containing `date`, starting on `weekStartsOn`. */
@@ -247,8 +270,11 @@ declare const buildMonthWeeks: (month: Date, weekStartsOn: WeekStartsOn, {
247
270
  showSixWeeks?: boolean;
248
271
  isRTL?: boolean;
249
272
  }) => Date[][];
273
+ /** True when `date` is a Saturday or Sunday. */
250
274
  declare const isWeekend: (date: Date) => boolean;
275
+ /** True when `date` falls on the current calendar day. */
251
276
  declare const getIsToday: (date: Date) => boolean;
277
+ /** True when `a` and `b` are the same calendar day (ignoring the time of day). */
252
278
  declare const isSameCalendarDay: (a: Date, b: Date) => boolean;
253
279
  /** Minutes elapsed since midnight (0–1439). */
254
280
  declare const minutesIntoDay: (date: Date) => number;
@@ -393,8 +419,9 @@ declare function monthEventCapacity(availableHeightPx: number, chipRowHeightPx:
393
419
  declare function monthVisibleCount(total: number, capacity: MonthEventCapacity): number;
394
420
  //#endregion
395
421
  //#region src/utils/layout.d.ts
422
+ /** An event placed on a single day's time grid by {@link layoutDayEvents}, with its vertical span and overlap column. */
396
423
  type PositionedEvent<T> = {
397
- event: CalendarEvent<T>; /** Hours from midnight to the event's segment start on this day (fractional). */
424
+ /** The source event for this segment. */event: CalendarEvent<T>; /** Hours from midnight to the event's segment start on this day (fractional). */
398
425
  startHours: number; /** Segment duration in hours on this day (clamped to a small minimum). */
399
426
  durationHours: number; /** Zero-based column index within its overlap cluster. */
400
427
  column: number; /** Total columns in this event's overlap cluster. */
@@ -450,35 +477,51 @@ declare function closedHourBands(day: Date, businessHours: BusinessHours | undef
450
477
  //#region src/utils/monthGrid.d.ts
451
478
  /** A single day in the grid, with all the state a custom cell needs to render. */
452
479
  interface MonthGridDay {
480
+ /** The day this cell represents. */
453
481
  date: Date;
454
482
  /** Stable `yyyy-MM-dd` id, handy as a React key. */
455
483
  id: string;
456
484
  /** Day-of-month, e.g. "1". */
457
485
  label: string;
486
+ /** False for days bleeding in from the previous or next month. */
458
487
  isCurrentMonth: boolean;
488
+ /** The day is today. */
459
489
  isToday: boolean;
490
+ /** The day is a Saturday or Sunday. */
460
491
  isWeekend: boolean;
492
+ /** The day fails the min/max/disabled constraints. */
461
493
  isDisabled: boolean;
494
+ /** The day is a `selectedDates` day or a range endpoint (and not disabled). */
462
495
  isSelected: boolean;
496
+ /** The day is the range's start endpoint. */
463
497
  isRangeStart: boolean;
498
+ /** The day is the range's end endpoint. */
464
499
  isRangeEnd: boolean;
465
500
  /** Inside a complete range (endpoints included). */
466
501
  isInRange: boolean;
467
502
  }
468
503
  /** One week row. */
469
504
  interface MonthGridWeek {
505
+ /** Stable id for the week row, handy as a React key. */
470
506
  id: string;
507
+ /** The seven days of the row, in display order. */
471
508
  days: MonthGridDay[];
472
509
  }
473
510
  /** A weekday header cell (e.g. "Mon"). */
474
511
  interface MonthGridWeekday {
512
+ /** A representative date for the column, used to derive the label. */
475
513
  date: Date;
514
+ /** The short weekday name (e.g. "Mon"), localised via `locale`. */
476
515
  label: string;
477
516
  }
517
+ /** The full grid for one month: the week rows and the weekday header cells. */
478
518
  interface MonthGrid {
519
+ /** The week rows, padded to whole weeks. */
479
520
  weeks: MonthGridWeek[];
521
+ /** The weekday header cells, in display order. */
480
522
  weekdays: MonthGridWeekday[];
481
523
  }
524
+ /** Options for {@link buildMonthGrid} and {@link useMonthGrid}. */
482
525
  interface UseMonthGridOptions extends DateSelectionConstraints {
483
526
  /** First day of the week. Sunday = 0 (default) … Saturday = 6. */
484
527
  weekStartsOn?: WeekStartsOn;
@@ -539,4 +582,4 @@ declare function toZonedTime(date: Date, timeZone: string): Date;
539
582
  */
540
583
  declare function eventsInTimeZone<T>(events: CalendarEvent<T>[], timeZone: string): CalendarEvent<T>[];
541
584
  //#endregion
542
- export { BusinessHours, CalendarColors, CalendarEvent, CalendarMode, CalendarSelection, CalendarSelectionProvider, DateRange, DateSelectionConstraints, DayBadgeKind, DaySelectionState, EventChipLayout, EventKeyExtractor, ICalendarEvent, MIN_BOX_HEIGHT_FOR_TIME, MonthEventCapacity, MonthGrid, MonthGridDay, MonthGridWeek, MonthGridWeekday, PositionedEvent, RangeBandKind, RecurrenceFrequency, RecurrenceRule, TimeGridMode, UseDateRangeOptions, UseMonthGridOptions, WeekStartsOn, bandRounding, buildMonthGrid, buildMonthWeeks, cellRangeFromDrag, closedHourBands, compareDayEvents, darkColors, dayBadgeKind, daySelectionState, eventAccessibilityLabel, eventChipLayout, eventDayKeys, eventTimeLabel, eventsInTimeZone, expandRecurringEvents, formatHour, getIsToday, getViewDays, getWeekDays, groupEventsByDay, isAllDayEvent, isDateSelectable, isRangeEndpoint, isSameCalendarDay, isTimeVisibleAtHeight, isWeekend, isWithinDateRange, layoutDayEvents, lightColors, minutesIntoDay, monthEventCapacity, monthVisibleCount, nextDateRange, rangeBandKind, resolveDraggedBounds, shiftMinutes, snapDeltaMinutes, titleEllipsizeMode, titleNumberOfLines, toZonedTime, useCalendarSelection, useDateRange, useMonthGrid, viewDayCount, weekDaysCount };
585
+ export { BusinessHours, CalendarColors, CalendarEvent, CalendarMode, CalendarSelection, CalendarSelectionProvider, DateRange, DateSelectionConstraints, DayBadgeKind, DaySelectionState, EventChipLayout, EventKeyExtractor, ICalendarEvent, MIN_BOX_HEIGHT_FOR_TIME, MonthEventCapacity, MonthGrid, MonthGridDay, MonthGridWeek, MonthGridWeekday, PositionedEvent, RangeBandKind, RecurrenceFrequency, RecurrenceRule, TimeGridMode, UseDateRangeOptions, UseDateRangeResult, UseMonthGridOptions, WeekStartsOn, bandRounding, buildMonthGrid, buildMonthWeeks, cellRangeFromDrag, closedHourBands, compareDayEvents, darkColors, dayBadgeKind, daySelectionState, eventAccessibilityLabel, eventChipLayout, eventDayKeys, eventTimeLabel, eventsInTimeZone, expandRecurringEvents, formatHour, getIsToday, getViewDays, getWeekDays, groupEventsByDay, isAllDayEvent, isDateSelectable, isRangeEndpoint, isSameCalendarDay, isTimeVisibleAtHeight, isWeekend, isWithinDateRange, layoutDayEvents, lightColors, minutesIntoDay, monthEventCapacity, monthVisibleCount, nextDateRange, rangeBandKind, resolveDraggedBounds, shiftMinutes, snapDeltaMinutes, titleEllipsizeMode, titleNumberOfLines, toZonedTime, useCalendarSelection, useDateRange, useMonthGrid, viewDayCount, weekDaysCount };
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  let date_fns = require("date-fns");
3
3
  let react = require("react");
4
4
  //#region src/tokens.ts
5
+ /** The default light-theme colour palette. */
5
6
  const lightColors = {
6
7
  gridLine: "#E2E4E9",
7
8
  weekendBackground: "#F6F7F9",
@@ -19,6 +20,7 @@ const lightColors = {
19
20
  eventBackground: "#DCE7FF",
20
21
  eventText: "#1A1B1E"
21
22
  };
23
+ /** The default dark-theme colour palette. */
22
24
  const darkColors = {
23
25
  gridLine: "#2A2E37",
24
26
  weekendBackground: "#15171C",
@@ -130,11 +132,14 @@ const buildMonthWeeks = (month, weekStartsOn, { showSixWeeks = false, isRTL = fa
130
132
  }
131
133
  return weeks;
132
134
  };
135
+ /** True when `date` is a Saturday or Sunday. */
133
136
  const isWeekend = (date) => {
134
137
  const day = date.getDay();
135
138
  return day === 0 || day === 6;
136
139
  };
140
+ /** True when `date` falls on the current calendar day. */
137
141
  const getIsToday = (date) => (0, date_fns.isToday)(date);
142
+ /** True when `a` and `b` are the same calendar day (ignoring the time of day). */
138
143
  const isSameCalendarDay = (a, b) => (0, date_fns.isSameDay)(a, b);
139
144
  /** Minutes elapsed since midnight (0–1439). */
140
145
  const minutesIntoDay = (date) => (0, date_fns.getHours)(date) * 60 + (0, date_fns.getMinutes)(date);
@@ -210,6 +215,7 @@ const CalendarSelectionContext = (0, react.createContext)({});
210
215
  * the virtualized list has cached (and so won't re-render) their page.
211
216
  */
212
217
  const CalendarSelectionProvider = CalendarSelectionContext.Provider;
218
+ /** Reads the active selection provided by {@link CalendarSelectionProvider}. */
213
219
  const useCalendarSelection = () => (0, react.useContext)(CalendarSelectionContext);
214
220
  /**
215
221
  * Controlled-ish range selection state for the month view. Returns the current
package/dist/index.mjs CHANGED
@@ -1,6 +1,7 @@
1
1
  import { addDays, addMonths, addWeeks, addYears, differenceInMinutes, eachDayOfInterval, endOfMonth, endOfWeek, format, getHours, getMinutes, isAfter, isBefore, isSameDay, isSameMonth, isToday, max, min, startOfDay, startOfMonth, startOfWeek } from "date-fns";
2
2
  import { createContext, useCallback, useContext, useMemo, useState } from "react";
3
3
  //#region src/tokens.ts
4
+ /** The default light-theme colour palette. */
4
5
  const lightColors = {
5
6
  gridLine: "#E2E4E9",
6
7
  weekendBackground: "#F6F7F9",
@@ -18,6 +19,7 @@ const lightColors = {
18
19
  eventBackground: "#DCE7FF",
19
20
  eventText: "#1A1B1E"
20
21
  };
22
+ /** The default dark-theme colour palette. */
21
23
  const darkColors = {
22
24
  gridLine: "#2A2E37",
23
25
  weekendBackground: "#15171C",
@@ -129,11 +131,14 @@ const buildMonthWeeks = (month, weekStartsOn, { showSixWeeks = false, isRTL = fa
129
131
  }
130
132
  return weeks;
131
133
  };
134
+ /** True when `date` is a Saturday or Sunday. */
132
135
  const isWeekend = (date) => {
133
136
  const day = date.getDay();
134
137
  return day === 0 || day === 6;
135
138
  };
139
+ /** True when `date` falls on the current calendar day. */
136
140
  const getIsToday = (date) => isToday(date);
141
+ /** True when `a` and `b` are the same calendar day (ignoring the time of day). */
137
142
  const isSameCalendarDay = (a, b) => isSameDay(a, b);
138
143
  /** Minutes elapsed since midnight (0–1439). */
139
144
  const minutesIntoDay = (date) => getHours(date) * 60 + getMinutes(date);
@@ -209,6 +214,7 @@ const CalendarSelectionContext = createContext({});
209
214
  * the virtualized list has cached (and so won't re-render) their page.
210
215
  */
211
216
  const CalendarSelectionProvider = CalendarSelectionContext.Provider;
217
+ /** Reads the active selection provided by {@link CalendarSelectionProvider}. */
212
218
  const useCalendarSelection = () => useContext(CalendarSelectionContext);
213
219
  /**
214
220
  * Controlled-ish range selection state for the month view. Returns the current
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@super-calendar/core",
3
- "version": "2.0.0",
3
+ "version": "2.1.3",
4
4
  "description": "Render-agnostic core for super-calendar: date math, selection model, event layout, the month-grid builder, headless hooks, and neutral theme tokens. No renderer.",
5
5
  "keywords": [
6
6
  "calendar",
@@ -9,10 +9,11 @@
9
9
  "headless",
10
10
  "react"
11
11
  ],
12
+ "homepage": "https://super-calendar.afonsojramos.me",
12
13
  "license": "MIT",
13
14
  "repository": {
14
15
  "type": "git",
15
- "url": "git+https://github.com/afonsojramos/react-native-super-calendar.git",
16
+ "url": "git+https://github.com/afonsojramos/super-calendar.git",
16
17
  "directory": "packages/core"
17
18
  },
18
19
  "source": "./src/index.ts",
package/src/index.ts CHANGED
@@ -1,7 +1,21 @@
1
- // @super-calendar/core: the render-agnostic core. Date math, the selection
2
- // model, event layout, the month-grid builder, the headless hooks, and the
3
- // neutral theme tokens. Imports nothing from React Native, react-dom, Reanimated,
4
- // Gesture Handler, or Legend List, so it bundles into any renderer.
1
+ /**
2
+ * The render-agnostic core of super-calendar. Date math, the selection model,
3
+ * event layout, the month-grid builder, the headless hooks, and the neutral
4
+ * theme tokens.
5
+ *
6
+ * Imports nothing from React Native, react-dom, Reanimated, Gesture Handler, or
7
+ * Legend List, so it bundles into any renderer. Pair it with `@super-calendar/dom`
8
+ * or `@super-calendar/native`, or drive your own UI from the headless hooks.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * import { useMonthGrid, buildMonthWeeks } from "@super-calendar/core";
13
+ * ```
14
+ *
15
+ * @see https://super-calendar.afonsojramos.me
16
+ *
17
+ * @module
18
+ */
5
19
  export * from "./types";
6
20
  export * from "./tokens";
7
21
  export * from "./presentation";
package/src/tokens.ts CHANGED
@@ -3,6 +3,7 @@
3
3
  // platform types. Renderer-specific metrics (cell / badge / band sizes) stay in
4
4
  // each renderer's theme, since they legitimately differ between the two.
5
5
 
6
+ /** The shared colour palette both renderers derive their themes from. */
6
7
  export interface CalendarColors {
7
8
  /** Hour lines, day separators and month-cell borders. */
8
9
  gridLine: string;
@@ -36,6 +37,7 @@ export interface CalendarColors {
36
37
  eventText: string;
37
38
  }
38
39
 
40
+ /** The default light-theme colour palette. */
39
41
  export const lightColors: CalendarColors = {
40
42
  gridLine: "#E2E4E9",
41
43
  weekendBackground: "#F6F7F9",
@@ -54,6 +56,7 @@ export const lightColors: CalendarColors = {
54
56
  eventText: "#1A1B1E",
55
57
  };
56
58
 
59
+ /** The default dark-theme colour palette. */
57
60
  export const darkColors: CalendarColors = {
58
61
  gridLine: "#2A2E37",
59
62
  weekendBackground: "#15171C",
package/src/types.ts CHANGED
@@ -1,3 +1,4 @@
1
+ /** The view the calendar renders: a day-column grid (`day`, `3days`, `week`, `custom`), the `month` grid, or the `schedule` list. */
1
2
  export type CalendarMode = "day" | "3days" | "week" | "custom" | "month" | "schedule";
2
3
 
3
4
  /** The time-grid modes (day-column views, excluding month and schedule). */
@@ -10,8 +11,11 @@ export type TimeGridMode = Exclude<CalendarMode, "month" | "schedule">;
10
11
  * threaded through untouched via the `T` generic.
11
12
  */
12
13
  export interface ICalendarEvent {
14
+ /** When the event begins. */
13
15
  start: Date;
16
+ /** When the event ends. */
14
17
  end: Date;
18
+ /** Display label, shown by the built-in default renderer. */
15
19
  title?: string;
16
20
  /**
17
21
  * Force this event into the all-day lane (above the time grid) instead of the
@@ -34,6 +38,7 @@ export type RecurrenceFrequency = "daily" | "weekly" | "monthly" | "yearly";
34
38
 
35
39
  /** A simple, RRULE-inspired repeat rule expanded by `expandRecurringEvents`. */
36
40
  export interface RecurrenceRule {
41
+ /** How often the event repeats. */
37
42
  freq: RecurrenceFrequency;
38
43
  /** Repeat every N periods. Default 1. */
39
44
  interval?: number;
@@ -1,10 +1,21 @@
1
1
  import { isAfter, isBefore, startOfDay } from "date-fns";
2
- import { createContext, useCallback, useContext, useMemo, useState } from "react";
2
+ import {
3
+ type Context,
4
+ createContext,
5
+ type Dispatch,
6
+ type SetStateAction,
7
+ useCallback,
8
+ useContext,
9
+ useMemo,
10
+ useState,
11
+ } from "react";
3
12
  import { isSameCalendarDay } from "./dates";
4
13
 
5
14
  /** A selected span. `end` is `null` while only the first endpoint has been picked. */
6
15
  export interface DateRange {
16
+ /** The first endpoint. */
7
17
  start: Date;
18
+ /** The second endpoint, or `null` while only the first has been picked. */
8
19
  end: Date | null;
9
20
  }
10
21
 
@@ -72,7 +83,9 @@ export interface DaySelectionState {
72
83
  isSelected: boolean;
73
84
  /** Inside a complete range, endpoints included (and not disabled). */
74
85
  isInRange: boolean;
86
+ /** The range's start endpoint (and not disabled). */
75
87
  isRangeStart: boolean;
88
+ /** The range's end endpoint (and not disabled). */
76
89
  isRangeEnd: boolean;
77
90
  }
78
91
 
@@ -106,11 +119,13 @@ export function daySelectionState(
106
119
  * cached/virtualized day cells still repaint when any of it changes.
107
120
  */
108
121
  export interface CalendarSelection extends DateSelectionConstraints {
122
+ /** Selected discrete days (single or multiple). */
109
123
  selectedDates?: Date[];
124
+ /** Selected span. */
110
125
  selectedRange?: DateRange;
111
126
  }
112
127
 
113
- const CalendarSelectionContext = createContext<CalendarSelection>({});
128
+ const CalendarSelectionContext: Context<CalendarSelection> = createContext<CalendarSelection>({});
114
129
 
115
130
  /**
116
131
  * Provides the active selection to the month grid. Day cells read it via
@@ -119,7 +134,8 @@ const CalendarSelectionContext = createContext<CalendarSelection>({});
119
134
  */
120
135
  export const CalendarSelectionProvider = CalendarSelectionContext.Provider;
121
136
 
122
- export const useCalendarSelection = () => useContext(CalendarSelectionContext);
137
+ /** Reads the active selection provided by {@link CalendarSelectionProvider}. */
138
+ export const useCalendarSelection = (): CalendarSelection => useContext(CalendarSelectionContext);
123
139
 
124
140
  /** Options for {@link useDateRange}. */
125
141
  export interface UseDateRangeOptions extends DateSelectionConstraints {
@@ -127,6 +143,20 @@ export interface UseDateRangeOptions extends DateSelectionConstraints {
127
143
  initialRange?: DateRange | null;
128
144
  }
129
145
 
146
+ /** The state and handlers returned by {@link useDateRange}. */
147
+ export interface UseDateRangeResult {
148
+ /** The current selection; `null` until the first endpoint is picked. */
149
+ range: DateRange | null;
150
+ /** Wire to `onPressDay`: advances the range (start, then end, then restarts). */
151
+ onPressDate: (date: Date) => void;
152
+ /** Set both endpoints at once (ordered); ignored if either isn't selectable. */
153
+ selectRange: (a: Date, b: Date) => void;
154
+ /** Clear the selection. */
155
+ reset: () => void;
156
+ /** The raw state setter, for full control. */
157
+ setRange: Dispatch<SetStateAction<DateRange | null>>;
158
+ }
159
+
130
160
  /**
131
161
  * Controlled-ish range selection state for the month view. Returns the current
132
162
  * `range` plus an `onPressDate` handler to wire to `Calendar`'s `onPressDay`, a
@@ -137,7 +167,7 @@ export interface UseDateRangeOptions extends DateSelectionConstraints {
137
167
  * <Calendar mode="month" selectedRange={range ?? undefined} onPressDay={onPressDate} … />
138
168
  * ```
139
169
  */
140
- export function useDateRange(options: UseDateRangeOptions = {}) {
170
+ export function useDateRange(options: UseDateRangeOptions = {}): UseDateRangeResult {
141
171
  const { initialRange = null, minDate, maxDate, isDateDisabled } = options;
142
172
  const [range, setRange] = useState<DateRange | null>(initialRange);
143
173
  const constraints = useMemo<DateSelectionConstraints>(
@@ -105,13 +105,16 @@ export const buildMonthWeeks = (
105
105
  return weeks;
106
106
  };
107
107
 
108
+ /** True when `date` is a Saturday or Sunday. */
108
109
  export const isWeekend = (date: Date): boolean => {
109
110
  const day = date.getDay();
110
111
  return day === 0 || day === 6;
111
112
  };
112
113
 
114
+ /** True when `date` falls on the current calendar day. */
113
115
  export const getIsToday = (date: Date): boolean => isToday(date);
114
116
 
117
+ /** True when `a` and `b` are the same calendar day (ignoring the time of day). */
115
118
  export const isSameCalendarDay = (a: Date, b: Date): boolean => isSameDay(a, b);
116
119
 
117
120
  /** Minutes elapsed since midnight (0–1439). */
@@ -6,7 +6,9 @@ const MINUTES_PER_HOUR = 60;
6
6
  // span still occupies a sliver rather than collapsing to nothing.
7
7
  const MIN_DURATION_HOURS = 0.25;
8
8
 
9
+ /** An event placed on a single day's time grid by {@link layoutDayEvents}, with its vertical span and overlap column. */
9
10
  export type PositionedEvent<T> = {
11
+ /** The source event for this segment. */
10
12
  event: CalendarEvent<T>;
11
13
  /** Hours from midnight to the event's segment start on this day (fractional). */
12
14
  startHours: number;
@@ -6,17 +6,25 @@ import { buildMonthWeeks, getIsToday, isWeekend } from "./dates";
6
6
 
7
7
  /** A single day in the grid, with all the state a custom cell needs to render. */
8
8
  export interface MonthGridDay {
9
+ /** The day this cell represents. */
9
10
  date: Date;
10
11
  /** Stable `yyyy-MM-dd` id, handy as a React key. */
11
12
  id: string;
12
13
  /** Day-of-month, e.g. "1". */
13
14
  label: string;
15
+ /** False for days bleeding in from the previous or next month. */
14
16
  isCurrentMonth: boolean;
17
+ /** The day is today. */
15
18
  isToday: boolean;
19
+ /** The day is a Saturday or Sunday. */
16
20
  isWeekend: boolean;
21
+ /** The day fails the min/max/disabled constraints. */
17
22
  isDisabled: boolean;
23
+ /** The day is a `selectedDates` day or a range endpoint (and not disabled). */
18
24
  isSelected: boolean;
25
+ /** The day is the range's start endpoint. */
19
26
  isRangeStart: boolean;
27
+ /** The day is the range's end endpoint. */
20
28
  isRangeEnd: boolean;
21
29
  /** Inside a complete range (endpoints included). */
22
30
  isInRange: boolean;
@@ -24,21 +32,29 @@ export interface MonthGridDay {
24
32
 
25
33
  /** One week row. */
26
34
  export interface MonthGridWeek {
35
+ /** Stable id for the week row, handy as a React key. */
27
36
  id: string;
37
+ /** The seven days of the row, in display order. */
28
38
  days: MonthGridDay[];
29
39
  }
30
40
 
31
41
  /** A weekday header cell (e.g. "Mon"). */
32
42
  export interface MonthGridWeekday {
43
+ /** A representative date for the column, used to derive the label. */
33
44
  date: Date;
45
+ /** The short weekday name (e.g. "Mon"), localised via `locale`. */
34
46
  label: string;
35
47
  }
36
48
 
49
+ /** The full grid for one month: the week rows and the weekday header cells. */
37
50
  export interface MonthGrid {
51
+ /** The week rows, padded to whole weeks. */
38
52
  weeks: MonthGridWeek[];
53
+ /** The weekday header cells, in display order. */
39
54
  weekdays: MonthGridWeekday[];
40
55
  }
41
56
 
57
+ /** Options for {@link buildMonthGrid} and {@link useMonthGrid}. */
42
58
  export interface UseMonthGridOptions extends DateSelectionConstraints {
43
59
  /** First day of the week. Sunday = 0 (default) … Saturday = 6. */
44
60
  weekStartsOn?: WeekStartsOn;