-
-
Notifications
You must be signed in to change notification settings - Fork 697
/
SelectMultipleContext.tsx
151 lines (132 loc) · 3.98 KB
/
SelectMultipleContext.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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import { createContext, ReactNode, useContext } from "react";
import { isSameDay } from "date-fns";
import { DayPickerBase } from "../../types/DayPickerBase";
import {
DayPickerMultipleProps,
isDayPickerMultiple
} from "../../types/DayPickerMultiple";
import { DayClickEventHandler } from "../../types/EventHandlers";
import { InternalModifier, Modifiers } from "../../types/Modifiers";
/** Represent the modifiers that are changed by the multiple selection. */
export type SelectMultipleModifiers = Pick<
Modifiers,
InternalModifier.Disabled
>;
/** Represents the value of a {@link SelectMultipleContext}. */
export interface SelectMultipleContextValue {
/** The days that have been selected. */
selected: Date[] | undefined;
/** The modifiers for the corresponding selection. */
modifiers: SelectMultipleModifiers;
/** Event handler to attach to the day button to enable the multiple select. */
onDayClick?: DayClickEventHandler;
}
/**
* The SelectMultiple context shares details about the selected days when in
* multiple selection mode.
*
* Access this context from the {@link useSelectMultiple} hook.
*/
export const SelectMultipleContext = createContext<
SelectMultipleContextValue | undefined
>(undefined);
export type SelectMultipleProviderProps = {
initialProps: DayPickerBase;
children?: ReactNode;
};
/** Provides the values for the {@link SelectMultipleContext}. */
export function SelectMultipleProvider(
props: SelectMultipleProviderProps
): JSX.Element {
if (!isDayPickerMultiple(props.initialProps)) {
const emptyContextValue: SelectMultipleContextValue = {
selected: undefined,
modifiers: {
disabled: []
}
};
return (
<SelectMultipleContext.Provider value={emptyContextValue}>
{props.children}
</SelectMultipleContext.Provider>
);
}
return (
<SelectMultipleProviderInternal
initialProps={props.initialProps}
children={props.children}
/>
);
}
/** @private */
export interface SelectMultipleProviderInternalProps {
initialProps: DayPickerMultipleProps;
children?: ReactNode;
}
export function SelectMultipleProviderInternal({
initialProps,
children
}: SelectMultipleProviderInternalProps): JSX.Element {
const { selected, min, max } = initialProps;
const onDayClick: DayClickEventHandler = (day, activeModifiers, e) => {
initialProps.onDayClick?.(day, activeModifiers, e);
const isMinSelected = Boolean(
activeModifiers.selected && min && selected?.length === min
);
if (isMinSelected) {
return;
}
const isMaxSelected = Boolean(
!activeModifiers.selected && max && selected?.length === max
);
if (isMaxSelected) {
return;
}
const selectedDays = selected ? [...selected] : [];
if (activeModifiers.selected) {
const index = selectedDays.findIndex((selectedDay) =>
isSameDay(day, selectedDay)
);
selectedDays.splice(index, 1);
} else {
selectedDays.push(day);
}
initialProps.onSelect?.(selectedDays, day, activeModifiers, e);
};
const modifiers: SelectMultipleModifiers = {
disabled: []
};
if (selected) {
modifiers.disabled.push((day: Date) => {
const isMaxSelected = max && selected.length > max - 1;
const isSelected = selected.some((selectedDay) =>
isSameDay(selectedDay, day)
);
return Boolean(isMaxSelected && !isSelected);
});
}
const contextValue = {
selected,
onDayClick,
modifiers
};
return (
<SelectMultipleContext.Provider value={contextValue}>
{children}
</SelectMultipleContext.Provider>
);
}
/**
* Hook to access the {@link SelectMultipleContextValue}.
*
* This hook is meant to be used inside internal or custom components.
*/
export function useSelectMultiple(): SelectMultipleContextValue {
const context = useContext(SelectMultipleContext);
if (!context) {
throw new Error(
"useSelectMultiple must be used within a SelectMultipleProvider"
);
}
return context;
}