@lazerlen/legend-calendar 1.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/.eslintrc.js +29 -0
- package/.turbo/turbo-build.log +19 -0
- package/.turbo/turbo-lint.log +14 -0
- package/.turbo/turbo-test.log +261 -0
- package/.turbo/turbo-typecheck.log +1 -0
- package/CHANGELOG.md +127 -0
- package/dist/index.d.mts +679 -0
- package/dist/index.d.ts +679 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +47 -0
- package/src/components/Calendar.stories.tsx +226 -0
- package/src/components/Calendar.tsx +224 -0
- package/src/components/CalendarItemDay.tsx +385 -0
- package/src/components/CalendarItemEmpty.tsx +30 -0
- package/src/components/CalendarItemWeekName.tsx +67 -0
- package/src/components/CalendarList.stories.tsx +326 -0
- package/src/components/CalendarList.tsx +373 -0
- package/src/components/CalendarRowMonth.tsx +62 -0
- package/src/components/CalendarRowWeek.tsx +46 -0
- package/src/components/CalendarThemeProvider.tsx +43 -0
- package/src/components/HStack.tsx +67 -0
- package/src/components/VStack.tsx +67 -0
- package/src/components/index.ts +108 -0
- package/src/developer/decorators.tsx +54 -0
- package/src/developer/loggginHandler.tsx +6 -0
- package/src/developer/useRenderCount.ts +7 -0
- package/src/helpers/dates.test.ts +567 -0
- package/src/helpers/dates.ts +163 -0
- package/src/helpers/functions.ts +327 -0
- package/src/helpers/numbers.ts +11 -0
- package/src/helpers/strings.ts +2 -0
- package/src/helpers/tokens.ts +71 -0
- package/src/helpers/types.ts +3 -0
- package/src/hooks/useCalendar.test.ts +381 -0
- package/src/hooks/useCalendar.ts +351 -0
- package/src/hooks/useCalendarList.test.ts +382 -0
- package/src/hooks/useCalendarList.tsx +291 -0
- package/src/hooks/useDateRange.test.ts +128 -0
- package/src/hooks/useDateRange.ts +94 -0
- package/src/hooks/useOptimizedDayMetadata.test.ts +582 -0
- package/src/hooks/useOptimizedDayMetadata.ts +93 -0
- package/src/hooks/useTheme.ts +14 -0
- package/src/index.ts +24 -0
- package/tsconfig.json +13 -0
- package/tsup.config.ts +15 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { renderHook, act } from "@testing-library/react-hooks";
|
|
2
|
+
import { describe, it, expect } from "bun:test";
|
|
3
|
+
|
|
4
|
+
import { useDateRange } from "./useDateRange"; // replace with the actual path to your hook
|
|
5
|
+
|
|
6
|
+
describe("useDateRange", () => {
|
|
7
|
+
it("should initialize with correct default values", () => {
|
|
8
|
+
const { result } = renderHook(() => useDateRange());
|
|
9
|
+
|
|
10
|
+
expect(result.current.dateRange).toEqual({
|
|
11
|
+
startId: undefined,
|
|
12
|
+
endId: undefined,
|
|
13
|
+
});
|
|
14
|
+
expect(result.current.calendarActiveDateRanges).toEqual([]);
|
|
15
|
+
expect(result.current.isDateRangeValid).toBe(false);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("should update dateRange correctly on onCalendarDayPress", () => {
|
|
19
|
+
const { result } = renderHook(() => useDateRange());
|
|
20
|
+
|
|
21
|
+
// Sets the start date
|
|
22
|
+
act(() => {
|
|
23
|
+
result.current.onCalendarDayPress("2022-01-01");
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
expect(result.current.dateRange).toEqual({
|
|
27
|
+
startId: "2022-01-01",
|
|
28
|
+
endId: undefined,
|
|
29
|
+
});
|
|
30
|
+
expect(result.current.calendarActiveDateRanges).toEqual([
|
|
31
|
+
{ startId: "2022-01-01", endId: undefined },
|
|
32
|
+
]);
|
|
33
|
+
|
|
34
|
+
// Sets the end date
|
|
35
|
+
act(() => {
|
|
36
|
+
result.current.onCalendarDayPress("2022-01-10");
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
expect(result.current.dateRange).toEqual({
|
|
40
|
+
startId: "2022-01-01",
|
|
41
|
+
endId: "2022-01-10",
|
|
42
|
+
});
|
|
43
|
+
expect(result.current.calendarActiveDateRanges).toEqual([
|
|
44
|
+
{ startId: "2022-01-01", endId: "2022-01-10" },
|
|
45
|
+
]);
|
|
46
|
+
|
|
47
|
+
// Sets a new start date
|
|
48
|
+
act(() => {
|
|
49
|
+
result.current.onCalendarDayPress("2024-02-16");
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
expect(result.current.dateRange).toEqual({
|
|
53
|
+
startId: "2024-02-16",
|
|
54
|
+
endId: undefined,
|
|
55
|
+
});
|
|
56
|
+
expect(result.current.calendarActiveDateRanges).toEqual([
|
|
57
|
+
{ startId: "2024-02-16", endId: undefined },
|
|
58
|
+
]);
|
|
59
|
+
|
|
60
|
+
// Sets an earlier end date, which should swap the start and end dates
|
|
61
|
+
act(() => {
|
|
62
|
+
result.current.onCalendarDayPress("2024-02-01");
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
expect(result.current.dateRange).toEqual({
|
|
66
|
+
startId: "2024-02-01",
|
|
67
|
+
endId: "2024-02-16",
|
|
68
|
+
});
|
|
69
|
+
expect(result.current.calendarActiveDateRanges).toEqual([
|
|
70
|
+
{ startId: "2024-02-01", endId: "2024-02-16" },
|
|
71
|
+
]);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("should clear dateRange on onClearDateRange", () => {
|
|
75
|
+
const { result } = renderHook(() => useDateRange());
|
|
76
|
+
|
|
77
|
+
act(() => {
|
|
78
|
+
result.current.onCalendarDayPress("2022-01-01");
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
act(() => {
|
|
82
|
+
result.current.onCalendarDayPress("2022-01-10");
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
act(() => {
|
|
86
|
+
result.current.onClearDateRange();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
expect(result.current.dateRange).toEqual({
|
|
90
|
+
startId: undefined,
|
|
91
|
+
endId: undefined,
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("should update isDateRangeValid correctly", () => {
|
|
96
|
+
const { result } = renderHook(() => useDateRange());
|
|
97
|
+
expect(result.current.isDateRangeValid).toBe(false);
|
|
98
|
+
|
|
99
|
+
act(() => {
|
|
100
|
+
result.current.onCalendarDayPress("2022-01-01");
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
expect(result.current.isDateRangeValid).toBe(false);
|
|
104
|
+
|
|
105
|
+
act(() => {
|
|
106
|
+
result.current.onCalendarDayPress("2022-01-10");
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
expect(result.current.isDateRangeValid).toBe(true);
|
|
110
|
+
|
|
111
|
+
act(() => {
|
|
112
|
+
result.current.onClearDateRange();
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
expect(result.current.isDateRangeValid).toBe(false);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it("can initialize a date range", () => {
|
|
119
|
+
const { result } = renderHook(() =>
|
|
120
|
+
useDateRange({ startId: "2022-01-01", endId: "2022-01-10" })
|
|
121
|
+
);
|
|
122
|
+
expect(result.current.dateRange).toEqual({
|
|
123
|
+
startId: "2022-01-01",
|
|
124
|
+
endId: "2022-01-10",
|
|
125
|
+
});
|
|
126
|
+
expect(result.current.isDateRangeValid).toBe(true);
|
|
127
|
+
});
|
|
128
|
+
});
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { useCallback, useMemo, useState } from "react";
|
|
2
|
+
|
|
3
|
+
import type { CalendarOnDayPress } from "@/components";
|
|
4
|
+
import type { CalendarActiveDateRange } from "@/hooks/useCalendar";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A convenience hook to simplify managing a date range in the calendar in a
|
|
8
|
+
* performant way.
|
|
9
|
+
*/
|
|
10
|
+
export const useDateRange = (
|
|
11
|
+
initialDateRange: CalendarActiveDateRange = {
|
|
12
|
+
startId: undefined,
|
|
13
|
+
endId: undefined,
|
|
14
|
+
}
|
|
15
|
+
) => {
|
|
16
|
+
const [dateRange, setDateRange] =
|
|
17
|
+
useState<CalendarActiveDateRange>(initialDateRange);
|
|
18
|
+
|
|
19
|
+
const onCalendarDayPress = useCallback<CalendarOnDayPress>(
|
|
20
|
+
(dateId: string) => {
|
|
21
|
+
setDateRange((prev) => {
|
|
22
|
+
// Starting the first range
|
|
23
|
+
if (!prev.startId && !prev.endId) {
|
|
24
|
+
return {
|
|
25
|
+
startId: dateId,
|
|
26
|
+
endId: undefined,
|
|
27
|
+
};
|
|
28
|
+
} else if (prev.startId && prev.endId) {
|
|
29
|
+
// Starting a new range
|
|
30
|
+
return {
|
|
31
|
+
startId: dateId,
|
|
32
|
+
endId: undefined,
|
|
33
|
+
};
|
|
34
|
+
} else if (prev.startId && !prev.endId) {
|
|
35
|
+
if (dateId < prev.startId) {
|
|
36
|
+
return {
|
|
37
|
+
startId: dateId,
|
|
38
|
+
endId: prev.startId,
|
|
39
|
+
};
|
|
40
|
+
} else {
|
|
41
|
+
return {
|
|
42
|
+
...prev,
|
|
43
|
+
endId: dateId,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
startId: dateId,
|
|
49
|
+
endId: dateId,
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
},
|
|
53
|
+
[]
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const onClearDateRange = useCallback(() => {
|
|
57
|
+
setDateRange({
|
|
58
|
+
startId: undefined,
|
|
59
|
+
endId: undefined,
|
|
60
|
+
});
|
|
61
|
+
}, []);
|
|
62
|
+
|
|
63
|
+
return useMemo(() => {
|
|
64
|
+
const calendarActiveDateRanges =
|
|
65
|
+
!dateRange.startId && !dateRange.endId ? [] : [dateRange];
|
|
66
|
+
const isDateRangeValid = !!(dateRange.startId && dateRange.endId);
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
/**
|
|
70
|
+
* The current date range.
|
|
71
|
+
**/
|
|
72
|
+
dateRange,
|
|
73
|
+
/**
|
|
74
|
+
* Derived from the current date range as a convenience when passing to
|
|
75
|
+
* the `<Calendar.List />` component.
|
|
76
|
+
*/
|
|
77
|
+
calendarActiveDateRanges,
|
|
78
|
+
/**
|
|
79
|
+
* Clears the current date range.
|
|
80
|
+
*/
|
|
81
|
+
onClearDateRange,
|
|
82
|
+
/**
|
|
83
|
+
* Callback to pass to the `<Calendar.List />` component to handle date
|
|
84
|
+
* range.
|
|
85
|
+
*/
|
|
86
|
+
onCalendarDayPress,
|
|
87
|
+
/**
|
|
88
|
+
* Whether the current date range is valid (e.g. has both start and end
|
|
89
|
+
* dates)
|
|
90
|
+
*/
|
|
91
|
+
isDateRangeValid,
|
|
92
|
+
};
|
|
93
|
+
}, [dateRange, onCalendarDayPress, onClearDateRange]);
|
|
94
|
+
};
|