@uxf/datepicker 11.111.2 → 11.114.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.
Files changed (55) hide show
  1. package/hooks/use-date-picker-navigation.d.ts +4 -3
  2. package/hooks/use-date-picker-navigation.js +30 -34
  3. package/hooks/use-date-picker-navigation.test.js +40 -4
  4. package/hooks/use-date-picker.js +40 -26
  5. package/hooks/use-date-picker.test.js +2 -2
  6. package/hooks/use-date-range-picker.js +103 -76
  7. package/hooks/use-day.js +12 -11
  8. package/hooks/use-decade.js +9 -8
  9. package/jest.dst.config.js +22 -0
  10. package/jest.dst.global-setup.js +14 -0
  11. package/package.json +9 -4
  12. package/utils/can-select-range.d.ts +6 -5
  13. package/utils/can-select-range.js +7 -19
  14. package/utils/can-select-range.test.js +30 -27
  15. package/utils/date-string.d.ts +34 -0
  16. package/utils/date-string.js +64 -0
  17. package/utils/date-string.test.d.ts +1 -0
  18. package/utils/date-string.test.js +63 -0
  19. package/utils/dayjs-utils.d.ts +0 -1
  20. package/utils/dayjs-utils.js +1 -5
  21. package/utils/dst-robustness.test.d.ts +11 -0
  22. package/utils/dst-robustness.test.js +328 -0
  23. package/utils/get-current-year-month-and-date.js +1 -2
  24. package/utils/get-date-invervals.js +2 -5
  25. package/utils/get-date-month-and-year.js +6 -5
  26. package/utils/get-days.js +12 -9
  27. package/utils/get-each.d.ts +2 -1
  28. package/utils/get-each.js +37 -9
  29. package/utils/get-each.test.js +34 -19
  30. package/utils/get-initial-months.js +3 -6
  31. package/utils/get-months.js +7 -7
  32. package/utils/get-next-active-month.js +6 -10
  33. package/utils/get-weekday-labels.js +4 -2
  34. package/utils/get-years.js +5 -4
  35. package/utils/is-date-blocked.d.ts +7 -6
  36. package/utils/is-date-blocked.js +6 -7
  37. package/utils/is-date-blocked.test.js +108 -11
  38. package/utils/is-date-hovered.d.ts +6 -5
  39. package/utils/is-date-hovered.js +17 -24
  40. package/utils/is-date-hovered.test.js +42 -25
  41. package/utils/is-date-inside-range.d.ts +2 -1
  42. package/utils/is-date-inside-range.js +1 -2
  43. package/utils/is-date-selected.test.js +16 -8
  44. package/utils/is-end-date.d.ts +2 -1
  45. package/utils/is-end-date.js +1 -2
  46. package/utils/is-end-date.test.js +11 -6
  47. package/utils/is-first-or-last-selected-date.d.ts +2 -1
  48. package/utils/is-first-or-last-selected-date.js +1 -3
  49. package/utils/is-first-or-last-selected-date.test.js +9 -6
  50. package/utils/is-in-unavailable-dates.d.ts +2 -1
  51. package/utils/is-in-unavailable-dates.js +1 -2
  52. package/utils/is-in-unavailable-dates.test.js +10 -6
  53. package/utils/is-start-date.d.ts +2 -1
  54. package/utils/is-start-date.js +1 -2
  55. package/utils/is-start-date.test.js +12 -6
@@ -1,11 +1,12 @@
1
+ import { DateString } from "@uxf/core/date";
1
2
  import { Dispatch, SetStateAction } from "react";
2
3
  import { MonthType } from "../utils/types";
3
4
  export interface UseDatePickerNavigationProps {
4
5
  activeMonths: MonthType[];
5
6
  setActiveMonths: Dispatch<SetStateAction<MonthType[]>>;
6
- setFocusedDate: Dispatch<SetStateAction<Date | null>>;
7
- minBookingDate?: Date;
8
- maxBookingDate?: Date;
7
+ setFocusedDate: (date: Date | null) => void;
8
+ minBookingDate?: DateString;
9
+ maxBookingDate?: DateString;
9
10
  numberOfMonths: number;
10
11
  }
