@uxf/datepicker 10.0.0 → 11.0.0
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 +25 -17
- package/contexts/date-picker-context.js +2 -0
- package/contexts/date-range-picker-context.js +2 -0
- package/hooks/use-date-picker.d.ts +7 -2
- package/hooks/use-date-picker.js +6 -2
- package/hooks/use-date-range-picker.d.ts +6 -2
- package/hooks/use-date-range-picker.js +6 -2
- package/hooks/use-day.d.ts +9 -2
- package/hooks/use-day.js +34 -3
- package/hooks/use-day.test.js +63 -6
- package/package.json +1 -1
- package/utils/get-date-intervals.test.d.ts +1 -0
- package/utils/get-date-intervals.test.js +39 -0
- package/utils/get-date-invervals.d.ts +3 -0
- package/utils/get-date-invervals.js +32 -0
- package/utils/types.d.ts +10 -0
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ A set of React hooks to create an awesome datepicker.
|
|
|
10
10
|
|
|
11
11
|
### Main logic component
|
|
12
12
|
|
|
13
|
-
```
|
|
13
|
+
```tsx
|
|
14
14
|
export const DatePicker: FC = () => {
|
|
15
15
|
// prepare state to handle selected date
|
|
16
16
|
const [selectedDate, setSelectedDate] = useState<OnDateChangeType>(null);
|
|
@@ -42,7 +42,7 @@ export const DatePicker: FC = () => {
|
|
|
42
42
|
|
|
43
43
|
### Month component
|
|
44
44
|
|
|
45
|
-
```
|
|
45
|
+
```tsx
|
|
46
46
|
export const DateRangePickerMonth: FC<UseMonthProps> = ({
|
|
47
47
|
firstDayOfWeek,
|
|
48
48
|
month,
|
|
@@ -69,7 +69,7 @@ export const DateRangePickerMonth: FC<UseMonthProps> = ({
|
|
|
69
69
|
|
|
70
70
|
### Day component
|
|
71
71
|
|
|
72
|
-
```
|
|
72
|
+
```tsx
|
|
73
73
|
export const DateRangePickerDay: FC<{ day: string; date: Date }> = ({ day, date }) => {
|
|
74
74
|
const dayRef = useRef(null);
|
|
75
75
|
const {
|
|
@@ -134,7 +134,8 @@ export const DateRangePickerDay: FC<{ day: string; date: Date }> = ({ day, date
|
|
|
134
134
|
| numberOfMonths | `number` | | `1` | |
|
|
135
135
|
| onDateChange | `(data: OnDateChangeType): void` | yes | | |
|
|
136
136
|
| selectedDate | `Date \| null` | yes | | |
|
|
137
|
-
| unavailableDates | `Date[]` | | `[]` |
|
|
137
|
+
| unavailableDates | `Date[]` | | `[]` | @deprecated |
|
|
138
|
+
| datesConfig | `DatesConfig[]` | | `[]` | |
|
|
138
139
|
|
|
139
140
|
**UseDatePickerReturnType**
|
|
140
141
|
|
|
@@ -186,7 +187,8 @@ export const DateRangePickerDay: FC<{ day: string; date: Date }> = ({ day, date
|
|
|
186
187
|
| numberOfMonths | `number` | | `2` | |
|
|
187
188
|
| onDatesChange | `(data: OnDatesChangeType): void` | yes | | |
|
|
188
189
|
| startDate | `Date \| null` | yes | | |
|
|
189
|
-
| unavailableDates | `Date[]` | | `[]` |
|
|
190
|
+
| unavailableDates | `Date[]` | | `[]` | @deprecated |
|
|
191
|
+
| datesConfig | `DatesConfig[]` | | `[]` | |
|
|
190
192
|
|
|
191
193
|
**UseDateRangePickerReturnType**
|
|
192
194
|
|
|
@@ -280,24 +282,29 @@ export const DateRangePickerDay: FC<{ day: string; date: Date }> = ({ day, date
|
|
|
280
282
|
|
|
281
283
|
**UseDayProps**
|
|
282
284
|
|
|
283
|
-
| name
|
|
284
|
-
|
|
285
|
-
| date
|
|
286
|
-
| dayRef
|
|
287
|
-
| focusedDate
|
|
288
|
-
| isDateBlocked
|
|
289
|
-
| isDateFocused
|
|
290
|
-
| isDateHovered
|
|
291
|
-
| isDateSelected
|
|
292
|
-
| onDateFocus
|
|
293
|
-
| onDateHover
|
|
294
|
-
| onDateSelect
|
|
285
|
+
| name | type | required | default | description |
|
|
286
|
+
|------------------|---------------------------|----------|---------|-------------|
|
|
287
|
+
| date | `Date` | yes | | |
|
|
288
|
+
| dayRef | `RefObject` | | | |
|
|
289
|
+
| focusedDate | `Date \| null` | yes | | |
|
|
290
|
+
| isDateBlocked | `(date: Date) => boolean` | yes | | |
|
|
291
|
+
| isDateFocused | `(date: Date) => boolean` | yes | | |
|
|
292
|
+
| isDateHovered | `(date: Date) => boolean` | yes | | |
|
|
293
|
+
| isDateSelected | `(date: Date) => boolean` | yes | | |
|
|
294
|
+
| onDateFocus | `(date: Date) => void` | yes | | |
|
|
295
|
+
| onDateHover | `(date: Date) => void` | yes | | |
|
|
296
|
+
| onDateSelect | `(date: Date) => void` | yes | | |
|
|
297
|
+
| unavailableDates | `Date[]` | | | @deprecated |
|
|
298
|
+
| datesConfig | `DatesConfig[]` | | | |
|
|
295
299
|
|
|
296
300
|
**UseDayReturnType**
|
|
297
301
|
|
|
298
302
|
| name | type | description |
|
|
299
303
|
|--------------------|------------------------------|-------------|
|
|
300
304
|
| disabledDate | `boolean` | |
|
|
305
|
+
| isFirstDisabled | `boolean` | |
|
|
306
|
+
| isLastDisabled | `boolean` | |
|
|
307
|
+
| disabledDate | `boolean` | |
|
|
301
308
|
| isHovered | `boolean` | |
|
|
302
309
|
| isSelected | `boolean` | |
|
|
303
310
|
| isToday | `boolean` | |
|
|
@@ -306,6 +313,7 @@ export const DateRangePickerDay: FC<{ day: string; date: Date }> = ({ day, date
|
|
|
306
313
|
| onKeyDown | `(e: KeyboardEvent) => void` | |
|
|
307
314
|
| onMouseEnter | `() => void` | |
|
|
308
315
|
| tabIndex | `number` | |
|
|
316
|
+
| flags | `Flag[]` | |
|
|
309
317
|
|
|
310
318
|
## Known issues
|
|
311
319
|
|
|
@@ -4,6 +4,7 @@ exports.DatePickerContext = void 0;
|
|
|
4
4
|
const react_1 = require("react");
|
|
5
5
|
exports.DatePickerContext = (0, react_1.createContext)({
|
|
6
6
|
activeMonths: [],
|
|
7
|
+
datesConfig: [],
|
|
7
8
|
canGoToMonth: () => true,
|
|
8
9
|
canGoToNextMonth: true,
|
|
9
10
|
canGoToNextYear: true,
|
|
@@ -30,4 +31,5 @@ exports.DatePickerContext = (0, react_1.createContext)({
|
|
|
30
31
|
onDateSelect: () => undefined,
|
|
31
32
|
onResetDates: () => undefined,
|
|
32
33
|
preventScroll: undefined,
|
|
34
|
+
unavailableDates: [],
|
|
33
35
|
});
|
|
@@ -4,6 +4,7 @@ exports.DateRangePickerContext = void 0;
|
|
|
4
4
|
const react_1 = require("react");
|
|
5
5
|
exports.DateRangePickerContext = (0, react_1.createContext)({
|
|
6
6
|
activeMonths: [],
|
|
7
|
+
datesConfig: [],
|
|
7
8
|
canGoToMonth: () => true,
|
|
8
9
|
canGoToNextMonth: true,
|
|
9
10
|
canGoToNextYear: true,
|
|
@@ -32,4 +33,5 @@ exports.DateRangePickerContext = (0, react_1.createContext)({
|
|
|
32
33
|
onDateHover: () => undefined,
|
|
33
34
|
onDateSelect: () => undefined,
|
|
34
35
|
onResetDates: () => undefined,
|
|
36
|
+
unavailableDates: [],
|
|
35
37
|
});
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { FirstDayOfWeek, MonthType } from "../utils/types";
|
|
1
|
+
import { DatesConfig, FirstDayOfWeek, MonthType } from "../utils/types";
|
|
2
2
|
import { UseDatePickerNavigationReturnType } from "./use-date-picker-navigation";
|
|
3
3
|
export type OnDateChangeType = Date | null;
|
|
4
4
|
export interface UseDatePickerProps {
|
|
5
|
+
datesConfig?: DatesConfig[];
|
|
5
6
|
firstDayOfWeek?: FirstDayOfWeek;
|
|
6
7
|
initialVisibleMonth?: Date;
|
|
7
8
|
isDateBlocked?: (date: Date) => boolean;
|
|
@@ -11,10 +12,12 @@ export interface UseDatePickerProps {
|
|
|
11
12
|
onDateChange: (data: OnDateChangeType) => void;
|
|
12
13
|
preventScroll?: boolean;
|
|
13
14
|
selectedDate: Date | null;
|
|
15
|
+
/** @deprecated */
|
|
14
16
|
unavailableDates?: Date[];
|
|
15
17
|
}
|
|
16
18
|
export interface UseDatePickerReturnType extends UseDatePickerNavigationReturnType {
|
|
17
19
|
activeMonths: MonthType[];
|
|
20
|
+
datesConfig?: DatesConfig[];
|
|
18
21
|
firstDayOfWeek: FirstDayOfWeek;
|
|
19
22
|
focusedDate: Date | null;
|
|
20
23
|
hoveredDate: Date | null;
|
|
@@ -28,5 +31,7 @@ export interface UseDatePickerReturnType extends UseDatePickerNavigationReturnTy
|
|
|
28
31
|
onDateSelect: (date: Date) => void;
|
|
29
32
|
onResetDates: () => void;
|
|
30
33
|
preventScroll?: boolean;
|
|
34
|
+
/** deprecated */
|
|
35
|
+
unavailableDates: Date[];
|
|
31
36
|
}
|
|
32
|
-
export declare function useDatePicker({ firstDayOfWeek, initialVisibleMonth, isDateBlocked: isDateBlockedProps, maxBookingDate, minBookingDate, numberOfMonths, onDateChange, preventScroll, selectedDate, unavailableDates, }: UseDatePickerProps): UseDatePickerReturnType;
|
|
37
|
+
export declare function useDatePicker({ datesConfig, firstDayOfWeek, initialVisibleMonth, isDateBlocked: isDateBlockedProps, maxBookingDate, minBookingDate, numberOfMonths, onDateChange, preventScroll, selectedDate, unavailableDates, }: UseDatePickerProps): UseDatePickerReturnType;
|
package/hooks/use-date-picker.js
CHANGED
|
@@ -10,14 +10,16 @@ const is_date_hovered_1 = require("../utils/is-date-hovered");
|
|
|
10
10
|
const is_in_unavailable_dates_1 = require("../utils/is-in-unavailable-dates");
|
|
11
11
|
const is_start_date_1 = require("../utils/is-start-date");
|
|
12
12
|
const use_date_picker_navigation_1 = require("./use-date-picker-navigation");
|
|
13
|
-
function useDatePicker({ firstDayOfWeek = 0, initialVisibleMonth, isDateBlocked: isDateBlockedProps = () => false, maxBookingDate, minBookingDate, numberOfMonths = 1, onDateChange, preventScroll, selectedDate, unavailableDates = [], }) {
|
|
13
|
+
function useDatePicker({ datesConfig = [], firstDayOfWeek = 0, initialVisibleMonth, isDateBlocked: isDateBlockedProps = () => false, maxBookingDate, minBookingDate, numberOfMonths = 1, onDateChange, preventScroll, selectedDate, unavailableDates = [], }) {
|
|
14
|
+
const disabledDatesFromConfig = datesConfig.filter((config) => config.isDisabled).flatMap((config) => config.dates);
|
|
15
|
+
const disabledDates = [...unavailableDates, ...disabledDatesFromConfig];
|
|
14
16
|
const [activeMonths, setActiveMonths] = (0, react_1.useState)(() => selectedDate
|
|
15
17
|
? (0, get_initial_months_1.getInitialMonths)(numberOfMonths, selectedDate)
|
|
16
18
|
: (0, get_initial_months_1.getInitialMonths)(numberOfMonths, initialVisibleMonth || null));
|
|
17
19
|
const [hoveredDate, setHoveredDate] = (0, react_1.useState)(null);
|
|
18
20
|
const [focusedDate, setFocusedDate] = (0, react_1.useState)(selectedDate);
|
|
19
21
|
const disabledDatesByUser = (date) => {
|
|
20
|
-
return (0, is_in_unavailable_dates_1.isInUnavailableDates)(
|
|
22
|
+
return (0, is_in_unavailable_dates_1.isInUnavailableDates)(disabledDates, date) || isDateBlockedProps(date);
|
|
21
23
|
};
|
|
22
24
|
const onDateFocus = (0, react_1.useCallback)((date) => {
|
|
23
25
|
setFocusedDate(date);
|
|
@@ -97,6 +99,7 @@ function useDatePicker({ firstDayOfWeek = 0, initialVisibleMonth, isDateBlocked:
|
|
|
97
99
|
setFocusedDate,
|
|
98
100
|
}),
|
|
99
101
|
activeMonths,
|
|
102
|
+
datesConfig,
|
|
100
103
|
firstDayOfWeek,
|
|
101
104
|
focusedDate,
|
|
102
105
|
hoveredDate,
|
|
@@ -110,6 +113,7 @@ function useDatePicker({ firstDayOfWeek = 0, initialVisibleMonth, isDateBlocked:
|
|
|
110
113
|
onDateSelect,
|
|
111
114
|
onResetDates: onReset,
|
|
112
115
|
preventScroll,
|
|
116
|
+
unavailableDates: disabledDates,
|
|
113
117
|
};
|
|
114
118
|
}
|
|
115
119
|
exports.useDatePicker = useDatePicker;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FirstDayOfWeek, MonthType } from "../utils/types";
|
|
1
|
+
import { DatesConfig, FirstDayOfWeek, MonthType } from "../utils/types";
|
|
2
2
|
import { UseDatePickerNavigationReturnType } from "./use-date-picker-navigation";
|
|
3
3
|
export declare const START_DATE = "startDate";
|
|
4
4
|
export declare const END_DATE = "endDate";
|
|
@@ -10,6 +10,7 @@ export interface OnDatesChangeProps {
|
|
|
10
10
|
}
|
|
11
11
|
export interface UseDateRangePickerProps {
|
|
12
12
|
changeActiveMonthOnSelect?: boolean;
|
|
13
|
+
datesConfig?: DatesConfig[];
|
|
13
14
|
endDate: Date | null;
|
|
14
15
|
exactMinBookingDays?: boolean;
|
|
15
16
|
firstDayOfWeek?: FirstDayOfWeek;
|
|
@@ -23,10 +24,12 @@ export interface UseDateRangePickerProps {
|
|
|
23
24
|
onDatesChange: (data: OnDatesChangeProps) => void;
|
|
24
25
|
preventScroll?: boolean;
|
|
25
26
|
startDate: Date | null;
|
|
27
|
+
/** @deprecated */
|
|
26
28
|
unavailableDates?: Date[];
|
|
27
29
|
}
|
|
28
30
|
export interface UseDateRangePickerReturnType extends UseDatePickerNavigationReturnType {
|
|
29
31
|
activeMonths: MonthType[];
|
|
32
|
+
datesConfig?: DatesConfig[];
|
|
30
33
|
firstDayOfWeek: FirstDayOfWeek;
|
|
31
34
|
focusedDate: Date | null;
|
|
32
35
|
hoveredDate: Date | null;
|
|
@@ -43,5 +46,6 @@ export interface UseDateRangePickerReturnType extends UseDatePickerNavigationRet
|
|
|
43
46
|
onDateSelect: (date: Date) => void;
|
|
44
47
|
onResetDates: () => void;
|
|
45
48
|
preventScroll?: boolean;
|
|
49
|
+
unavailableDates: Date[];
|
|
46
50
|
}
|
|
47
|
-
export declare function useDateRangePicker({ changeActiveMonthOnSelect, endDate, exactMinBookingDays, firstDayOfWeek, focusedInput, initialVisibleMonth, isDateBlocked: isDateBlockedProps, maxBookingDate, minBookingDate, minBookingDays, numberOfMonths, onDatesChange, startDate, unavailableDates, }: UseDateRangePickerProps): UseDateRangePickerReturnType;
|
|
51
|
+
export declare function useDateRangePicker({ changeActiveMonthOnSelect, datesConfig, endDate, exactMinBookingDays, firstDayOfWeek, focusedInput, initialVisibleMonth, isDateBlocked: isDateBlockedProps, maxBookingDate, minBookingDate, minBookingDays, numberOfMonths, onDatesChange, startDate, unavailableDates, }: UseDateRangePickerProps): UseDateRangePickerReturnType;
|
|
@@ -16,14 +16,16 @@ const is_start_date_1 = require("../utils/is-start-date");
|
|
|
16
16
|
const use_date_picker_navigation_1 = require("./use-date-picker-navigation");
|
|
17
17
|
exports.START_DATE = "startDate";
|
|
18
18
|
exports.END_DATE = "endDate";
|
|
19
|
-
function useDateRangePicker({ changeActiveMonthOnSelect = false, endDate, exactMinBookingDays = false, firstDayOfWeek = 0, focusedInput, initialVisibleMonth, isDateBlocked: isDateBlockedProps = () => false, maxBookingDate, minBookingDate, minBookingDays = 1, numberOfMonths = 2, onDatesChange, startDate, unavailableDates = [], }) {
|
|
19
|
+
function useDateRangePicker({ changeActiveMonthOnSelect = false, datesConfig = [], endDate, exactMinBookingDays = false, firstDayOfWeek = 0, focusedInput, initialVisibleMonth, isDateBlocked: isDateBlockedProps = () => false, maxBookingDate, minBookingDate, minBookingDays = 1, numberOfMonths = 2, onDatesChange, startDate, unavailableDates = [], }) {
|
|
20
|
+
const disabledDatesFromConfig = datesConfig.filter((config) => config.isDisabled).flatMap((config) => config.dates);
|
|
21
|
+
const disabledDates = [...unavailableDates, ...disabledDatesFromConfig];
|
|
20
22
|
const [activeMonths, setActiveMonths] = (0, react_1.useState)(() => startDate
|
|
21
23
|
? (0, get_initial_months_1.getInitialMonths)(numberOfMonths, startDate)
|
|
22
24
|
: (0, get_initial_months_1.getInitialMonths)(numberOfMonths, initialVisibleMonth || null));
|
|
23
25
|
const [hoveredDate, setHoveredDate] = (0, react_1.useState)(null);
|
|
24
26
|
const [focusedDate, setFocusedDate] = (0, react_1.useState)(startDate);
|
|
25
27
|
const disabledDatesByUser = (date) => {
|
|
26
|
-
return (0, is_in_unavailable_dates_1.isInUnavailableDates)(
|
|
28
|
+
return (0, is_in_unavailable_dates_1.isInUnavailableDates)(disabledDates, date) || isDateBlockedProps(date);
|
|
27
29
|
};
|
|
28
30
|
const onDateFocus = (0, react_1.useCallback)((date) => {
|
|
29
31
|
setFocusedDate(date);
|
|
@@ -205,6 +207,7 @@ function useDateRangePicker({ changeActiveMonthOnSelect = false, endDate, exactM
|
|
|
205
207
|
setFocusedDate,
|
|
206
208
|
}),
|
|
207
209
|
activeMonths,
|
|
210
|
+
datesConfig,
|
|
208
211
|
firstDayOfWeek,
|
|
209
212
|
focusedDate,
|
|
210
213
|
hoveredDate,
|
|
@@ -220,6 +223,7 @@ function useDateRangePicker({ changeActiveMonthOnSelect = false, endDate, exactM
|
|
|
220
223
|
onDateHover,
|
|
221
224
|
onDateSelect,
|
|
222
225
|
onResetDates,
|
|
226
|
+
unavailableDates: disabledDates,
|
|
223
227
|
};
|
|
224
228
|
}
|
|
225
229
|
exports.useDateRangePicker = useDateRangePicker;
|
package/hooks/use-day.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { KeyboardEvent, RefObject } from "react";
|
|
2
|
+
import { DatesConfig, Flag } from "../utils/types";
|
|
2
3
|
export interface UseDayProps {
|
|
3
4
|
date: Date;
|
|
5
|
+
datesConfig?: DatesConfig[];
|
|
4
6
|
dayRef?: RefObject<HTMLElement>;
|
|
5
7
|
focusedDate: Date | null;
|
|
6
8
|
isDateBlocked: (date: Date) => boolean;
|
|
@@ -12,12 +14,17 @@ export interface UseDayProps {
|
|
|
12
14
|
onDateHover: (date: Date) => void;
|
|
13
15
|
onDateSelect: (date: Date) => void;
|
|
14
16
|
preventScroll?: boolean;
|
|
17
|
+
/** @deprecated */
|
|
18
|
+
unavailableDates: Date[];
|
|
15
19
|
}
|
|
16
20
|
export interface UseDayReturnType {
|
|
21
|
+
flags: Flag[];
|
|
17
22
|
disabledDate: boolean;
|
|
23
|
+
isFirstDisabled: boolean;
|
|
18
24
|
isHovered: boolean;
|
|
19
|
-
isSelected: boolean;
|
|
20
25
|
isInsideRange: boolean;
|
|
26
|
+
isLastDisabled: boolean;
|
|
27
|
+
isSelected: boolean;
|
|
21
28
|
isToday: boolean;
|
|
22
29
|
isWithinHoverRange: boolean;
|
|
23
30
|
onClick?: () => void;
|
|
@@ -25,4 +32,4 @@ export interface UseDayReturnType {
|
|
|
25
32
|
onMouseEnter: () => void;
|
|
26
33
|
tabIndex: number;
|
|
27
34
|
}
|
|
28
|
-
export declare function useDay({ date, dayRef, focusedDate, isDateBlocked, isDateFocused, isDateHovered, isDateInsideRange, isDateSelected, onDateFocus, onDateHover, onDateSelect, preventScroll, }: UseDayProps): UseDayReturnType;
|
|
35
|
+
export declare function useDay({ date, datesConfig, dayRef, focusedDate, isDateBlocked, isDateFocused, isDateHovered, isDateInsideRange, isDateSelected, onDateFocus, onDateHover, onDateSelect, preventScroll, unavailableDates, }: UseDayProps): UseDayReturnType;
|
package/hooks/use-day.js
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.useDay = void 0;
|
|
7
|
+
const dayjs_1 = __importDefault(require("dayjs"));
|
|
4
8
|
const react_1 = require("react");
|
|
5
9
|
const dayjs_en_1 = require("../utils/dayjs-en");
|
|
6
|
-
|
|
10
|
+
const get_date_invervals_1 = require("../utils/get-date-invervals");
|
|
11
|
+
function useDay({ date, datesConfig, dayRef, focusedDate, isDateBlocked, isDateFocused, isDateHovered, isDateInsideRange, isDateSelected, onDateFocus, onDateHover, onDateSelect, preventScroll, unavailableDates, }) {
|
|
12
|
+
var _a;
|
|
13
|
+
const disabledDatesFromConfig = (_a = datesConfig === null || datesConfig === void 0 ? void 0 : datesConfig.filter((config) => config.isDisabled).flatMap((config) => config.dates)) !== null && _a !== void 0 ? _a : [];
|
|
14
|
+
const disabledDates = [...unavailableDates, ...disabledDatesFromConfig];
|
|
7
15
|
const onClick = (0, react_1.useCallback)(() => onDateSelect(date), [date, onDateSelect]);
|
|
8
16
|
const onMouseEnter = (0, react_1.useCallback)(() => onDateHover(date), [date, onDateHover]);
|
|
9
17
|
const disabled = isDateBlocked(date) && !isDateHovered(date);
|
|
@@ -34,17 +42,40 @@ function useDay({ date, dayRef, focusedDate, isDateBlocked, isDateFocused, isDat
|
|
|
34
42
|
}
|
|
35
43
|
}
|
|
36
44
|
}, [date, onDateFocus]);
|
|
45
|
+
const dateIntervals = (0, get_date_invervals_1.getDateIntervals)(disabledDates);
|
|
46
|
+
const _isFirstUnavailableDate = () => {
|
|
47
|
+
return dateIntervals.some((interval) => (0, dayjs_1.default)(interval.start).isSame(date, "day"));
|
|
48
|
+
};
|
|
49
|
+
const _isLastUnavailableDate = () => {
|
|
50
|
+
return dateIntervals.some((interval) => (0, dayjs_1.default)(interval.end).isSame(date, "day"));
|
|
51
|
+
};
|
|
52
|
+
const applicableDatesConfigs = datesConfig === null || datesConfig === void 0 ? void 0 : datesConfig.filter((config) => config.dates.some((configDay) => (0, dayjs_1.default)(configDay).isSame(date, "day")));
|
|
53
|
+
const flags = applicableDatesConfigs === null || applicableDatesConfigs === void 0 ? void 0 : applicableDatesConfigs.reduce((acc, curr) => {
|
|
54
|
+
if (!curr.flag) {
|
|
55
|
+
return acc;
|
|
56
|
+
}
|
|
57
|
+
const intervals = (0, get_date_invervals_1.getDateIntervals)(curr.dates);
|
|
58
|
+
acc.push({
|
|
59
|
+
flag: curr.flag,
|
|
60
|
+
isFirst: intervals.some((interval) => (0, dayjs_1.default)(interval.start).isSame(date, "day")),
|
|
61
|
+
isLast: intervals.some((interval) => (0, dayjs_1.default)(interval.end).isSame(date, "day")),
|
|
62
|
+
});
|
|
63
|
+
return acc;
|
|
64
|
+
}, []);
|
|
37
65
|
return {
|
|
66
|
+
flags: flags !== null && flags !== void 0 ? flags : [],
|
|
38
67
|
disabledDate: disabled,
|
|
68
|
+
isFirstDisabled: _isFirstUnavailableDate(),
|
|
39
69
|
isHovered: isDateHovered(date),
|
|
40
|
-
isSelected: isDateSelected(date),
|
|
41
70
|
isInsideRange: isDateInsideRange ? isDateInsideRange(date) : false,
|
|
71
|
+
isLastDisabled: _isLastUnavailableDate(),
|
|
72
|
+
isSelected: isDateSelected(date),
|
|
73
|
+
isToday,
|
|
42
74
|
isWithinHoverRange: isDateHovered(date),
|
|
43
75
|
onClick: !disabled ? onClick : undefined,
|
|
44
76
|
onKeyDown,
|
|
45
77
|
onMouseEnter,
|
|
46
78
|
tabIndex: focusedDate === null || isDateFocused(date) ? 0 : -1,
|
|
47
|
-
isToday,
|
|
48
79
|
};
|
|
49
80
|
}
|
|
50
81
|
exports.useDay = useDay;
|
package/hooks/use-day.test.js
CHANGED
|
@@ -15,23 +15,78 @@ beforeAll(() => {
|
|
|
15
15
|
test("useDay", () => {
|
|
16
16
|
const { result } = (0, react_hooks_1.renderHook)(() => (0, use_day_1.useDay)({
|
|
17
17
|
date: new Date("2021-09-05"),
|
|
18
|
-
|
|
18
|
+
datesConfig: [],
|
|
19
19
|
focusedDate: null,
|
|
20
|
+
isDateBlocked: () => false,
|
|
21
|
+
isDateFocused: () => false,
|
|
22
|
+
isDateHovered: () => false,
|
|
23
|
+
isDateInsideRange: () => false,
|
|
24
|
+
isDateSelected: () => false,
|
|
20
25
|
onDateFocus: () => undefined,
|
|
26
|
+
onDateHover: () => undefined,
|
|
27
|
+
onDateSelect: () => undefined,
|
|
28
|
+
unavailableDates: [],
|
|
29
|
+
}));
|
|
30
|
+
expect(result.current.tabIndex).toBe(0);
|
|
31
|
+
expect(result.current.disabledDate).toBe(false);
|
|
32
|
+
expect(result.current.isFirstDisabled).toBe(false);
|
|
33
|
+
expect(result.current.isLastDisabled).toBe(false);
|
|
34
|
+
expect(result.current.isHovered).toBe(false);
|
|
35
|
+
expect(result.current.isToday).toBe(false);
|
|
36
|
+
expect(result.current.isSelected).toBe(false);
|
|
37
|
+
expect(result.current.isInsideRange).toBe(false);
|
|
38
|
+
expect(result.current.isWithinHoverRange).toBe(false);
|
|
39
|
+
});
|
|
40
|
+
test("useDay with unavailableDates", () => {
|
|
41
|
+
const { result } = (0, react_hooks_1.renderHook)(() => (0, use_day_1.useDay)({
|
|
42
|
+
date: new Date("2021-09-05"),
|
|
43
|
+
datesConfig: [],
|
|
44
|
+
focusedDate: null,
|
|
45
|
+
isDateBlocked: () => true,
|
|
21
46
|
isDateFocused: () => false,
|
|
22
47
|
isDateHovered: () => false,
|
|
48
|
+
isDateInsideRange: () => false,
|
|
23
49
|
isDateSelected: () => false,
|
|
50
|
+
onDateFocus: () => undefined,
|
|
51
|
+
onDateHover: () => undefined,
|
|
52
|
+
onDateSelect: () => undefined,
|
|
53
|
+
unavailableDates: [new Date("2021-09-05")],
|
|
54
|
+
}));
|
|
55
|
+
expect(result.current.tabIndex).toBe(0);
|
|
56
|
+
expect(result.current.disabledDate).toBe(true);
|
|
57
|
+
expect(result.current.isFirstDisabled).toBe(true);
|
|
58
|
+
expect(result.current.isLastDisabled).toBe(true);
|
|
59
|
+
expect(result.current.isHovered).toBe(false);
|
|
60
|
+
expect(result.current.isToday).toBe(false);
|
|
61
|
+
expect(result.current.isSelected).toBe(false);
|
|
62
|
+
expect(result.current.isInsideRange).toBe(false);
|
|
63
|
+
expect(result.current.isWithinHoverRange).toBe(false);
|
|
64
|
+
});
|
|
65
|
+
test("useDay with datesConfig", () => {
|
|
66
|
+
const { result } = (0, react_hooks_1.renderHook)(() => (0, use_day_1.useDay)({
|
|
67
|
+
date: new Date("2021-09-05"),
|
|
68
|
+
datesConfig: [{ dates: [new Date("2021-09-05")], flag: "custom-classname", isDisabled: true }],
|
|
69
|
+
focusedDate: null,
|
|
70
|
+
isDateBlocked: () => true,
|
|
71
|
+
isDateFocused: () => false,
|
|
72
|
+
isDateHovered: () => false,
|
|
24
73
|
isDateInsideRange: () => false,
|
|
74
|
+
isDateSelected: () => false,
|
|
75
|
+
onDateFocus: () => undefined,
|
|
25
76
|
onDateHover: () => undefined,
|
|
26
77
|
onDateSelect: () => undefined,
|
|
78
|
+
unavailableDates: [],
|
|
27
79
|
}));
|
|
28
80
|
expect(result.current.tabIndex).toBe(0);
|
|
29
|
-
expect(result.current.disabledDate).toBe(
|
|
81
|
+
expect(result.current.disabledDate).toBe(true);
|
|
82
|
+
expect(result.current.isFirstDisabled).toBe(true);
|
|
83
|
+
expect(result.current.isLastDisabled).toBe(true);
|
|
30
84
|
expect(result.current.isHovered).toBe(false);
|
|
31
85
|
expect(result.current.isToday).toBe(false);
|
|
32
86
|
expect(result.current.isSelected).toBe(false);
|
|
33
87
|
expect(result.current.isInsideRange).toBe(false);
|
|
34
88
|
expect(result.current.isWithinHoverRange).toBe(false);
|
|
89
|
+
expect(result.current.flags).toStrictEqual([{ flag: "custom-classname", isFirst: true, isLast: true }]);
|
|
35
90
|
});
|
|
36
91
|
test("actions", () => {
|
|
37
92
|
let hoveredDate = null;
|
|
@@ -41,16 +96,18 @@ test("actions", () => {
|
|
|
41
96
|
const { result: ref } = (0, react_hooks_1.renderHook)(() => (0, react_1.useRef)(null));
|
|
42
97
|
const { result, rerender } = (0, react_hooks_1.renderHook)(() => (0, use_day_1.useDay)({
|
|
43
98
|
date: new Date("2021-09-05"),
|
|
44
|
-
|
|
99
|
+
datesConfig: [],
|
|
100
|
+
dayRef: ref.current,
|
|
45
101
|
focusedDate: null,
|
|
46
|
-
|
|
102
|
+
isDateBlocked: () => false,
|
|
47
103
|
isDateFocused: (date) => (0, dayjs_1.default)(date).isSame(focusedDate, "day"),
|
|
48
104
|
isDateHovered: (date) => (0, dayjs_1.default)(date).isSame(hoveredDate, "day"),
|
|
49
|
-
isDateSelected: (date) => (0, dayjs_1.default)(date).isSame(selectedDate, "day"),
|
|
50
105
|
isDateInsideRange: (date) => (0, dayjs_1.default)(date).isSame(insideRangeDate, "day"),
|
|
106
|
+
isDateSelected: (date) => (0, dayjs_1.default)(date).isSame(selectedDate, "day"),
|
|
107
|
+
onDateFocus: (date) => (focusedDate = date),
|
|
51
108
|
onDateHover: (date) => (hoveredDate = date),
|
|
52
109
|
onDateSelect: (date) => (selectedDate = date),
|
|
53
|
-
|
|
110
|
+
unavailableDates: [new Date("2021-09-05")],
|
|
54
111
|
}));
|
|
55
112
|
// hover
|
|
56
113
|
expect(result.current.isHovered).toBe(false);
|
package/package.json
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const dayjs_1 = __importDefault(require("dayjs"));
|
|
7
|
+
const get_date_invervals_1 = require("./get-date-invervals");
|
|
8
|
+
describe("getDateIntervals", () => {
|
|
9
|
+
it("should return empty array for empty input", () => {
|
|
10
|
+
expect((0, get_date_invervals_1.getDateIntervals)([])).toStrictEqual([]);
|
|
11
|
+
});
|
|
12
|
+
it("should return single date as an interval", () => {
|
|
13
|
+
const date = (0, dayjs_1.default)("2023-10-12").toDate();
|
|
14
|
+
expect((0, get_date_invervals_1.getDateIntervals)([date])).toStrictEqual([{ start: date, end: date }]);
|
|
15
|
+
});
|
|
16
|
+
it("should group contiguous dates into intervals", () => {
|
|
17
|
+
const dates = [
|
|
18
|
+
(0, dayjs_1.default)("2023-10-12").toDate(),
|
|
19
|
+
(0, dayjs_1.default)("2023-10-13").toDate(),
|
|
20
|
+
(0, dayjs_1.default)("2023-10-14").toDate(),
|
|
21
|
+
(0, dayjs_1.default)("2023-10-16").toDate(),
|
|
22
|
+
(0, dayjs_1.default)("2023-10-17").toDate(),
|
|
23
|
+
];
|
|
24
|
+
const expected = [
|
|
25
|
+
{ start: dates[0], end: dates[2] },
|
|
26
|
+
{ start: dates[3], end: dates[4] },
|
|
27
|
+
];
|
|
28
|
+
expect((0, get_date_invervals_1.getDateIntervals)(dates)).toStrictEqual(expected);
|
|
29
|
+
});
|
|
30
|
+
it("should handle non-contiguous dates", () => {
|
|
31
|
+
const dates = [(0, dayjs_1.default)("2023-10-12").toDate(), (0, dayjs_1.default)("2023-10-14").toDate(), (0, dayjs_1.default)("2023-10-16").toDate()];
|
|
32
|
+
const expected = [
|
|
33
|
+
{ start: dates[0], end: dates[0] },
|
|
34
|
+
{ start: dates[1], end: dates[1] },
|
|
35
|
+
{ start: dates[2], end: dates[2] },
|
|
36
|
+
];
|
|
37
|
+
expect((0, get_date_invervals_1.getDateIntervals)(dates)).toStrictEqual(expected);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getDateIntervals = void 0;
|
|
7
|
+
const dayjs_1 = __importDefault(require("dayjs"));
|
|
8
|
+
function getDateIntervals(dates) {
|
|
9
|
+
const sortedDates = dates.slice().sort((a, b) => a.getTime() - b.getTime());
|
|
10
|
+
const intervals = [];
|
|
11
|
+
let currentStart = sortedDates[0];
|
|
12
|
+
let currentEnd = sortedDates[0];
|
|
13
|
+
for (let i = 1; i < sortedDates.length; i++) {
|
|
14
|
+
const currentDate = sortedDates[i];
|
|
15
|
+
const nextDate = (0, dayjs_1.default)(currentEnd).add(1, "day").toDate();
|
|
16
|
+
// If the current date matches the expected next date, it's contiguous
|
|
17
|
+
if ((0, dayjs_1.default)(currentDate).isSame(nextDate, "day")) {
|
|
18
|
+
currentEnd = currentDate;
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
intervals.push({ start: currentStart, end: currentEnd });
|
|
22
|
+
currentStart = currentDate;
|
|
23
|
+
currentEnd = currentDate;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
if (sortedDates[0]) {
|
|
27
|
+
// Push the last interval
|
|
28
|
+
intervals.push({ start: currentStart, end: currentEnd });
|
|
29
|
+
}
|
|
30
|
+
return intervals;
|
|
31
|
+
}
|
|
32
|
+
exports.getDateIntervals = getDateIntervals;
|
package/utils/types.d.ts
CHANGED