1 | import { useEffect, useState } from "react";
|
2 |
|
3 | import type {
|
4 | CalendarWeek,
|
5 | CalendarDay,
|
6 | CalendarMonth
|
7 | } from "./classes/index.js";
|
8 | import { getDates } from "./helpers/getDates.js";
|
9 | import { getDays } from "./helpers/getDays.js";
|
10 | import { getDisplayMonths } from "./helpers/getDisplayMonths.js";
|
11 | import { getInitialMonth } from "./helpers/getInitialMonth.js";
|
12 | import { getMonths } from "./helpers/getMonths.js";
|
13 | import { getNavMonths } from "./helpers/getNavMonth.js";
|
14 | import { getNextMonth } from "./helpers/getNextMonth.js";
|
15 | import { getPreviousMonth } from "./helpers/getPreviousMonth.js";
|
16 | import { getWeeks } from "./helpers/getWeeks.js";
|
17 | import type { DayPickerProps } from "./types/props.js";
|
18 | import type { DateLib } from "./types/shared.js";
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 | export interface Calendar {
|
26 | |
27 |
|
28 |
|
29 |
|
30 |
|
31 | days: CalendarDay[];
|
32 |
|
33 | weeks: CalendarWeek[];
|
34 |
|
35 | months: CalendarMonth[];
|
36 |
|
37 |
|
38 | nextMonth: Date | undefined;
|
39 |
|
40 | previousMonth: Date | undefined;
|
41 |
|
42 | |
43 |
|
44 |
|
45 |
|
46 | navStart: Date | undefined;
|
47 | |
48 |
|
49 |
|
50 |
|
51 | navEnd: Date | undefined;
|
52 |
|
53 |
|
54 | goToMonth: (month: Date) => void;
|
55 | |
56 |
|
57 |
|
58 |
|
59 |
|
60 |
|
61 |
|
62 |
|
63 |
|
64 | goToDay: (day: CalendarDay) => void;
|
65 | }
|
66 |
|
67 |
|
68 | export function useCalendar(
|
69 | props: Pick<
|
70 | DayPickerProps,
|
71 | | "captionLayout"
|
72 | | "endMonth"
|
73 | | "startMonth"
|
74 | | "today"
|
75 | | "fixedWeeks"
|
76 | | "ISOWeek"
|
77 | | "weekStartsOn"
|
78 | | "numberOfMonths"
|
79 | | "disableNavigation"
|
80 | | "onMonthChange"
|
81 | | "month"
|
82 | | "defaultMonth"
|
83 |
|
84 | | "fromMonth"
|
85 | | "fromYear"
|
86 | | "toMonth"
|
87 | | "toYear"
|
88 | >,
|
89 | dateLib: DateLib
|
90 | ): Calendar {
|
91 | const [navStart, navEnd] = getNavMonths(props, dateLib);
|
92 |
|
93 | const { startOfMonth, endOfMonth } = dateLib;
|
94 |
|
95 | const initialMonth = getInitialMonth(props, dateLib);
|
96 |
|
97 | const [firstMonth, setFirstMonth] = useState(initialMonth);
|
98 |
|
99 |
|
100 | useEffect(() => {
|
101 | const initialDisplayMonth = getInitialMonth(props, dateLib);
|
102 | setFirstMonth(initialDisplayMonth);
|
103 |
|
104 | }, [props.month]);
|
105 |
|
106 |
|
107 | useEffect(() => {
|
108 |
|
109 |
|
110 | const initialDisplayMonth = getInitialMonth(props, dateLib);
|
111 | setFirstMonth(initialDisplayMonth);
|
112 |
|
113 | }, [props.startMonth, props.endMonth]);
|
114 |
|
115 |
|
116 | const displayMonths = getDisplayMonths(firstMonth, navEnd, props, dateLib);
|
117 |
|
118 |
|
119 | const dates = getDates(
|
120 | displayMonths,
|
121 | props.endMonth ? endOfMonth(props.endMonth) : undefined,
|
122 | props,
|
123 | dateLib
|
124 | );
|
125 |
|
126 |
|
127 | const months = getMonths(displayMonths, dates, props, dateLib);
|
128 |
|
129 |
|
130 | const weeks = getWeeks(months);
|
131 |
|
132 |
|
133 | const days = getDays(months);
|
134 |
|
135 | const previousMonth = getPreviousMonth(firstMonth, navStart, props, dateLib);
|
136 | const nextMonth = getNextMonth(firstMonth, navEnd, props, dateLib);
|
137 |
|
138 | const { disableNavigation, onMonthChange } = props;
|
139 |
|
140 | const isDayInCalendar = (day: CalendarDay) =>
|
141 | weeks.some((week: CalendarWeek) => week.days.some((d) => d.isEqualTo(day)));
|
142 |
|
143 | const goToMonth = (date: Date) => {
|
144 | if (disableNavigation) {
|
145 | return;
|
146 | }
|
147 | let newMonth = startOfMonth(date);
|
148 |
|
149 | if (navStart && newMonth < startOfMonth(navStart)) {
|
150 | newMonth = startOfMonth(navStart);
|
151 | }
|
152 |
|
153 | if (navEnd && newMonth > startOfMonth(navEnd)) {
|
154 | newMonth = startOfMonth(navEnd);
|
155 | }
|
156 | setFirstMonth(newMonth);
|
157 | onMonthChange?.(newMonth);
|
158 | };
|
159 |
|
160 | const goToDay = (day: CalendarDay) => {
|
161 |
|
162 | if (isDayInCalendar(day)) {
|
163 | return;
|
164 | }
|
165 | goToMonth(day.date);
|
166 | };
|
167 |
|
168 | const calendar = {
|
169 | months,
|
170 | weeks,
|
171 | days,
|
172 |
|
173 | navStart,
|
174 | navEnd,
|
175 |
|
176 | previousMonth,
|
177 | nextMonth,
|
178 |
|
179 | goToMonth,
|
180 | goToDay
|
181 | };
|
182 |
|
183 | return calendar;
|
184 | }
|