11
12
  export interface UseDatePickerNavigationReturnType {
@@ -2,11 +2,12 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.useDatePickerNavigation = useDatePickerNavigation;
4
4
  const react_1 = require("react");
5
- const dayjs_utils_1 = require("../utils/dayjs-utils");
5
+ const create_date_string_1 = require("../utils/create-date-string");
6
+ const date_string_1 = require("../utils/date-string");
6
7
  const get_initial_months_1 = require("../utils/get-initial-months");
7
8
  const get_next_active_month_1 = require("../utils/get-next-active-month");
8
9
  function useDatePickerNavigation({ activeMonths, setActiveMonths, setFocusedDate, minBookingDate, maxBookingDate, numberOfMonths, }) {
9
- var _a, _b, _c, _d;
10
+ var _a, _b;
10
11
  const goToPrevMonths = (0, react_1.useCallback)(() => {
11
12
  const newActiveMonths = (0, get_next_active_month_1.getNextActiveMonth)(activeMonths, numberOfMonths, -1);
12
13
  setActiveMonths(newActiveMonths);
@@ -49,40 +50,35 @@ function useDatePickerNavigation({ activeMonths, setActiveMonths, setFocusedDate
49
50
  setFocusedDate(null);
50
51
  return newActiveMonths;
51
52
  }, [activeMonths, numberOfMonths, setActiveMonths, setFocusedDate]);
52
- const canGoToPrevMonth = minBookingDate
53
- ? !(0, dayjs_utils_1.dayjsEnRaw)((_b = (_a = activeMonths.at(0)) === null || _a === void 0 ? void 0 : _a.date) !== null && _b !== void 0 ? _b : new Date()).isBefore((0, dayjs_utils_1.dayjsEnRaw)(minBookingDate))
54
- : true;
55
- const canGoToNextMonth = maxBookingDate
56
- ? !(0, dayjs_utils_1.dayjsEnWithTz)(activeMonths[activeMonths.length - 1].date)
57
- .endOf("month")
58
- .isAfter((0, dayjs_utils_1.dayjsEnWithTz)(maxBookingDate))
59
- : true;
60
- const canGoToPrevYear = minBookingDate
61
- ? !(0, dayjs_utils_1.dayjsEnWithTz)((_d = (_c = activeMonths.at(0)) === null || _c === void 0 ? void 0 : _c.date) !== null && _d !== void 0 ? _d : new Date())
62
- .subtract(1, "year")
63
- .endOf("year")
64
- .isBefore((0, dayjs_utils_1.dayjsEnRaw)(minBookingDate))
65
- : true;
66
- const canGoToNextYear = maxBookingDate
67
- ? !(0, dayjs_utils_1.dayjsEnWithTz)(activeMonths[activeMonths.length - 1].date)
68
- .add(1, "year")
69
- .startOf("year")
70
- .isAfter((0, dayjs_utils_1.dayjsEnWithTz)(maxBookingDate))
71
- : true;
53
+ const firstMonthStr = (0, date_string_1.toDateString)((_b = (_a = activeMonths.at(0)) === null || _a === void 0 ? void 0 : _a.date) !== null && _b !== void 0 ? _b : new Date());
54
+ const lastMonthStr = (0, date_string_1.toDateString)(activeMonths[activeMonths.length - 1].date);
55
+ const firstYear = parseInt(firstMonthStr.slice(0, 4), 10);
56
+ const lastYear = parseInt(lastMonthStr.slice(0, 4), 10);
57
+ // Can navigate back if the first active month is not before minBookingDate.
58
+ const canGoToPrevMonth = !minBookingDate || minBookingDate <= firstMonthStr;
59
+ // Can navigate forward if the month after the last active month is still within maxBookingDate.
60
+ const canGoToNextMonth = !maxBookingDate || (0, date_string_1.addMonths)(lastMonthStr, 1) <= maxBookingDate;
61
+ // Can navigate back a year if Dec 31 of (firstYear - 1) is still on or after minBookingDate.
62
+ const canGoToPrevYear = !minBookingDate || (0, create_date_string_1.createDateString)(firstYear - 1, 11, 31) >= minBookingDate;
63
+ // Can navigate forward a year if Jan 1 of (lastYear + 1) is still within maxBookingDate.
64
+ const canGoToNextYear = !maxBookingDate || (0, create_date_string_1.createDateString)(lastYear + 1, 0) <= maxBookingDate;
72
65
  const canGoTo = (0, react_1.useCallback)((month, type) => {
73
- if (minBookingDate || maxBookingDate) {
74
- if (minBookingDate && maxBookingDate) {
75
- return ((0, dayjs_utils_1.dayjsEnWithTz)(month).endOf(type).add(1, "day").isAfter(minBookingDate, "day") &&
76
- (0, dayjs_utils_1.dayjsEnWithTz)(month).startOf(type).subtract(1, "day").isBefore(maxBookingDate, "day"));
77
- }
78
- if (minBookingDate) {
79
- return (0, dayjs_utils_1.dayjsEnWithTz)(month).endOf(type).add(1, "day").isAfter(minBookingDate, "day");
80
- }
81
- if (maxBookingDate) {
82
- return (0, dayjs_utils_1.dayjsEnWithTz)(month).startOf(type).subtract(1, "day").isBefore(maxBookingDate, "day");
83
- }
66
+ if (!minBookingDate && !maxBookingDate) {
67
+ return true;
84
68
  }
85
- return true;
69
+ const ds = (0, date_string_1.toDateString)(month);
70
+ const year = parseInt(ds.slice(0, 4), 10);
71
+ if (type === "month") {
72
+ // Month is reachable if its range overlaps [minBookingDate, maxBookingDate].
73
+ // "end of this month + 1 day > min" AND "start of this month - 1 day < max"
74
+ const afterMin = !minBookingDate || (0, date_string_1.addMonths)(ds, 1) > minBookingDate;
75
+ const beforeMax = !maxBookingDate || (0, date_string_1.addDays)(ds, -1) < maxBookingDate;
76
+ return afterMin && beforeMax;
77
+ }
78
+ // type === "year"
79
+ const afterMin = !minBookingDate || (0, create_date_string_1.createDateString)(year + 1, 0) > minBookingDate;
80
+ const beforeMax = !maxBookingDate || (0, create_date_string_1.createDateString)(year - 1, 11, 31) < maxBookingDate;
81
+ return afterMin && beforeMax;
86
82
  }, [maxBookingDate, minBookingDate]);
87
83
  const canGoToMonth = (0, react_1.useCallback)((date) => canGoTo(date, "month"), [canGoTo]);
88
84
  const canGoToYear = (0, react_1.useCallback)((date) => canGoTo(date, "year"), [canGoTo]);
@@ -24,8 +24,8 @@ test("base data with min and max date", () => {
24
24
  setActiveMonths: () => undefined,
25
25
  numberOfMonths: 1,
26
26
  setFocusedDate: () => undefined,
27
- minBookingDate: new Date("2015-05-05"),
28
- maxBookingDate: new Date("2025-10-11"),
27
+ minBookingDate: "2015-05-05",
28
+ maxBookingDate: "2025-10-11",
29
29
  }));
30
30
  expect(result.current.canGoToMonth(new Date("2021-08-01"))).toBe(true);
31
31
  expect(result.current.canGoToMonth(new Date("2015-04-01"))).toBe(false);
@@ -34,6 +34,42 @@ test("base data with min and max date", () => {
34
34
  expect(result.current.canGoToYear(new Date("2014-01-01"))).toBe(false);
35
35
  expect(result.current.canGoToYear(new Date("2026-01-01"))).toBe(false);
36
36
  });
37
+ test("canGoToNextMonth edge cases with maxBookingDate", () => {
38
+ // Active month: September 2021 (lastMonthStr = "2021-09-01")
39
+ // addMonths("2021-09-01", 1) = "2021-10-01"
40
+ // maxBookingDate = 1st of next month ("2021-10-01"):
41
+ // "2021-10-01" <= "2021-10-01" → true → can navigate forward
42
+ // (October has at least one bookable day)
43
+ const { result: result1 } = (0, react_1.renderHook)(() => (0, use_date_picker_navigation_1.useDatePickerNavigation)({
44
+ activeMonths: ACTIVE_MONTHS,
45
+ setActiveMonths: () => undefined,
46
+ numberOfMonths: 1,
47
+ setFocusedDate: () => undefined,
48
+ maxBookingDate: "2021-10-01",
49
+ }));
50
+ expect(result1.current.canGoToNextMonth).toBe(true);
51
+ // maxBookingDate = last day of current month ("2021-09-30"):
52
+ // "2021-10-01" <= "2021-09-30" → false → cannot navigate forward
53
+ // (October is entirely past maxBookingDate)
54
+ const { result: result2 } = (0, react_1.renderHook)(() => (0, use_date_picker_navigation_1.useDatePickerNavigation)({
55
+ activeMonths: ACTIVE_MONTHS,
56
+ setActiveMonths: () => undefined,
57
+ numberOfMonths: 1,
58
+ setFocusedDate: () => undefined,
59
+ maxBookingDate: "2021-09-30",
60
+ }));
61
+ expect(result2.current.canGoToNextMonth).toBe(false);
62
+ // maxBookingDate = mid-next-month ("2021-10-15"):
63
+ // "2021-10-01" <= "2021-10-15" → true → can navigate forward
64
+ const { result: result3 } = (0, react_1.renderHook)(() => (0, use_date_picker_navigation_1.useDatePickerNavigation)({
65
+ activeMonths: ACTIVE_MONTHS,
66
+ setActiveMonths: () => undefined,
67
+ numberOfMonths: 1,
68
+ setFocusedDate: () => undefined,
69
+ maxBookingDate: "2021-10-15",
70
+ }));
71
+ expect(result3.current.canGoToNextMonth).toBe(true);
72
+ });
37
73
  test("actions", () => {
38
74
  const { result: state } = (0, react_1.renderHook)(() => (0, react_2.useState)([{ month: 8, year: 2021, date: new Date("2021-09-01") }]));
39
75
  const { result, rerender } = (0, react_1.renderHook)(() => {
@@ -43,8 +79,8 @@ test("actions", () => {
43
79
  setActiveMonths,
44
80
  numberOfMonths: 1,
45
81
  setFocusedDate: () => undefined,
46
- minBookingDate: new Date("2020-12-25"),
47
- maxBookingDate: new Date("2022-03-11"),
82
+ minBookingDate: "2020-12-25",
83
+ maxBookingDate: "2022-03-11",
48
84
  });
49
85
  });
50
86
  // go to year 2020
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.useDatePicker = useDatePicker;
4
4
  const react_1 = require("react");
5
- const dayjs_utils_1 = require("../utils/dayjs-utils");
5
+ const date_string_1 = require("../utils/date-string");
6
6
  const get_initial_months_1 = require("../utils/get-initial-months");
7
7
  const is_date_blocked_1 = require("../utils/is-date-blocked");
8
8
  const is_date_hovered_1 = require("../utils/is-date-hovered");
@@ -10,38 +10,50 @@ const is_in_unavailable_dates_1 = require("../utils/is-in-unavailable-dates");
10
10
  const is_start_date_1 = require("../utils/is-start-date");
11
11
  const use_date_picker_navigation_1 = require("./use-date-picker-navigation");
12
12
  function useDatePicker({ datesConfig = [], firstDayOfWeek = 0, initialVisibleMonth, isDateBlocked: isDateBlockedProps = () => false, maxBookingDate, minBookingDate, numberOfMonths = 1, onDateChange, preventScroll, selectedDate, unavailableDates = [], }) {
13
+ // --- Normalize all Date inputs to DateString at boundary ---
14
+ const normalizedSelectedDate = selectedDate ? (0, date_string_1.toDateString)(selectedDate) : null;
15
+ const normalizedMinBookingDate = minBookingDate ? (0, date_string_1.toDateString)(minBookingDate) : undefined;
16
+ const normalizedMaxBookingDate = maxBookingDate ? (0, date_string_1.toDateString)(maxBookingDate) : undefined;
13
17
  const disabledDatesFromConfig = datesConfig.filter((config) => config.isDisabled).flatMap((config) => config.dates);
14
- const disabledDates = [...unavailableDates, ...disabledDatesFromConfig];
18
+ const allDisabledDates = [
19
+ ...unavailableDates.map(date_string_1.toDateString),
20
+ ...disabledDatesFromConfig.map(date_string_1.toDateString),
21
+ ];
15
22
  const [activeMonths, setActiveMonths] = (0, react_1.useState)(() => selectedDate
16
23
  ? (0, get_initial_months_1.getInitialMonths)(numberOfMonths, selectedDate)
17
24
  : (0, get_initial_months_1.getInitialMonths)(numberOfMonths, initialVisibleMonth || null));
18
25
  const [hoveredDate, setHoveredDate] = (0, react_1.useState)(null);
19
- const [focusedDate, setFocusedDate] = (0, react_1.useState)(selectedDate);
26
+ const [focusedDate, setFocusedDate] = (0, react_1.useState)(normalizedSelectedDate);
27
+ // Consumer's isDateBlocked callback still receives Date via fromDateString
20
28
  const disabledDatesByUser = (date) => {
21
- return (0, is_in_unavailable_dates_1.isInUnavailableDates)(disabledDates, date) || isDateBlockedProps(date);
29
+ return (0, is_in_unavailable_dates_1.isInUnavailableDates)(allDisabledDates, date) || isDateBlockedProps((0, date_string_1.fromDateString)(date));
22
30
  };
23
31
  const onDateFocus = (0, react_1.useCallback)((date) => {
24
- setFocusedDate(date);
25
- if (!focusedDate || !activeMonths.map((m) => m.month).includes((0, dayjs_utils_1.dayjsEnRaw)(date).month())) {
32
+ const dateStr = (0, date_string_1.toDateString)(date);
33
+ setFocusedDate(dateStr);
34
+ const focusedYYYYMM = (0, date_string_1.toDateString)(date).slice(0, 7);
35
+ if (!focusedDate ||
36
+ !activeMonths.some((m) => `${m.year}-${String(m.month + 1).padStart(2, "0")}` === focusedYYYYMM)) {
26
37
  setActiveMonths((0, get_initial_months_1.getInitialMonths)(numberOfMonths, date));
27
38
  }
28
39
  }, [activeMonths, focusedDate, numberOfMonths]);
29
- const _isDateSelected = (date) => (0, is_start_date_1.isStartDate)(date, selectedDate);
40
+ const _isDateSelected = (date) => (0, is_start_date_1.isStartDate)((0, date_string_1.toDateString)(date), normalizedSelectedDate);
30
41
  const _isDateBlocked = (date) => (0, is_date_blocked_1.isDateBlocked)({
31
- date,
32
- minBookingDate,
33
- maxBookingDate,
34
- startDate: selectedDate,
35
- endDate: selectedDate,
42
+ date: (0, date_string_1.toDateString)(date),
43
+ minBookingDate: normalizedMinBookingDate,
44
+ maxBookingDate: normalizedMaxBookingDate,
45
+ startDate: normalizedSelectedDate,
46
+ endDate: normalizedSelectedDate,
36
47
  minBookingDays: 1,
37
- isDateBlockedFn: disabledDatesByUser,
48
+ isDateBlockedFn: isDateBlockedProps,
49
+ unavailableDates: allDisabledDates,
38
50
  });
39
- const isDateFocused = (date) => (focusedDate ? (0, dayjs_utils_1.dayjsEnRaw)(date).isSame(focusedDate, "day") : false);
51
+ const isDateFocused = (date) => focusedDate !== null && (0, date_string_1.toDateString)(date) === focusedDate;
40
52
  const _isDateHovered = (date) => (0, is_date_hovered_1.isDateHovered)({
41
- date,
53
+ date: (0, date_string_1.toDateString)(date),
42
54
  hoveredDate,
43
- startDate: selectedDate,
44
- endDate: selectedDate,
55
+ startDate: normalizedSelectedDate,
56
+ endDate: normalizedSelectedDate,
45
57
  minBookingDays: 1,
46
58
  exactMinBookingDays: false,
47
59
  isDateBlocked: disabledDatesByUser,
@@ -65,7 +77,8 @@ function useDatePicker({ datesConfig = [], firstDayOfWeek = 0, initialVisibleMon
65
77
  onDateChange(null);
66
78
  }, [onDateChange]);
67
79
  function onDateSelect(date) {
68
- if (!(0, dayjs_utils_1.dayjsEnRaw)(date).isSame(selectedDate)) {
80
+ const dateStr = (0, date_string_1.toDateString)(date);
81
+ if (dateStr !== normalizedSelectedDate) {
69
82
  onDateChange(date);
70
83
  }
71
84
  else {
@@ -77,9 +90,10 @@ function useDatePicker({ datesConfig = [], firstDayOfWeek = 0, initialVisibleMon
77
90
  setHoveredDate(null);
78
91
  }
79
92
  else {
80
- const isNotBlocked = !_isDateBlocked(date) || (selectedDate && (0, dayjs_utils_1.dayjsEnRaw)(date).isSame(selectedDate, "day"));
93
+ const dateStr = (0, date_string_1.toDateString)(date);
94
+ const isNotBlocked = !_isDateBlocked(date) || (normalizedSelectedDate && dateStr === normalizedSelectedDate);
81
95
  if (isNotBlocked) {
82
- setHoveredDate(date);
96
+ setHoveredDate(dateStr);
83
97
  }
84
98
  else if (hoveredDate !== null) {
85
99
  setHoveredDate(null);
@@ -89,17 +103,17 @@ function useDatePicker({ datesConfig = [], firstDayOfWeek = 0, initialVisibleMon
89
103
  return {
90
104
  ...(0, use_date_picker_navigation_1.useDatePickerNavigation)({
91
105
  activeMonths,
92
- maxBookingDate,
93
- minBookingDate,
106
+ maxBookingDate: normalizedMaxBookingDate,
107
+ minBookingDate: normalizedMinBookingDate,
94
108
  numberOfMonths,
95
109
  setActiveMonths,
96
- setFocusedDate,
110
+ setFocusedDate: (date) => setFocusedDate(date ? (0, date_string_1.toDateString)(date) : null),
97
111
  }),
98
112
  activeMonths,
99
113
  datesConfig,
100
114
  firstDayOfWeek,
101
- focusedDate,
102
- hoveredDate,
115
+ focusedDate: focusedDate ? (0, date_string_1.fromDateString)(focusedDate) : null,
116
+ hoveredDate: hoveredDate ? (0, date_string_1.fromDateString)(hoveredDate) : null,
103
117
  isDateBlocked: _isDateBlocked,
104
118
  isDateFocused,
105
119
  isDateHovered: _isDateHovered,
@@ -111,6 +125,6 @@ function useDatePicker({ datesConfig = [], firstDayOfWeek = 0, initialVisibleMon
111
125
  onResetDates: onReset,
112
126
  preventScroll,
113
127
  selectedDate,
114
- unavailableDates: disabledDates,
128
+ unavailableDates: allDisabledDates.map(date_string_1.fromDateString),
115
129
  };
116
130
  }
@@ -4,11 +4,11 @@ const react_1 = require("@testing-library/react");
4
4
  const react_2 = require("react");
5
5
  const use_date_picker_1 = require("./use-date-picker");
6
6
  test("base data", () => {
7
- const BASE_DATE = new Date("2021-09-15T00:00:00+02:00");
7
+ const BASE_DATE = new Date("2021-09-15T00:00:00Z");
8
8
  const { result } = (0, react_1.renderHook)(() => (0, use_date_picker_1.useDatePicker)({
9
9
  selectedDate: BASE_DATE,
10
10
  onDateChange: () => undefined,
11
- minBookingDate: new Date("2020-01-01"),
11
+ minBookingDate: new Date("2020-01-01T00:00:00Z"),
12
12
  }));
13
13
  expect(result.current.firstDayOfWeek).toBe(0);
14
14
  expect(result.current.focusedDate).toStrictEqual(BASE_DATE);
@@ -4,7 +4,7 @@ exports.END_DATE = exports.START_DATE = void 0;
4
4
  exports.useDateRangePicker = useDateRangePicker;
5
5
  const react_1 = require("react");
6
6
  const can_select_range_1 = require("../utils/can-select-range");
7
- const dayjs_utils_1 = require("../utils/dayjs-utils");
7
+ const date_string_1 = require("../utils/date-string");
8
8
  const get_initial_months_1 = require("../utils/get-initial-months");
9
9
  const is_date_blocked_1 = require("../utils/is-date-blocked");
10
10
  const is_date_hovered_1 = require("../utils/is-date-hovered");
@@ -17,44 +17,62 @@ const use_date_picker_navigation_1 = require("./use-date-picker-navigation");
17
17
  exports.START_DATE = "startDate";
18
18
  exports.END_DATE = "endDate";
19
19
  function useDateRangePicker({ changeActiveMonthOnSelect = false, datesConfig = [], endDate, exactMinBookingDays = false, firstDayOfWeek = 0, focusedInput, initialVisibleMonth, isDateBlocked: isDateBlockedProps, maxBookingDate, minBookingDate, minBookingDays = 1, numberOfMonths = 2, onDatesChange, startDate, unavailableDates = [], }) {
20
+ // --- Normalize all Date inputs to DateString at boundary ---
21
+ const normalizedStartDate = startDate ? (0, date_string_1.toDateString)(startDate) : null;
22
+ const normalizedEndDate = endDate ? (0, date_string_1.toDateString)(endDate) : null;
23
+ const normalizedMinBookingDate = minBookingDate ? (0, date_string_1.toDateString)(minBookingDate) : undefined;
24
+ const normalizedMaxBookingDate = maxBookingDate ? (0, date_string_1.toDateString)(maxBookingDate) : undefined;
20
25
  const disabledDatesFromConfig = datesConfig.filter((config) => config.isDisabled).flatMap((config) => config.dates);
21
- const disabledDates = [...unavailableDates, ...disabledDatesFromConfig];
26
+ const allDisabledDates = [
27
+ ...unavailableDates.map(date_string_1.toDateString),
28
+ ...disabledDatesFromConfig.map(date_string_1.toDateString),
29
+ ];
22
30
  const [activeMonths, setActiveMonths] = (0, react_1.useState)(() => startDate
23
31
  ? (0, get_initial_months_1.getInitialMonths)(numberOfMonths, startDate)
24
32
  : (0, get_initial_months_1.getInitialMonths)(numberOfMonths, initialVisibleMonth || null));
25
33
  const [hoveredDate, setHoveredDate] = (0, react_1.useState)(null);
26
- const [focusedDate, setFocusedDate] = (0, react_1.useState)(startDate);
27
- const disabledDatesByUser = isDateBlockedProps || disabledDates.length > 0
34
+ const [focusedDate, setFocusedDate] = (0, react_1.useState)(normalizedStartDate);
35
+ // Consumer's isDateBlockedProps (Date boolean) wrapped as DateString → boolean
36
+ const disabledDatesByUser = isDateBlockedProps || allDisabledDates.length > 0
28
37
  ? (date) => {
29
38
  var _a;
30
- return (0, is_in_unavailable_dates_1.isInUnavailableDates)(disabledDates, date) || ((_a = isDateBlockedProps === null || isDateBlockedProps === void 0 ? void 0 : isDateBlockedProps(date)) !== null && _a !== void 0 ? _a : false);
39
+ return ((0, is_in_unavailable_dates_1.isInUnavailableDates)(allDisabledDates, date) ||
40
+ ((_a = isDateBlockedProps === null || isDateBlockedProps === void 0 ? void 0 : isDateBlockedProps((0, date_string_1.fromDateString)(date))) !== null && _a !== void 0 ? _a : false));
31
41
  }
32
42
  : null;
33
43
  const onDateFocus = (0, react_1.useCallback)((date) => {
34
- setFocusedDate(date);
35
- if (!focusedDate || !activeMonths.map((m) => m.month).includes((0, dayjs_utils_1.dayjsEnRaw)(date).month())) {
44
+ const dateStr = (0, date_string_1.toDateString)(date);
45
+ setFocusedDate(dateStr);
46
+ const focusedYYYYMM = (0, date_string_1.toDateString)(date).slice(0, 7);
47
+ if (!focusedDate ||
48
+ !activeMonths.some((m) => `${m.year}-${String(m.month + 1).padStart(2, "0")}` === focusedYYYYMM)) {
36
49
  setActiveMonths((0, get_initial_months_1.getInitialMonths)(numberOfMonths, date));
37
50
  }
38
51
  }, [activeMonths, focusedDate, numberOfMonths]);
39
- const _isDateSelected = (date) => (0, is_date_inside_range_1.isDateInsideRange)(date, startDate, endDate) || (0, is_first_or_last_selected_date_1.isFirstOrLastSelectedDate)(date, startDate, endDate);
40
- const _isStartDate = (date) => (0, is_start_date_1.isStartDate)(date, startDate);
41
- const _isEndDate = (date) => (0, is_end_date_1.isEndDate)(date, endDate);
42
- const _isDateInsideRange = (date) => (0, is_date_inside_range_1.isDateInsideRange)(date, startDate, endDate);
52
+ const _isDateSelected = (date) => {
53
+ const dateStr = (0, date_string_1.toDateString)(date);
54
+ return ((0, is_date_inside_range_1.isDateInsideRange)(dateStr, normalizedStartDate, normalizedEndDate) ||
55
+ (0, is_first_or_last_selected_date_1.isFirstOrLastSelectedDate)(dateStr, normalizedStartDate, normalizedEndDate));
56
+ };
57
+ const _isStartDate = (date) => (0, is_start_date_1.isStartDate)((0, date_string_1.toDateString)(date), normalizedStartDate);
58
+ const _isEndDate = (date) => (0, is_end_date_1.isEndDate)((0, date_string_1.toDateString)(date), normalizedEndDate);
59
+ const _isDateInsideRange = (date) => (0, is_date_inside_range_1.isDateInsideRange)((0, date_string_1.toDateString)(date), normalizedStartDate, normalizedEndDate);
43
60
  const _isDateBlocked = (date) => (0, is_date_blocked_1.isDateBlocked)({
44
- date,
45
- minBookingDate,
46
- maxBookingDate,
47
- startDate,
48
- endDate,
61
+ date: (0, date_string_1.toDateString)(date),
62
+ minBookingDate: normalizedMinBookingDate,
63
+ maxBookingDate: normalizedMaxBookingDate,
64
+ startDate: normalizedStartDate,
65
+ endDate: normalizedEndDate,
49
66
  minBookingDays,
50
- isDateBlockedFn: disabledDatesByUser,
67
+ isDateBlockedFn: isDateBlockedProps,
68
+ unavailableDates: allDisabledDates,
51
69
  });
52
- const isDateFocused = (date) => (focusedDate ? (0, dayjs_utils_1.dayjsEnRaw)(date).isSame(focusedDate, "day") : false);
70
+ const isDateFocused = (date) => focusedDate !== null && (0, date_string_1.toDateString)(date) === focusedDate;
53
71
  const _isDateHovered = (date) => (0, is_date_hovered_1.isDateHovered)({
54
- date,
72
+ date: (0, date_string_1.toDateString)(date),
55
73
  hoveredDate,
56
- startDate,
57
- endDate,
74
+ startDate: normalizedStartDate,
75
+ endDate: normalizedEndDate,
58
76
  minBookingDays,
59
77
  exactMinBookingDays,
60
78
  isDateBlocked: disabledDatesByUser,
@@ -83,41 +101,45 @@ function useDateRangePicker({ changeActiveMonthOnSelect = false, datesConfig = [
83
101
  }, [onDatesChange]);
84
102
  // eslint-disable-next-line complexity
85
103
  function onDateSelect(date) {
104
+ const dateStr = (0, date_string_1.toDateString)(date);
86
105
  if ((focusedInput === exports.END_DATE || focusedInput === exports.START_DATE) &&
87
106
  minBookingDays > 0 &&
88
107
  exactMinBookingDays &&
89
108
  (0, can_select_range_1.canSelectRange)({
90
109
  minBookingDays,
91
110
  exactMinBookingDays,
92
- minBookingDate,
93
- maxBookingDate,
111
+ minBookingDate: normalizedMinBookingDate,
112
+ maxBookingDate: normalizedMaxBookingDate,
94
113
  isDateBlocked: disabledDatesByUser,
95
- startDate: date,
114
+ startDate: dateStr,
96
115
  endDate: null,
97
116
  })) {
98
117
  onDatesChange({
99
- startDate: date,
100
- endDate: (0, dayjs_utils_1.dayjsEnRaw)(date)
101
- .add(minBookingDays - 1, "day")
102
- .toDate(),
118
+ startDate: (0, date_string_1.fromDateString)(dateStr),
119
+ endDate: (0, date_string_1.fromDateString)((0, date_string_1.addDays)(dateStr, minBookingDays - 1)),
103
120
  focusedInput: null,
104
121
  });
105
122
  }
106
- else if ((((focusedInput === exports.END_DATE && startDate && (0, dayjs_utils_1.dayjsEnRaw)(date).isBefore(startDate)) ||
107
- (focusedInput === exports.START_DATE && endDate && (0, dayjs_utils_1.dayjsEnRaw)(date).isAfter(endDate))) &&
123
+ else if ((((focusedInput === exports.END_DATE && normalizedStartDate && dateStr < normalizedStartDate) ||
124
+ (focusedInput === exports.START_DATE && normalizedEndDate && dateStr > normalizedEndDate)) &&
108
125
  !exactMinBookingDays &&
109
126
  (0, can_select_range_1.canSelectRange)({
110
127
  minBookingDays,
111
128
  isDateBlocked: disabledDatesByUser,
112
- startDate: date,
129
+ startDate: dateStr,
113
130
  endDate: null,
114
131
  })) ||
115
132
  (focusedInput === exports.START_DATE &&
116
133
  !exactMinBookingDays &&
117
- (0, can_select_range_1.canSelectRange)({ minBookingDays, isDateBlocked: disabledDatesByUser, endDate, startDate: date }))) {
134
+ (0, can_select_range_1.canSelectRange)({
135
+ minBookingDays,
136
+ isDateBlocked: disabledDatesByUser,
137
+ endDate: normalizedEndDate,
138
+ startDate: dateStr,
139
+ }))) {
118
140
  onDatesChange({
119
141
  endDate: null,
120
- startDate: date,
142
+ startDate: (0, date_string_1.fromDateString)(dateStr),
121
143
  focusedInput: exports.END_DATE,
122
144
  });
123
145
  }
@@ -127,51 +149,58 @@ function useDateRangePicker({ changeActiveMonthOnSelect = false, datesConfig = [
127
149
  minBookingDays,
128
150
  isDateBlocked: disabledDatesByUser,
129
151
  endDate: null,
130
- startDate: date,
152
+ startDate: dateStr,
131
153
  })) {
132
154
  onDatesChange({
133
155
  endDate: null,
134
- startDate: date,
156
+ startDate: (0, date_string_1.fromDateString)(dateStr),
135
157
  focusedInput: exports.END_DATE,
136
158
  });
137
159
  }
138
160
  else if (focusedInput === exports.END_DATE &&
139
- startDate &&
140
- !(0, dayjs_utils_1.dayjsEnRaw)(date).isBefore(startDate) &&
161
+ normalizedStartDate &&
162
+ dateStr >= normalizedStartDate &&
141
163
  !exactMinBookingDays &&
142
- (0, can_select_range_1.canSelectRange)({ minBookingDays, isDateBlocked: disabledDatesByUser, startDate, endDate: date })) {
164
+ (0, can_select_range_1.canSelectRange)({
165
+ minBookingDays,
166
+ isDateBlocked: disabledDatesByUser,
167
+ startDate: normalizedStartDate,
168
+ endDate: dateStr,
169
+ })) {
143
170
  onDatesChange({
144
- startDate,
145
- endDate: date,
171
+ startDate: (0, date_string_1.fromDateString)(normalizedStartDate),
172
+ endDate: (0, date_string_1.fromDateString)(dateStr),
146
173
  focusedInput: null,
147
174
  });
148
175
  }
149
176
  if (focusedInput !== exports.END_DATE &&
150
- (!focusedDate || !(0, dayjs_utils_1.dayjsEnRaw)(date).isSame(focusedDate, "month")) &&
177
+ (!focusedDate || dateStr.slice(0, 7) !== focusedDate.slice(0, 7)) &&
151
178
  changeActiveMonthOnSelect) {
152
- setActiveMonths((0, get_initial_months_1.getInitialMonths)(numberOfMonths, date));
179
+ setActiveMonths((0, get_initial_months_1.getInitialMonths)(numberOfMonths, (0, date_string_1.fromDateString)(dateStr)));
153
180
  }
154
181
  }
155
182
  function onDatesSelect(start, end) {
183
+ const startStr = (0, date_string_1.toDateString)(start);
184
+ const endStr = end ? (0, date_string_1.toDateString)(end) : null;
156
185
  if ((0, can_select_range_1.canSelectRange)({
157
186
  minBookingDays,
158
187
  exactMinBookingDays,
159
- minBookingDate,
160
- maxBookingDate,
188
+ minBookingDate: normalizedMinBookingDate,
189
+ maxBookingDate: normalizedMaxBookingDate,
161
190
  isDateBlocked: disabledDatesByUser,
162
- startDate: start,
163
- endDate: end,
191
+ startDate: startStr,
192
+ endDate: endStr,
164
193
  })) {
165
194
  onDatesChange({
166
- endDate: end,
167
- startDate: start,
195
+ endDate: endStr ? (0, date_string_1.fromDateString)(endStr) : null,
196
+ startDate: (0, date_string_1.fromDateString)(startStr),
168
197
  focusedInput: exports.START_DATE,
169
198
  });
170
199
  }
171
200
  if (focusedInput !== exports.END_DATE &&
172
- (!focusedDate || !(0, dayjs_utils_1.dayjsEnRaw)(start).isSame(focusedDate, "month")) &&
201
+ (!focusedDate || startStr.slice(0, 7) !== focusedDate.slice(0, 7)) &&
173
202
  changeActiveMonthOnSelect) {
174
- setActiveMonths((0, get_initial_months_1.getInitialMonths)(numberOfMonths, start));
203
+ setActiveMonths((0, get_initial_months_1.getInitialMonths)(numberOfMonths, (0, date_string_1.fromDateString)(startStr)));
175
204
  }
176
205
  }
177
206
  // eslint-disable-next-line complexity
@@ -180,20 +209,20 @@ function useDateRangePicker({ changeActiveMonthOnSelect = false, datesConfig = [
180
209
  setHoveredDate(null);
181
210
  }
182
211
  else {
183
- const isNotBlocked = !_isDateBlocked(date) || (startDate && (0, dayjs_utils_1.dayjsEnRaw)(date).isSame(startDate, "day"));
184
- const isHoveredDateAfterOrEqualMinDate = minBookingDate
185
- ? !(0, dayjs_utils_1.dayjsEnRaw)(date).isBefore((0, dayjs_utils_1.dayjsEnRaw)(minBookingDate).subtract(1, "day"))
212
+ const dateStr = (0, date_string_1.toDateString)(date);
213
+ const isNotBlocked = !_isDateBlocked(date) || (normalizedStartDate && dateStr === normalizedStartDate);
214
+ const isHoveredDateAfterOrEqualMinDate = normalizedMinBookingDate
215
+ ? dateStr >= (0, date_string_1.addDays)(normalizedMinBookingDate, -1)
186
216
  : true;
187
- const isHoveredDateBeforeOrEqualMaxDate = maxBookingDate ? !(0, dayjs_utils_1.dayjsEnRaw)(date).isAfter(maxBookingDate) : true;
188
- // Exact minimal booking days
189
- const potentialEndDate = (0, dayjs_utils_1.dayjsEnRaw)(date)
190
- .add(minBookingDays - 1, "day")
191
- .toDate();
192
- const isPotentialEndDateAfterOrEqualMinDate = minBookingDate
193
- ? !(0, dayjs_utils_1.dayjsEnRaw)(potentialEndDate).isBefore(minBookingDate)
217
+ const isHoveredDateBeforeOrEqualMaxDate = normalizedMaxBookingDate
218
+ ? dateStr <= normalizedMaxBookingDate
194
219
  : true;
195
- const isPotentialEndDateBeforeOrEqualMaxDate = maxBookingDate
196
- ? !(0, dayjs_utils_1.dayjsEnRaw)(potentialEndDate).isAfter(maxBookingDate)
220
+ const potentialEndDateStr = (0, date_string_1.addDays)(dateStr, minBookingDays - 1);
221
+ const isPotentialEndDateAfterOrEqualMinDate = normalizedMinBookingDate
222
+ ? potentialEndDateStr >= normalizedMinBookingDate
223
+ : true;
224
+ const isPotentialEndDateBeforeOrEqualMaxDate = normalizedMaxBookingDate
225
+ ? potentialEndDateStr <= normalizedMaxBookingDate
197
226
  : true;
198
227
  const isExactAndInRange = exactMinBookingDays &&
199
228
  minBookingDays > 1 &&
@@ -201,19 +230,17 @@ function useDateRangePicker({ changeActiveMonthOnSelect = false, datesConfig = [
201
230
  isHoveredDateBeforeOrEqualMaxDate &&
202
231
  isPotentialEndDateAfterOrEqualMinDate &&
203
232
  isPotentialEndDateBeforeOrEqualMaxDate;
204
- // Is date in range
205
- const isInRange = startDate &&
206
- !endDate &&
233
+ const isInRange = normalizedStartDate &&
234
+ !normalizedEndDate &&
207
235
  !exactMinBookingDays &&
208
236
  isHoveredDateAfterOrEqualMinDate &&
209
237
  isHoveredDateBeforeOrEqualMaxDate;
210
- // Is start date hovered and in range
211
- const isMinBookingDaysInRange = minBookingDays > 1 && startDate
212
- ? (0, dayjs_utils_1.dayjsEnRaw)(date).isBetween(startDate, (0, dayjs_utils_1.dayjsEnRaw)(startDate).add(minBookingDays - 2, "day"))
238
+ const isMinBookingDaysInRange = minBookingDays > 1 && normalizedStartDate
239
+ ? dateStr > normalizedStartDate && dateStr < (0, date_string_1.addDays)(normalizedStartDate, minBookingDays - 2)
213
240
  : true;
214
- const isStartDateHoveredAndInRange = startDate && (0, dayjs_utils_1.dayjsEnRaw)(date).isSame(startDate, "day") && isMinBookingDaysInRange;
241
+ const isStartDateHoveredAndInRange = normalizedStartDate && dateStr === normalizedStartDate && isMinBookingDaysInRange;
215
242
  if (isNotBlocked && (isExactAndInRange || isInRange || isStartDateHoveredAndInRange)) {
216
- setHoveredDate(date);
243
+ setHoveredDate(dateStr);
217
244
  }
218
245
  else if (hoveredDate !== null) {
219
246
  setHoveredDate(null);
@@ -223,17 +250,17 @@ function useDateRangePicker({ changeActiveMonthOnSelect = false, datesConfig = [
223
250
  return {
224
251
  ...(0, use_date_picker_navigation_1.useDatePickerNavigation)({
225
252
  activeMonths,
226
- maxBookingDate,
227
- minBookingDate,
253
+ maxBookingDate: normalizedMaxBookingDate,
254
+ minBookingDate: normalizedMinBookingDate,
228
255
  numberOfMonths,
229
256
  setActiveMonths,
230
- setFocusedDate,
257
+ setFocusedDate: (d) => setFocusedDate(d ? (0, date_string_1.toDateString)(d) : null),
231
258
  }),
232
259
  activeMonths,
233
260
  datesConfig,
234
261
  firstDayOfWeek,
235
- focusedDate,
236
- hoveredDate,
262
+ focusedDate: focusedDate ? (0, date_string_1.fromDateString)(focusedDate) : null,
263
+ hoveredDate: hoveredDate ? (0, date_string_1.fromDateString)(hoveredDate) : null,
237
264
  isDateBlocked: _isDateBlocked,
238
265
  isDateFocused,
239
266
  isDateHovered: _isDateHovered,
@@ -247,6 +274,6 @@ function useDateRangePicker({ changeActiveMonthOnSelect = false, datesConfig = [
247
274
  onDateSelect,
248
275
  onDatesSelect,
249
276
  onResetDates,
250
- unavailableDates: disabledDates,
277
+ unavailableDates: allDisabledDates.map(date_string_1.fromDateString),
251
278
  };
252
279
  }