@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.
Files changed (48) hide show
  1. package/.eslintrc.js +29 -0
  2. package/.turbo/turbo-build.log +19 -0
  3. package/.turbo/turbo-lint.log +14 -0
  4. package/.turbo/turbo-test.log +261 -0
  5. package/.turbo/turbo-typecheck.log +1 -0
  6. package/CHANGELOG.md +127 -0
  7. package/dist/index.d.mts +679 -0
  8. package/dist/index.d.ts +679 -0
  9. package/dist/index.js +2 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/index.mjs +2 -0
  12. package/dist/index.mjs.map +1 -0
  13. package/package.json +47 -0
  14. package/src/components/Calendar.stories.tsx +226 -0
  15. package/src/components/Calendar.tsx +224 -0
  16. package/src/components/CalendarItemDay.tsx +385 -0
  17. package/src/components/CalendarItemEmpty.tsx +30 -0
  18. package/src/components/CalendarItemWeekName.tsx +67 -0
  19. package/src/components/CalendarList.stories.tsx +326 -0
  20. package/src/components/CalendarList.tsx +373 -0
  21. package/src/components/CalendarRowMonth.tsx +62 -0
  22. package/src/components/CalendarRowWeek.tsx +46 -0
  23. package/src/components/CalendarThemeProvider.tsx +43 -0
  24. package/src/components/HStack.tsx +67 -0
  25. package/src/components/VStack.tsx +67 -0
  26. package/src/components/index.ts +108 -0
  27. package/src/developer/decorators.tsx +54 -0
  28. package/src/developer/loggginHandler.tsx +6 -0
  29. package/src/developer/useRenderCount.ts +7 -0
  30. package/src/helpers/dates.test.ts +567 -0
  31. package/src/helpers/dates.ts +163 -0
  32. package/src/helpers/functions.ts +327 -0
  33. package/src/helpers/numbers.ts +11 -0
  34. package/src/helpers/strings.ts +2 -0
  35. package/src/helpers/tokens.ts +71 -0
  36. package/src/helpers/types.ts +3 -0
  37. package/src/hooks/useCalendar.test.ts +381 -0
  38. package/src/hooks/useCalendar.ts +351 -0
  39. package/src/hooks/useCalendarList.test.ts +382 -0
  40. package/src/hooks/useCalendarList.tsx +291 -0
  41. package/src/hooks/useDateRange.test.ts +128 -0
  42. package/src/hooks/useDateRange.ts +94 -0
  43. package/src/hooks/useOptimizedDayMetadata.test.ts +582 -0
  44. package/src/hooks/useOptimizedDayMetadata.ts +93 -0
  45. package/src/hooks/useTheme.ts +14 -0
  46. package/src/index.ts +24 -0
  47. package/tsconfig.json +13 -0
  48. 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
+ };