-
-
Notifications
You must be signed in to change notification settings - Fork 697
/
NavigationContext.tsx
102 lines (89 loc) · 2.97 KB
/
NavigationContext.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
import { createContext, ReactNode, useContext } from "react";
import { addMonths, isBefore, isSameMonth } from "date-fns";
import { useDayPicker } from "../DayPicker";
import { useNavigationState } from "./useNavigationState";
import { getDisplayMonths } from "./utils/getDisplayMonths";
import { getNextMonth } from "./utils/getNextMonth";
import { getPreviousMonth } from "./utils/getPreviousMonth";
/** Represents the value of the {@link NavigationContext}. */
export interface NavigationContextValue {
/**
* The month to display in the calendar. When `numberOfMonths` is greater than
* one, is the first of the displayed months.
*/
currentMonth: Date;
/**
* The months rendered by DayPicker. DayPicker can render multiple months via
* `numberOfMonths`.
*/
displayMonths: Date[];
/** Navigate to the specified month. */
goToMonth: (month: Date) => void;
/** Navigate to the specified date. */
goToDate: (date: Date, refDate?: Date) => void;
/** The next month to display. */
nextMonth?: Date;
/** The previous month to display. */
previousMonth?: Date;
/** Whether the given day is included in the displayed months. */
isDateDisplayed: (day: Date) => boolean;
}
/**
* The Navigation context shares details and methods to navigate the months in
* DayPicker. Access this context from the {@link useNavigation} hook.
*/
export const NavigationContext = createContext<
NavigationContextValue | undefined
>(undefined);
/** Provides the values for the {@link NavigationContext}. */
export function NavigationProvider(props: {
children?: ReactNode;
}): JSX.Element {
const dayPicker = useDayPicker();
const [currentMonth, goToMonth] = useNavigationState();
const displayMonths = getDisplayMonths(currentMonth, dayPicker);
const nextMonth = getNextMonth(currentMonth, dayPicker);
const previousMonth = getPreviousMonth(currentMonth, dayPicker);
const isDateDisplayed = (date: Date) => {
return displayMonths.some((displayMonth) =>
isSameMonth(date, displayMonth)
);
};
const goToDate = (date: Date, refDate?: Date) => {
if (isDateDisplayed(date)) {
return;
}
if (refDate && isBefore(date, refDate)) {
goToMonth(addMonths(date, 1 + dayPicker.numberOfMonths * -1));
} else {
goToMonth(date);
}
};
const value: NavigationContextValue = {
currentMonth,
displayMonths,
goToMonth,
goToDate,
previousMonth,
nextMonth,
isDateDisplayed
};
return (
<NavigationContext.Provider value={value}>
{props.children}
</NavigationContext.Provider>
);
}
/**
* Hook to access the {@link NavigationContextValue}. Use this hook to navigate
* between months or years in DayPicker.
*
* This hook is meant to be used inside internal or custom components.
*/
export function useNavigation(): NavigationContextValue {
const context = useContext(NavigationContext);
if (!context) {
throw new Error("useNavigation must be used within a NavigationProvider");
}
return context;
}