@particle-academy/react-fancy 5.55.0 → 5.56.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/CHANGELOG.md +27 -0
- package/dist/calendar.cjs +2 -2
- package/dist/calendar.d.cts +30 -1
- package/dist/calendar.d.ts +30 -1
- package/dist/calendar.js +1 -1
- package/dist/{chunk-UET6D7B3.cjs → chunk-CQ7QXZLR.cjs} +45 -26
- package/dist/chunk-CQ7QXZLR.cjs.map +1 -0
- package/dist/{chunk-HVND2IIB.js → chunk-X2A3NAJW.js} +45 -26
- package/dist/chunk-X2A3NAJW.js.map +1 -0
- package/dist/index.cjs +2 -2
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/docs/Calendar.md +37 -0
- package/package.json +1 -1
- package/dist/chunk-HVND2IIB.js.map +0 -1
- package/dist/chunk-UET6D7B3.cjs.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
11
11
|
|
|
12
12
|
## [Unreleased]
|
|
13
13
|
|
|
14
|
+
## [5.56.0] - 2026-10-21
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- **`Calendar` per-day hooks and a controlled visible month.** All additive:
|
|
19
|
+
**nothing to do** for an existing Calendar, which renders and behaves as
|
|
20
|
+
before, plus new data attributes.
|
|
21
|
+
- Every day cell carries a stable id, `data-react-fancy-calendar-day`,
|
|
22
|
+
`YYYY-MM-DD` in local time by default (`dateId` replaces it). Leading and
|
|
23
|
+
trailing days carry `data-outside-month`; the heading carries
|
|
24
|
+
`data-react-fancy-calendar-month`.
|
|
25
|
+
- `renderDay(ctx)` draws a day's content, `dayClassName(ctx)` adds classes
|
|
26
|
+
to one day, `dayAriaLabel(ctx)` sets its accessible name. `ctx` is
|
|
27
|
+
`{ date, id, selected, disabled, inRange, outsideMonth, today }`, exported
|
|
28
|
+
as `CalendarDayContext`. A day shaded with `dayClassName` should get a
|
|
29
|
+
`dayAriaLabel` too: colour alone does not reach a screen reader.
|
|
30
|
+
- `visibleMonth` / `onVisibleMonthChange`: the shown month is controlled when
|
|
31
|
+
`visibleMonth` is given (the chevrons propose, the host decides);
|
|
32
|
+
uncontrolled it starts at today as before, and still reports each move.
|
|
33
|
+
The callback gets the 1st of the month.
|
|
34
|
+
- Opening a day on click is the existing `onChange` (single mode).
|
|
35
|
+
- Verified in Chrome in light, `.dark` and `[data-theme="dark"]`.
|
|
36
|
+
|
|
37
|
+
The requester's wording was `month` / `onMonthChange`. The names here follow
|
|
38
|
+
the spec (`visibleMonth` / `onVisibleMonthChange`), because `value` is already
|
|
39
|
+
a date and a bare `month` reads as the selected one.
|
|
40
|
+
|
|
14
41
|
## [5.55.0] - 2026-10-21
|
|
15
42
|
|
|
16
43
|
### Added
|
package/dist/calendar.cjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkCQ7QXZLR_cjs = require('./chunk-CQ7QXZLR.cjs');
|
|
4
4
|
require('./chunk-ZU5Q77OT.cjs');
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
Object.defineProperty(exports, "Calendar", {
|
|
9
9
|
enumerable: true,
|
|
10
|
-
get: function () { return
|
|
10
|
+
get: function () { return chunkCQ7QXZLR_cjs.Calendar; }
|
|
11
11
|
});
|
|
12
12
|
//# sourceMappingURL=calendar.cjs.map
|
|
13
13
|
//# sourceMappingURL=calendar.cjs.map
|
package/dist/calendar.d.cts
CHANGED
|
@@ -1,10 +1,24 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
2
3
|
|
|
3
4
|
type CalendarMode = "single" | "range" | "multiple";
|
|
4
5
|
interface DateRange {
|
|
5
6
|
start: Date | null;
|
|
6
7
|
end: Date | null;
|
|
7
8
|
}
|
|
9
|
+
/** Everything a per-day hook needs to know about one day cell. */
|
|
10
|
+
interface CalendarDayContext {
|
|
11
|
+
date: Date;
|
|
12
|
+
/** Stable id: `dateId(date)`, default `YYYY-MM-DD` in local time. Also on the cell as `data-react-fancy-calendar-day`. */
|
|
13
|
+
id: string;
|
|
14
|
+
selected: boolean;
|
|
15
|
+
disabled: boolean;
|
|
16
|
+
/** Strictly between a range's ends (range mode). */
|
|
17
|
+
inRange: boolean;
|
|
18
|
+
/** A leading/trailing day from the neighbouring month. */
|
|
19
|
+
outsideMonth: boolean;
|
|
20
|
+
today: boolean;
|
|
21
|
+
}
|
|
8
22
|
interface CalendarProps {
|
|
9
23
|
mode?: CalendarMode;
|
|
10
24
|
value?: Date | Date[] | DateRange | null;
|
|
@@ -13,8 +27,23 @@ interface CalendarProps {
|
|
|
13
27
|
maxDate?: Date;
|
|
14
28
|
disabledDates?: Date[];
|
|
15
29
|
className?: string;
|
|
30
|
+
/** Stable id per day. Default `YYYY-MM-DD` in local time. */
|
|
31
|
+
dateId?: (date: Date) => string;
|
|
32
|
+
/** The day cell's content. Default: the day number. The cell (button, click, state classes) stays the Calendar's. */
|
|
33
|
+
renderDay?: (ctx: CalendarDayContext) => ReactNode;
|
|
34
|
+
/** Extra classes for one day cell, merged after the built-in ones. */
|
|
35
|
+
dayClassName?: (ctx: CalendarDayContext) => string | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* The day cell's accessible name. Pair it with `dayClassName`: a shaded day
|
|
38
|
+
* must say what the shade means. It REPLACES the name, so include the date.
|
|
39
|
+
*/
|
|
40
|
+
dayAriaLabel?: (ctx: CalendarDayContext) => string | undefined;
|
|
41
|
+
/** Controlled visible month (any day in it). Uncontrolled when omitted; starts at today. */
|
|
42
|
+
visibleMonth?: Date;
|
|
43
|
+
/** Called with the 1st of the month navigated to, controlled or not. */
|
|
44
|
+
onVisibleMonthChange?: (month: Date) => void;
|
|
16
45
|
}
|
|
17
46
|
|
|
18
47
|
declare const Calendar: react.ForwardRefExoticComponent<CalendarProps & react.RefAttributes<HTMLDivElement>>;
|
|
19
48
|
|
|
20
|
-
export { Calendar, type CalendarMode, type CalendarProps, type DateRange };
|
|
49
|
+
export { Calendar, type CalendarDayContext, type CalendarMode, type CalendarProps, type DateRange };
|
package/dist/calendar.d.ts
CHANGED
|
@@ -1,10 +1,24 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
2
3
|
|
|
3
4
|
type CalendarMode = "single" | "range" | "multiple";
|
|
4
5
|
interface DateRange {
|
|
5
6
|
start: Date | null;
|
|
6
7
|
end: Date | null;
|
|
7
8
|
}
|
|
9
|
+
/** Everything a per-day hook needs to know about one day cell. */
|
|
10
|
+
interface CalendarDayContext {
|
|
11
|
+
date: Date;
|
|
12
|
+
/** Stable id: `dateId(date)`, default `YYYY-MM-DD` in local time. Also on the cell as `data-react-fancy-calendar-day`. */
|
|
13
|
+
id: string;
|
|
14
|
+
selected: boolean;
|
|
15
|
+
disabled: boolean;
|
|
16
|
+
/** Strictly between a range's ends (range mode). */
|
|
17
|
+
inRange: boolean;
|
|
18
|
+
/** A leading/trailing day from the neighbouring month. */
|
|
19
|
+
outsideMonth: boolean;
|
|
20
|
+
today: boolean;
|
|
21
|
+
}
|
|
8
22
|
interface CalendarProps {
|
|
9
23
|
mode?: CalendarMode;
|
|
10
24
|
value?: Date | Date[] | DateRange | null;
|
|
@@ -13,8 +27,23 @@ interface CalendarProps {
|
|
|
13
27
|
maxDate?: Date;
|
|
14
28
|
disabledDates?: Date[];
|
|
15
29
|
className?: string;
|
|
30
|
+
/** Stable id per day. Default `YYYY-MM-DD` in local time. */
|
|
31
|
+
dateId?: (date: Date) => string;
|
|
32
|
+
/** The day cell's content. Default: the day number. The cell (button, click, state classes) stays the Calendar's. */
|
|
33
|
+
renderDay?: (ctx: CalendarDayContext) => ReactNode;
|
|
34
|
+
/** Extra classes for one day cell, merged after the built-in ones. */
|
|
35
|
+
dayClassName?: (ctx: CalendarDayContext) => string | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* The day cell's accessible name. Pair it with `dayClassName`: a shaded day
|
|
38
|
+
* must say what the shade means. It REPLACES the name, so include the date.
|
|
39
|
+
*/
|
|
40
|
+
dayAriaLabel?: (ctx: CalendarDayContext) => string | undefined;
|
|
41
|
+
/** Controlled visible month (any day in it). Uncontrolled when omitted; starts at today. */
|
|
42
|
+
visibleMonth?: Date;
|
|
43
|
+
/** Called with the 1st of the month navigated to, controlled or not. */
|
|
44
|
+
onVisibleMonthChange?: (month: Date) => void;
|
|
16
45
|
}
|
|
17
46
|
|
|
18
47
|
declare const Calendar: react.ForwardRefExoticComponent<CalendarProps & react.RefAttributes<HTMLDivElement>>;
|
|
19
48
|
|
|
20
|
-
export { Calendar, type CalendarMode, type CalendarProps, type DateRange };
|
|
49
|
+
export { Calendar, type CalendarDayContext, type CalendarMode, type CalendarProps, type DateRange };
|
package/dist/calendar.js
CHANGED
|
@@ -23,6 +23,10 @@ var MONTHS = [
|
|
|
23
23
|
function isSameDay(a, b) {
|
|
24
24
|
return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
|
|
25
25
|
}
|
|
26
|
+
var pad2 = (n) => n < 10 ? `0${n}` : String(n);
|
|
27
|
+
function defaultDateId(date) {
|
|
28
|
+
return `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())}`;
|
|
29
|
+
}
|
|
26
30
|
function getDaysInMonth(year, month) {
|
|
27
31
|
const days = [];
|
|
28
32
|
const firstDay = new Date(year, month, 1);
|
|
@@ -47,34 +51,36 @@ var Calendar = react.forwardRef(
|
|
|
47
51
|
minDate,
|
|
48
52
|
maxDate,
|
|
49
53
|
disabledDates = [],
|
|
50
|
-
className
|
|
54
|
+
className,
|
|
55
|
+
dateId = defaultDateId,
|
|
56
|
+
renderDay,
|
|
57
|
+
dayClassName,
|
|
58
|
+
dayAriaLabel,
|
|
59
|
+
visibleMonth,
|
|
60
|
+
onVisibleMonthChange
|
|
51
61
|
}, ref) {
|
|
52
62
|
const today = react.useMemo(() => /* @__PURE__ */ new Date(), []);
|
|
53
|
-
const [
|
|
54
|
-
|
|
63
|
+
const [innerMonth, setInnerMonth] = react.useState(
|
|
64
|
+
() => new Date(today.getFullYear(), today.getMonth(), 1)
|
|
65
|
+
);
|
|
55
66
|
const [rangeHover, setRangeHover] = react.useState(null);
|
|
67
|
+
const shown = visibleMonth ?? innerMonth;
|
|
68
|
+
const viewMonth = shown.getMonth();
|
|
69
|
+
const viewYear = shown.getFullYear();
|
|
56
70
|
const days = react.useMemo(
|
|
57
71
|
() => getDaysInMonth(viewYear, viewMonth),
|
|
58
72
|
[viewYear, viewMonth]
|
|
59
73
|
);
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
const nextMonth = react.useCallback(() =>
|
|
70
|
-
setViewMonth((m) => {
|
|
71
|
-
if (m === 11) {
|
|
72
|
-
setViewYear((y) => y + 1);
|
|
73
|
-
return 0;
|
|
74
|
-
}
|
|
75
|
-
return m + 1;
|
|
76
|
-
});
|
|
77
|
-
}, []);
|
|
74
|
+
const goToMonth = react.useCallback(
|
|
75
|
+
(delta) => {
|
|
76
|
+
const next = new Date(viewYear, viewMonth + delta, 1);
|
|
77
|
+
if (visibleMonth === void 0) setInnerMonth(next);
|
|
78
|
+
onVisibleMonthChange?.(next);
|
|
79
|
+
},
|
|
80
|
+
[viewYear, viewMonth, visibleMonth, onVisibleMonthChange]
|
|
81
|
+
);
|
|
82
|
+
const prevMonth = react.useCallback(() => goToMonth(-1), [goToMonth]);
|
|
83
|
+
const nextMonth = react.useCallback(() => goToMonth(1), [goToMonth]);
|
|
78
84
|
const isDisabled = react.useCallback(
|
|
79
85
|
(date) => {
|
|
80
86
|
if (minDate && date < minDate) return true;
|
|
@@ -161,7 +167,7 @@ var Calendar = react.forwardRef(
|
|
|
161
167
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { size: 16 })
|
|
162
168
|
}
|
|
163
169
|
),
|
|
164
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm font-semibold", children: [
|
|
170
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm font-semibold", "data-react-fancy-calendar-month": "", children: [
|
|
165
171
|
MONTHS[viewMonth],
|
|
166
172
|
" ",
|
|
167
173
|
viewYear
|
|
@@ -191,11 +197,23 @@ var Calendar = react.forwardRef(
|
|
|
191
197
|
const inRange = isInRange(date);
|
|
192
198
|
const disabled = isDisabled(date);
|
|
193
199
|
const isToday = isSameDay(date, today);
|
|
200
|
+
const ctx = {
|
|
201
|
+
date,
|
|
202
|
+
id: dateId(date),
|
|
203
|
+
selected,
|
|
204
|
+
disabled,
|
|
205
|
+
inRange,
|
|
206
|
+
outsideMonth: !isCurrentMonth,
|
|
207
|
+
today: isToday
|
|
208
|
+
};
|
|
194
209
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
195
210
|
"button",
|
|
196
211
|
{
|
|
197
212
|
type: "button",
|
|
198
213
|
disabled,
|
|
214
|
+
"data-react-fancy-calendar-day": ctx.id,
|
|
215
|
+
"data-outside-month": isCurrentMonth ? void 0 : "",
|
|
216
|
+
"aria-label": dayAriaLabel?.(ctx) || void 0,
|
|
199
217
|
onClick: () => handleSelect(date),
|
|
200
218
|
onMouseEnter: () => mode === "range" && setRangeHover(date),
|
|
201
219
|
className: chunkZU5Q77OT_cjs.cn(
|
|
@@ -205,9 +223,10 @@ var Calendar = react.forwardRef(
|
|
|
205
223
|
inRange && "bg-blue-50 text-blue-700 dark:bg-blue-950 dark:text-blue-300",
|
|
206
224
|
selected && "bg-zinc-900 text-white dark:bg-white dark:text-zinc-900",
|
|
207
225
|
isToday && !selected && "font-bold",
|
|
208
|
-
disabled && "cursor-not-allowed opacity-30"
|
|
226
|
+
disabled && "cursor-not-allowed opacity-30",
|
|
227
|
+
dayClassName?.(ctx)
|
|
209
228
|
),
|
|
210
|
-
children: date.getDate()
|
|
229
|
+
children: renderDay ? renderDay(ctx) : date.getDate()
|
|
211
230
|
},
|
|
212
231
|
i
|
|
213
232
|
);
|
|
@@ -220,5 +239,5 @@ var Calendar = react.forwardRef(
|
|
|
220
239
|
Calendar.displayName = "Calendar";
|
|
221
240
|
|
|
222
241
|
exports.Calendar = Calendar;
|
|
223
|
-
//# sourceMappingURL=chunk-
|
|
224
|
-
//# sourceMappingURL=chunk-
|
|
242
|
+
//# sourceMappingURL=chunk-CQ7QXZLR.cjs.map
|
|
243
|
+
//# sourceMappingURL=chunk-CQ7QXZLR.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/Calendar/Calendar.tsx"],"names":["forwardRef","Calendar","useMemo","useState","useCallback","jsxs","cn","jsx","ChevronLeft","ChevronRight"],"mappings":";;;;;;;AAKA,IAAM,IAAA,GAAO,CAAC,IAAA,EAAM,IAAA,EAAM,MAAM,IAAA,EAAM,IAAA,EAAM,MAAM,IAAI,CAAA;AACtD,IAAM,MAAA,GAAS;AAAA,EACb,SAAA;AAAA,EAAW,UAAA;AAAA,EAAY,OAAA;AAAA,EAAS,OAAA;AAAA,EAAS,KAAA;AAAA,EAAO,MAAA;AAAA,EAChD,MAAA;AAAA,EAAQ,QAAA;AAAA,EAAU,WAAA;AAAA,EAAa,SAAA;AAAA,EAAW,UAAA;AAAA,EAAY;AACxD,CAAA;AAEA,SAAS,SAAA,CAAU,GAAS,CAAA,EAAkB;AAC5C,EAAA,OACE,EAAE,WAAA,EAAY,KAAM,CAAA,CAAE,WAAA,MACtB,CAAA,CAAE,QAAA,EAAS,KAAM,CAAA,CAAE,UAAS,IAC5B,CAAA,CAAE,OAAA,EAAQ,KAAM,EAAE,OAAA,EAAQ;AAE9B;AAEA,IAAM,IAAA,GAAO,CAAC,CAAA,KAAe,CAAA,GAAI,KAAK,CAAA,CAAA,EAAI,CAAC,CAAA,CAAA,GAAK,MAAA,CAAO,CAAC,CAAA;AAGxD,SAAS,cAAc,IAAA,EAAoB;AACzC,EAAA,OAAO,GAAG,IAAA,CAAK,WAAA,EAAa,CAAA,CAAA,EAAI,KAAK,IAAA,CAAK,QAAA,EAAS,GAAI,CAAC,CAAC,CAAA,CAAA,EAAI,IAAA,CAAK,IAAA,CAAK,OAAA,EAAS,CAAC,CAAA,CAAA;AACnF;AAEA,SAAS,cAAA,CAAe,MAAc,KAAA,EAAuB;AAC3D,EAAA,MAAM,OAAe,EAAC;AACtB,EAAA,MAAM,QAAA,GAAW,IAAI,IAAA,CAAK,IAAA,EAAM,OAAO,CAAC,CAAA;AACxC,EAAA,MAAM,cAAA,GAAiB,SAAS,MAAA,EAAO;AAGvC,EAAA,KAAA,IAAS,CAAA,GAAI,cAAA,GAAiB,CAAA,EAAG,CAAA,IAAK,GAAG,CAAA,EAAA,EAAK;AAC5C,IAAA,IAAA,CAAK,KAAK,IAAI,IAAA,CAAK,MAAM,KAAA,EAAO,CAAC,CAAC,CAAC,CAAA;AAAA,EACrC;AAGA,EAAA,MAAM,QAAA,GAAW,IAAI,IAAA,CAAK,IAAA,EAAM,QAAQ,CAAA,EAAG,CAAC,EAAE,OAAA,EAAQ;AACtD,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,IAAK,QAAA,EAAU,CAAA,EAAA,EAAK;AAClC,IAAA,IAAA,CAAK,KAAK,IAAI,IAAA,CAAK,IAAA,EAAM,KAAA,EAAO,CAAC,CAAC,CAAA;AAAA,EACpC;AAGA,EAAA,OAAO,IAAA,CAAK,SAAS,EAAA,EAAI;AACvB,IAAA,IAAA,CAAK,IAAA,CAAK,IAAI,IAAA,CAAK,IAAA,EAAM,KAAA,GAAQ,CAAA,EAAG,IAAA,CAAK,MAAA,GAAS,cAAA,GAAiB,QAAA,GAAW,CAAC,CAAC,CAAA;AAAA,EAClF;AAEA,EAAA,OAAO,IAAA;AACT;AAEO,IAAM,QAAA,GAAWA,gBAAA;AAAA,EACtB,SAASC,SAAAA,CACP;AAAA,IACE,IAAA,GAAO,QAAA;AAAA,IACP,KAAA;AAAA,IACA,QAAA;AAAA,IACA,OAAA;AAAA,IACA,OAAA;AAAA,IACA,gBAAgB,EAAC;AAAA,IACjB,SAAA;AAAA,IACA,MAAA,GAAS,aAAA;AAAA,IACT,SAAA;AAAA,IACA,YAAA;AAAA,IACA,YAAA;AAAA,IACA,YAAA;AAAA,IACA;AAAA,KAEF,GAAA,EACA;AACA,IAAA,MAAM,QAAQC,aAAA,CAAQ,0BAAU,IAAA,EAAK,EAAG,EAAE,CAAA;AAC1C,IAAA,MAAM,CAAC,UAAA,EAAY,aAAa,CAAA,GAAIC,cAAA;AAAA,MAClC,MAAM,IAAI,IAAA,CAAK,KAAA,CAAM,aAAY,EAAG,KAAA,CAAM,QAAA,EAAS,EAAG,CAAC;AAAA,KACzD;AACA,IAAA,MAAM,CAAC,UAAA,EAAY,aAAa,CAAA,GAAIA,eAAsB,IAAI,CAAA;AAE9D,IAAA,MAAM,QAAQ,YAAA,IAAgB,UAAA;AAC9B,IAAA,MAAM,SAAA,GAAY,MAAM,QAAA,EAAS;AACjC,IAAA,MAAM,QAAA,GAAW,MAAM,WAAA,EAAY;AAEnC,IAAA,MAAM,IAAA,GAAOD,aAAA;AAAA,MACX,MAAM,cAAA,CAAe,QAAA,EAAU,SAAS,CAAA;AAAA,MACxC,CAAC,UAAU,SAAS;AAAA,KACtB;AAEA,IAAA,MAAM,SAAA,GAAYE,iBAAA;AAAA,MAChB,CAAC,KAAA,KAAkB;AACjB,QAAA,MAAM,OAAO,IAAI,IAAA,CAAK,QAAA,EAAU,SAAA,GAAY,OAAO,CAAC,CAAA;AACpD,QAAA,IAAI,YAAA,KAAiB,MAAA,EAAW,aAAA,CAAc,IAAI,CAAA;AAClD,QAAA,oBAAA,GAAuB,IAAI,CAAA;AAAA,MAC7B,CAAA;AAAA,MACA,CAAC,QAAA,EAAU,SAAA,EAAW,YAAA,EAAc,oBAAoB;AAAA,KAC1D;AACA,IAAA,MAAM,SAAA,GAAYA,kBAAY,MAAM,SAAA,CAAU,EAAE,CAAA,EAAG,CAAC,SAAS,CAAC,CAAA;AAC9D,IAAA,MAAM,SAAA,GAAYA,kBAAY,MAAM,SAAA,CAAU,CAAC,CAAA,EAAG,CAAC,SAAS,CAAC,CAAA;AAE7D,IAAA,MAAM,UAAA,GAAaA,iBAAA;AAAA,MACjB,CAAC,IAAA,KAAwB;AACvB,QAAA,IAAI,OAAA,IAAW,IAAA,GAAO,OAAA,EAAS,OAAO,IAAA;AACtC,QAAA,IAAI,OAAA,IAAW,IAAA,GAAO,OAAA,EAAS,OAAO,IAAA;AACtC,QAAA,OAAO,cAAc,IAAA,CAAK,CAAC,MAAM,SAAA,CAAU,CAAA,EAAG,IAAI,CAAC,CAAA;AAAA,MACrD,CAAA;AAAA,MACA,CAAC,OAAA,EAAS,OAAA,EAAS,aAAa;AAAA,KAClC;AAEA,IAAA,MAAM,UAAA,GAAaA,iBAAA;AAAA,MACjB,CAAC,IAAA,KAAwB;AACvB,QAAA,IAAI,CAAC,OAAO,OAAO,KAAA;AACnB,QAAA,IAAI,IAAA,KAAS,QAAA,IAAY,KAAA,YAAiB,IAAA,EAAM;AAC9C,UAAA,OAAO,SAAA,CAAU,MAAM,KAAK,CAAA;AAAA,QAC9B;AACA,QAAA,IAAI,IAAA,KAAS,UAAA,IAAc,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AAC/C,UAAA,OAAO,MAAM,IAAA,CAAK,CAAC,MAAM,SAAA,CAAU,IAAA,EAAM,CAAC,CAAC,CAAA;AAAA,QAC7C;AACA,QAAA,IAAI,SAAS,OAAA,IAAW,KAAA,IAAS,OAAO,KAAA,KAAU,QAAA,IAAY,WAAW,KAAA,EAAO;AAC9E,UAAA,MAAM,KAAA,GAAQ,KAAA;AACd,UAAA,IAAI,MAAM,KAAA,IAAS,SAAA,CAAU,MAAM,KAAA,CAAM,KAAK,GAAG,OAAO,IAAA;AACxD,UAAA,IAAI,MAAM,GAAA,IAAO,SAAA,CAAU,MAAM,KAAA,CAAM,GAAG,GAAG,OAAO,IAAA;AAAA,QACtD;AACA,QAAA,OAAO,KAAA;AAAA,MACT,CAAA;AAAA,MACA,CAAC,OAAO,IAAI;AAAA,KACd;AAEA,IAAA,MAAM,SAAA,GAAYA,iBAAA;AAAA,MAChB,CAAC,IAAA,KAAwB;AACvB,QAAA,IAAI,IAAA,KAAS,WAAW,CAAC,KAAA,IAAS,OAAO,KAAA,KAAU,QAAA,IAAY,EAAE,OAAA,IAAW,KAAA,CAAA;AAC1E,UAAA,OAAO,KAAA;AACT,QAAA,MAAM,KAAA,GAAQ,KAAA;AACd,QAAA,IAAI,CAAC,KAAA,CAAM,KAAA,EAAO,OAAO,KAAA;AACzB,QAAA,MAAM,GAAA,GAAM,MAAM,GAAA,IAAO,UAAA;AACzB,QAAA,IAAI,CAAC,KAAK,OAAO,KAAA;AACjB,QAAA,MAAM,CAAC,CAAA,EAAG,CAAC,CAAA,GAAI,MAAM,KAAA,IAAS,GAAA,GAAM,CAAC,KAAA,CAAM,OAAO,GAAG,CAAA,GAAI,CAAC,GAAA,EAAK,MAAM,KAAK,CAAA;AAC1E,QAAA,OAAO,IAAA,GAAO,KAAK,IAAA,GAAO,CAAA;AAAA,MAC5B,CAAA;AAAA,MACA,CAAC,KAAA,EAAO,IAAA,EAAM,UAAU;AAAA,KAC1B;AAEA,IAAA,MAAM,YAAA,GAAeA,iBAAA;AAAA,MACnB,CAAC,IAAA,KAAe;AACd,QAAA,IAAI,UAAA,CAAW,IAAI,CAAA,EAAG;AAEtB,QAAA,IAAI,SAAS,QAAA,EAAU;AACrB,UAAA,QAAA,GAAW,IAAI,CAAA;AAAA,QACjB,CAAA,MAAA,IAAW,SAAS,UAAA,EAAY;AAC9B,UAAA,MAAM,MAAO,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,GAAI,QAAQ,EAAC;AAC7C,UAAA,MAAM,MAAA,GAAS,IAAI,SAAA,CAAU,CAAC,MAAM,SAAA,CAAU,CAAA,EAAG,IAAI,CAAC,CAAA;AACtD,UAAA,IAAI,UAAU,CAAA,EAAG;AACf,YAAA,QAAA,GAAW,IAAI,MAAA,CAAO,CAAC,GAAG,CAAA,KAAM,CAAA,KAAM,MAAM,CAAC,CAAA;AAAA,UAC/C,CAAA,MAAO;AACL,YAAA,QAAA,GAAW,CAAC,GAAG,GAAA,EAAK,IAAI,CAAC,CAAA;AAAA,UAC3B;AAAA,QACF,CAAA,MAAA,IAAW,SAAS,OAAA,EAAS;AAC3B,UAAA,MAAM,KAAA,GAAS,KAAA,IAAS,OAAO,KAAA,KAAU,QAAA,IAAY,OAAA,IAAW,KAAA,GAC5D,KAAA,GACA,EAAE,KAAA,EAAO,IAAA,EAAM,GAAA,EAAK,IAAA,EAAK;AAE7B,UAAA,IAAI,CAAC,KAAA,CAAM,KAAA,IAAS,KAAA,CAAM,GAAA,EAAK;AAC7B,YAAA,QAAA,GAAW,EAAE,KAAA,EAAO,IAAA,EAAM,GAAA,EAAK,MAAM,CAAA;AAAA,UACvC,CAAA,MAAO;AACL,YAAA,MAAM,CAAC,CAAA,EAAG,CAAC,CAAA,GACT,QAAQ,KAAA,CAAM,KAAA,GAAQ,CAAC,KAAA,CAAM,OAAO,IAAI,CAAA,GAAI,CAAC,IAAA,EAAM,MAAM,KAAK,CAAA;AAChE,YAAA,QAAA,GAAW,EAAE,KAAA,EAAO,CAAA,EAAG,GAAA,EAAK,GAAG,CAAA;AAAA,UACjC;AAAA,QACF;AAAA,MACF,CAAA;AAAA,MACA,CAAC,IAAA,EAAM,KAAA,EAAO,QAAA,EAAU,UAAU;AAAA,KACpC;AAEA,IAAA,MAAM,OAAA,GACJ,+EAAA;AAEF,IAAA,uBACEC,eAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,2BAAA,EAA0B,EAAA;AAAA,QAC1B,GAAA;AAAA,QACA,SAAA,EAAWC,oBAAA;AAAA,UACT,wRAAA;AAAA,UACA;AAAA,SACF;AAAA,QAGA,QAAA,EAAA;AAAA,0BAAAD,eAAA,CAAC,KAAA,EAAA,EAAI,WAAU,wCAAA,EACb,QAAA,EAAA;AAAA,4BAAAE,cAAA;AAAA,cAAC,QAAA;AAAA,cAAA;AAAA,gBACC,IAAA,EAAK,QAAA;AAAA,gBACL,OAAA,EAAS,SAAA;AAAA,gBACT,SAAA,EAAU,4KAAA;AAAA,gBACV,YAAA,EAAW,gBAAA;AAAA,gBAEX,QAAA,kBAAAA,cAAA,CAACC,uBAAA,EAAA,EAAY,IAAA,EAAM,EAAA,EAAI;AAAA;AAAA,aACzB;AAAA,4BACAH,eAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,uBAAA,EAAwB,mCAAgC,EAAA,EACrE,QAAA,EAAA;AAAA,cAAA,MAAA,CAAO,SAAS,CAAA;AAAA,cAAE,GAAA;AAAA,cAAE;AAAA,aAAA,EACvB,CAAA;AAAA,4BACAE,cAAA;AAAA,cAAC,QAAA;AAAA,cAAA;AAAA,gBACC,IAAA,EAAK,QAAA;AAAA,gBACL,OAAA,EAAS,SAAA;AAAA,gBACT,SAAA,EAAU,4KAAA;AAAA,gBACV,YAAA,EAAW,YAAA;AAAA,gBAEX,QAAA,kBAAAA,cAAA,CAACE,wBAAA,EAAA,EAAa,IAAA,EAAM,EAAA,EAAI;AAAA;AAAA;AAC1B,WAAA,EACF,CAAA;AAAA,yCAGC,KAAA,EAAA,EAAI,SAAA,EAAU,+BACZ,QAAA,EAAA,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,qBACTF,cAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cAEC,SAAA,EAAU,wEAAA;AAAA,cAET,QAAA,EAAA;AAAA,aAAA;AAAA,YAHI;AAAA,WAKR,CAAA,EACH,CAAA;AAAA,0BAGAA,cAAA,CAAC,SAAI,SAAA,EAAU,wBAAA,EACZ,eAAK,GAAA,CAAI,CAAC,MAAM,CAAA,KAAM;AACrB,YAAA,MAAM,cAAA,GAAiB,IAAA,CAAK,QAAA,EAAS,KAAM,SAAA;AAC3C,YAAA,MAAM,QAAA,GAAW,WAAW,IAAI,CAAA;AAChC,YAAA,MAAM,OAAA,GAAU,UAAU,IAAI,CAAA;AAC9B,YAAA,MAAM,QAAA,GAAW,WAAW,IAAI,CAAA;AAChC,YAAA,MAAM,OAAA,GAAU,SAAA,CAAU,IAAA,EAAM,KAAK,CAAA;AACrC,YAAA,MAAM,GAAA,GAA0B;AAAA,cAC9B,IAAA;AAAA,cACA,EAAA,EAAI,OAAO,IAAI,CAAA;AAAA,cACf,QAAA;AAAA,cACA,QAAA;AAAA,cACA,OAAA;AAAA,cACA,cAAc,CAAC,cAAA;AAAA,cACf,KAAA,EAAO;AAAA,aACT;AAEA,YAAA,uBACEA,cAAA;AAAA,cAAC,QAAA;AAAA,cAAA;AAAA,gBAEC,IAAA,EAAK,QAAA;AAAA,gBACL,QAAA;AAAA,gBACA,iCAA+B,GAAA,CAAI,EAAA;AAAA,gBACnC,oBAAA,EAAoB,iBAAiB,MAAA,GAAY,EAAA;AAAA,gBACjD,YAAA,EAAY,YAAA,GAAe,GAAG,CAAA,IAAK,MAAA;AAAA,gBACnC,OAAA,EAAS,MAAM,YAAA,CAAa,IAAI,CAAA;AAAA,gBAChC,YAAA,EAAc,MACZ,IAAA,KAAS,OAAA,IAAW,cAAc,IAAI,CAAA;AAAA,gBAExC,SAAA,EAAWD,oBAAA;AAAA,kBACT,OAAA;AAAA,kBACA,CAAC,cAAA,IAAkB,kCAAA;AAAA,kBACnB,cAAA,IACE,CAAC,QAAA,IACD,CAAC,OAAA,IACD,6QAAA;AAAA,kBACF,OAAA,IACE,8DAAA;AAAA,kBACF,QAAA,IACE,yDAAA;AAAA,kBACF,OAAA,IAAW,CAAC,QAAA,IAAY,WAAA;AAAA,kBACxB,QAAA,IAAY,+BAAA;AAAA,kBACZ,eAAe,GAAG;AAAA,iBACpB;AAAA,gBAEC,QAAA,EAAA,SAAA,GAAY,SAAA,CAAU,GAAG,CAAA,GAAI,KAAK,OAAA;AAAQ,eAAA;AAAA,cA1BtC;AAAA,aA2BP;AAAA,UAEJ,CAAC,CAAA,EACH;AAAA;AAAA;AAAA,KACF;AAAA,EAEJ;AACF;AAEA,QAAA,CAAS,WAAA,GAAc,UAAA","file":"chunk-CQ7QXZLR.cjs","sourcesContent":["import { forwardRef, useCallback, useMemo, useState } from \"react\";\nimport { ChevronLeft, ChevronRight } from \"lucide-react\";\nimport { cn } from \"../../utils/cn\";\nimport type { CalendarDayContext, CalendarProps, DateRange } from \"./Calendar.types\";\n\nconst DAYS = [\"Su\", \"Mo\", \"Tu\", \"We\", \"Th\", \"Fr\", \"Sa\"];\nconst MONTHS = [\n \"January\", \"February\", \"March\", \"April\", \"May\", \"June\",\n \"July\", \"August\", \"September\", \"October\", \"November\", \"December\",\n];\n\nfunction isSameDay(a: Date, b: Date): boolean {\n return (\n a.getFullYear() === b.getFullYear() &&\n a.getMonth() === b.getMonth() &&\n a.getDate() === b.getDate()\n );\n}\n\nconst pad2 = (n: number) => (n < 10 ? `0${n}` : String(n));\n\n/** `YYYY-MM-DD` in LOCAL time — never `toISOString()`, which shifts the day east of UTC. */\nfunction defaultDateId(date: Date): string {\n return `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())}`;\n}\n\nfunction getDaysInMonth(year: number, month: number): Date[] {\n const days: Date[] = [];\n const firstDay = new Date(year, month, 1);\n const startDayOfWeek = firstDay.getDay();\n\n // Fill leading days from previous month\n for (let i = startDayOfWeek - 1; i >= 0; i--) {\n days.push(new Date(year, month, -i));\n }\n\n // Fill current month\n const lastDate = new Date(year, month + 1, 0).getDate();\n for (let d = 1; d <= lastDate; d++) {\n days.push(new Date(year, month, d));\n }\n\n // Fill trailing days to complete 6 rows\n while (days.length < 42) {\n days.push(new Date(year, month + 1, days.length - startDayOfWeek - lastDate + 1));\n }\n\n return days;\n}\n\nexport const Calendar = forwardRef<HTMLDivElement, CalendarProps>(\n function Calendar(\n {\n mode = \"single\",\n value,\n onChange,\n minDate,\n maxDate,\n disabledDates = [],\n className,\n dateId = defaultDateId,\n renderDay,\n dayClassName,\n dayAriaLabel,\n visibleMonth,\n onVisibleMonthChange,\n },\n ref,\n ) {\n const today = useMemo(() => new Date(), []);\n const [innerMonth, setInnerMonth] = useState(\n () => new Date(today.getFullYear(), today.getMonth(), 1),\n );\n const [rangeHover, setRangeHover] = useState<Date | null>(null);\n\n const shown = visibleMonth ?? innerMonth;\n const viewMonth = shown.getMonth();\n const viewYear = shown.getFullYear();\n\n const days = useMemo(\n () => getDaysInMonth(viewYear, viewMonth),\n [viewYear, viewMonth],\n );\n\n const goToMonth = useCallback(\n (delta: number) => {\n const next = new Date(viewYear, viewMonth + delta, 1);\n if (visibleMonth === undefined) setInnerMonth(next);\n onVisibleMonthChange?.(next);\n },\n [viewYear, viewMonth, visibleMonth, onVisibleMonthChange],\n );\n const prevMonth = useCallback(() => goToMonth(-1), [goToMonth]);\n const nextMonth = useCallback(() => goToMonth(1), [goToMonth]);\n\n const isDisabled = useCallback(\n (date: Date): boolean => {\n if (minDate && date < minDate) return true;\n if (maxDate && date > maxDate) return true;\n return disabledDates.some((d) => isSameDay(d, date));\n },\n [minDate, maxDate, disabledDates],\n );\n\n const isSelected = useCallback(\n (date: Date): boolean => {\n if (!value) return false;\n if (mode === \"single\" && value instanceof Date) {\n return isSameDay(date, value);\n }\n if (mode === \"multiple\" && Array.isArray(value)) {\n return value.some((v) => isSameDay(date, v));\n }\n if (mode === \"range\" && value && typeof value === \"object\" && \"start\" in value) {\n const range = value as DateRange;\n if (range.start && isSameDay(date, range.start)) return true;\n if (range.end && isSameDay(date, range.end)) return true;\n }\n return false;\n },\n [value, mode],\n );\n\n const isInRange = useCallback(\n (date: Date): boolean => {\n if (mode !== \"range\" || !value || typeof value !== \"object\" || !(\"start\" in value))\n return false;\n const range = value as DateRange;\n if (!range.start) return false;\n const end = range.end ?? rangeHover;\n if (!end) return false;\n const [s, e] = range.start <= end ? [range.start, end] : [end, range.start];\n return date > s && date < e;\n },\n [value, mode, rangeHover],\n );\n\n const handleSelect = useCallback(\n (date: Date) => {\n if (isDisabled(date)) return;\n\n if (mode === \"single\") {\n onChange?.(date);\n } else if (mode === \"multiple\") {\n const arr = (Array.isArray(value) ? value : []) as Date[];\n const exists = arr.findIndex((d) => isSameDay(d, date));\n if (exists >= 0) {\n onChange?.(arr.filter((_, i) => i !== exists));\n } else {\n onChange?.([...arr, date]);\n }\n } else if (mode === \"range\") {\n const range = (value && typeof value === \"object\" && \"start\" in value\n ? value\n : { start: null, end: null }) as DateRange;\n\n if (!range.start || range.end) {\n onChange?.({ start: date, end: null });\n } else {\n const [s, e] =\n date >= range.start ? [range.start, date] : [date, range.start];\n onChange?.({ start: s, end: e });\n }\n }\n },\n [mode, value, onChange, isDisabled],\n );\n\n const btnBase =\n \"flex h-8 w-8 items-center justify-center rounded-lg text-sm transition-colors\";\n\n return (\n <div\n data-react-fancy-calendar=\"\"\n ref={ref}\n className={cn(\n \"inline-block w-72 rounded-xl border border-[color:var(--fancy-border,var(--color-zinc-200))] bg-[color:var(--fancy-surface,var(--color-white))] p-4 dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))] dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\",\n className,\n )}\n >\n {/* Header */}\n <div className=\"mb-3 flex items-center justify-between\">\n <button\n type=\"button\"\n onClick={prevMonth}\n className=\"rounded-lg p-1 text-zinc-400 hover:bg-[color:var(--fancy-surface-muted,var(--color-zinc-100))] dark:hover:bg-[color:var(--fancy-surface-muted-dark,var(--color-zinc-800))]\"\n aria-label=\"Previous month\"\n >\n <ChevronLeft size={16} />\n </button>\n <span className=\"text-sm font-semibold\" data-react-fancy-calendar-month=\"\">\n {MONTHS[viewMonth]} {viewYear}\n </span>\n <button\n type=\"button\"\n onClick={nextMonth}\n className=\"rounded-lg p-1 text-zinc-400 hover:bg-[color:var(--fancy-surface-muted,var(--color-zinc-100))] dark:hover:bg-[color:var(--fancy-surface-muted-dark,var(--color-zinc-800))]\"\n aria-label=\"Next month\"\n >\n <ChevronRight size={16} />\n </button>\n </div>\n\n {/* Day headers */}\n <div className=\"mb-1 grid grid-cols-7 gap-1\">\n {DAYS.map((d) => (\n <div\n key={d}\n className=\"flex h-8 items-center justify-center text-xs font-medium text-zinc-400\"\n >\n {d}\n </div>\n ))}\n </div>\n\n {/* Day grid */}\n <div className=\"grid grid-cols-7 gap-1\">\n {days.map((date, i) => {\n const isCurrentMonth = date.getMonth() === viewMonth;\n const selected = isSelected(date);\n const inRange = isInRange(date);\n const disabled = isDisabled(date);\n const isToday = isSameDay(date, today);\n const ctx: CalendarDayContext = {\n date,\n id: dateId(date),\n selected,\n disabled,\n inRange,\n outsideMonth: !isCurrentMonth,\n today: isToday,\n };\n\n return (\n <button\n key={i}\n type=\"button\"\n disabled={disabled}\n data-react-fancy-calendar-day={ctx.id}\n data-outside-month={isCurrentMonth ? undefined : \"\"}\n aria-label={dayAriaLabel?.(ctx) || undefined}\n onClick={() => handleSelect(date)}\n onMouseEnter={() =>\n mode === \"range\" && setRangeHover(date)\n }\n className={cn(\n btnBase,\n !isCurrentMonth && \"text-zinc-300 dark:text-zinc-600\",\n isCurrentMonth &&\n !selected &&\n !inRange &&\n \"text-[color:var(--fancy-text-soft,var(--color-zinc-700))] hover:bg-[color:var(--fancy-surface-muted,var(--color-zinc-100))] dark:text-[color:var(--fancy-text-soft-dark,var(--color-zinc-300))] dark:hover:bg-[color:var(--fancy-surface-muted-dark,var(--color-zinc-800))]\",\n inRange &&\n \"bg-blue-50 text-blue-700 dark:bg-blue-950 dark:text-blue-300\",\n selected &&\n \"bg-zinc-900 text-white dark:bg-white dark:text-zinc-900\",\n isToday && !selected && \"font-bold\",\n disabled && \"cursor-not-allowed opacity-30\",\n dayClassName?.(ctx),\n )}\n >\n {renderDay ? renderDay(ctx) : date.getDate()}\n </button>\n );\n })}\n </div>\n </div>\n );\n },\n);\n\nCalendar.displayName = \"Calendar\";\n"]}
|
|
@@ -21,6 +21,10 @@ var MONTHS = [
|
|
|
21
21
|
function isSameDay(a, b) {
|
|
22
22
|
return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
|
|
23
23
|
}
|
|
24
|
+
var pad2 = (n) => n < 10 ? `0${n}` : String(n);
|
|
25
|
+
function defaultDateId(date) {
|
|
26
|
+
return `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())}`;
|
|
27
|
+
}
|
|
24
28
|
function getDaysInMonth(year, month) {
|
|
25
29
|
const days = [];
|
|
26
30
|
const firstDay = new Date(year, month, 1);
|
|
@@ -45,34 +49,36 @@ var Calendar = forwardRef(
|
|
|
45
49
|
minDate,
|
|
46
50
|
maxDate,
|
|
47
51
|
disabledDates = [],
|
|
48
|
-
className
|
|
52
|
+
className,
|
|
53
|
+
dateId = defaultDateId,
|
|
54
|
+
renderDay,
|
|
55
|
+
dayClassName,
|
|
56
|
+
dayAriaLabel,
|
|
57
|
+
visibleMonth,
|
|
58
|
+
onVisibleMonthChange
|
|
49
59
|
}, ref) {
|
|
50
60
|
const today = useMemo(() => /* @__PURE__ */ new Date(), []);
|
|
51
|
-
const [
|
|
52
|
-
|
|
61
|
+
const [innerMonth, setInnerMonth] = useState(
|
|
62
|
+
() => new Date(today.getFullYear(), today.getMonth(), 1)
|
|
63
|
+
);
|
|
53
64
|
const [rangeHover, setRangeHover] = useState(null);
|
|
65
|
+
const shown = visibleMonth ?? innerMonth;
|
|
66
|
+
const viewMonth = shown.getMonth();
|
|
67
|
+
const viewYear = shown.getFullYear();
|
|
54
68
|
const days = useMemo(
|
|
55
69
|
() => getDaysInMonth(viewYear, viewMonth),
|
|
56
70
|
[viewYear, viewMonth]
|
|
57
71
|
);
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const nextMonth = useCallback(() =>
|
|
68
|
-
setViewMonth((m) => {
|
|
69
|
-
if (m === 11) {
|
|
70
|
-
setViewYear((y) => y + 1);
|
|
71
|
-
return 0;
|
|
72
|
-
}
|
|
73
|
-
return m + 1;
|
|
74
|
-
});
|
|
75
|
-
}, []);
|
|
72
|
+
const goToMonth = useCallback(
|
|
73
|
+
(delta) => {
|
|
74
|
+
const next = new Date(viewYear, viewMonth + delta, 1);
|
|
75
|
+
if (visibleMonth === void 0) setInnerMonth(next);
|
|
76
|
+
onVisibleMonthChange?.(next);
|
|
77
|
+
},
|
|
78
|
+
[viewYear, viewMonth, visibleMonth, onVisibleMonthChange]
|
|
79
|
+
);
|
|
80
|
+
const prevMonth = useCallback(() => goToMonth(-1), [goToMonth]);
|
|
81
|
+
const nextMonth = useCallback(() => goToMonth(1), [goToMonth]);
|
|
76
82
|
const isDisabled = useCallback(
|
|
77
83
|
(date) => {
|
|
78
84
|
if (minDate && date < minDate) return true;
|
|
@@ -159,7 +165,7 @@ var Calendar = forwardRef(
|
|
|
159
165
|
children: /* @__PURE__ */ jsx(ChevronLeft, { size: 16 })
|
|
160
166
|
}
|
|
161
167
|
),
|
|
162
|
-
/* @__PURE__ */ jsxs("span", { className: "text-sm font-semibold", children: [
|
|
168
|
+
/* @__PURE__ */ jsxs("span", { className: "text-sm font-semibold", "data-react-fancy-calendar-month": "", children: [
|
|
163
169
|
MONTHS[viewMonth],
|
|
164
170
|
" ",
|
|
165
171
|
viewYear
|
|
@@ -189,11 +195,23 @@ var Calendar = forwardRef(
|
|
|
189
195
|
const inRange = isInRange(date);
|
|
190
196
|
const disabled = isDisabled(date);
|
|
191
197
|
const isToday = isSameDay(date, today);
|
|
198
|
+
const ctx = {
|
|
199
|
+
date,
|
|
200
|
+
id: dateId(date),
|
|
201
|
+
selected,
|
|
202
|
+
disabled,
|
|
203
|
+
inRange,
|
|
204
|
+
outsideMonth: !isCurrentMonth,
|
|
205
|
+
today: isToday
|
|
206
|
+
};
|
|
192
207
|
return /* @__PURE__ */ jsx(
|
|
193
208
|
"button",
|
|
194
209
|
{
|
|
195
210
|
type: "button",
|
|
196
211
|
disabled,
|
|
212
|
+
"data-react-fancy-calendar-day": ctx.id,
|
|
213
|
+
"data-outside-month": isCurrentMonth ? void 0 : "",
|
|
214
|
+
"aria-label": dayAriaLabel?.(ctx) || void 0,
|
|
197
215
|
onClick: () => handleSelect(date),
|
|
198
216
|
onMouseEnter: () => mode === "range" && setRangeHover(date),
|
|
199
217
|
className: cn(
|
|
@@ -203,9 +221,10 @@ var Calendar = forwardRef(
|
|
|
203
221
|
inRange && "bg-blue-50 text-blue-700 dark:bg-blue-950 dark:text-blue-300",
|
|
204
222
|
selected && "bg-zinc-900 text-white dark:bg-white dark:text-zinc-900",
|
|
205
223
|
isToday && !selected && "font-bold",
|
|
206
|
-
disabled && "cursor-not-allowed opacity-30"
|
|
224
|
+
disabled && "cursor-not-allowed opacity-30",
|
|
225
|
+
dayClassName?.(ctx)
|
|
207
226
|
),
|
|
208
|
-
children: date.getDate()
|
|
227
|
+
children: renderDay ? renderDay(ctx) : date.getDate()
|
|
209
228
|
},
|
|
210
229
|
i
|
|
211
230
|
);
|
|
@@ -218,5 +237,5 @@ var Calendar = forwardRef(
|
|
|
218
237
|
Calendar.displayName = "Calendar";
|
|
219
238
|
|
|
220
239
|
export { Calendar };
|
|
221
|
-
//# sourceMappingURL=chunk-
|
|
222
|
-
//# sourceMappingURL=chunk-
|
|
240
|
+
//# sourceMappingURL=chunk-X2A3NAJW.js.map
|
|
241
|
+
//# sourceMappingURL=chunk-X2A3NAJW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/Calendar/Calendar.tsx"],"names":["Calendar"],"mappings":"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","file":"chunk-X2A3NAJW.js","sourcesContent":["import { forwardRef, useCallback, useMemo, useState } from \"react\";\nimport { ChevronLeft, ChevronRight } from \"lucide-react\";\nimport { cn } from \"../../utils/cn\";\nimport type { CalendarDayContext, CalendarProps, DateRange } from \"./Calendar.types\";\n\nconst DAYS = [\"Su\", \"Mo\", \"Tu\", \"We\", \"Th\", \"Fr\", \"Sa\"];\nconst MONTHS = [\n \"January\", \"February\", \"March\", \"April\", \"May\", \"June\",\n \"July\", \"August\", \"September\", \"October\", \"November\", \"December\",\n];\n\nfunction isSameDay(a: Date, b: Date): boolean {\n return (\n a.getFullYear() === b.getFullYear() &&\n a.getMonth() === b.getMonth() &&\n a.getDate() === b.getDate()\n );\n}\n\nconst pad2 = (n: number) => (n < 10 ? `0${n}` : String(n));\n\n/** `YYYY-MM-DD` in LOCAL time — never `toISOString()`, which shifts the day east of UTC. */\nfunction defaultDateId(date: Date): string {\n return `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())}`;\n}\n\nfunction getDaysInMonth(year: number, month: number): Date[] {\n const days: Date[] = [];\n const firstDay = new Date(year, month, 1);\n const startDayOfWeek = firstDay.getDay();\n\n // Fill leading days from previous month\n for (let i = startDayOfWeek - 1; i >= 0; i--) {\n days.push(new Date(year, month, -i));\n }\n\n // Fill current month\n const lastDate = new Date(year, month + 1, 0).getDate();\n for (let d = 1; d <= lastDate; d++) {\n days.push(new Date(year, month, d));\n }\n\n // Fill trailing days to complete 6 rows\n while (days.length < 42) {\n days.push(new Date(year, month + 1, days.length - startDayOfWeek - lastDate + 1));\n }\n\n return days;\n}\n\nexport const Calendar = forwardRef<HTMLDivElement, CalendarProps>(\n function Calendar(\n {\n mode = \"single\",\n value,\n onChange,\n minDate,\n maxDate,\n disabledDates = [],\n className,\n dateId = defaultDateId,\n renderDay,\n dayClassName,\n dayAriaLabel,\n visibleMonth,\n onVisibleMonthChange,\n },\n ref,\n ) {\n const today = useMemo(() => new Date(), []);\n const [innerMonth, setInnerMonth] = useState(\n () => new Date(today.getFullYear(), today.getMonth(), 1),\n );\n const [rangeHover, setRangeHover] = useState<Date | null>(null);\n\n const shown = visibleMonth ?? innerMonth;\n const viewMonth = shown.getMonth();\n const viewYear = shown.getFullYear();\n\n const days = useMemo(\n () => getDaysInMonth(viewYear, viewMonth),\n [viewYear, viewMonth],\n );\n\n const goToMonth = useCallback(\n (delta: number) => {\n const next = new Date(viewYear, viewMonth + delta, 1);\n if (visibleMonth === undefined) setInnerMonth(next);\n onVisibleMonthChange?.(next);\n },\n [viewYear, viewMonth, visibleMonth, onVisibleMonthChange],\n );\n const prevMonth = useCallback(() => goToMonth(-1), [goToMonth]);\n const nextMonth = useCallback(() => goToMonth(1), [goToMonth]);\n\n const isDisabled = useCallback(\n (date: Date): boolean => {\n if (minDate && date < minDate) return true;\n if (maxDate && date > maxDate) return true;\n return disabledDates.some((d) => isSameDay(d, date));\n },\n [minDate, maxDate, disabledDates],\n );\n\n const isSelected = useCallback(\n (date: Date): boolean => {\n if (!value) return false;\n if (mode === \"single\" && value instanceof Date) {\n return isSameDay(date, value);\n }\n if (mode === \"multiple\" && Array.isArray(value)) {\n return value.some((v) => isSameDay(date, v));\n }\n if (mode === \"range\" && value && typeof value === \"object\" && \"start\" in value) {\n const range = value as DateRange;\n if (range.start && isSameDay(date, range.start)) return true;\n if (range.end && isSameDay(date, range.end)) return true;\n }\n return false;\n },\n [value, mode],\n );\n\n const isInRange = useCallback(\n (date: Date): boolean => {\n if (mode !== \"range\" || !value || typeof value !== \"object\" || !(\"start\" in value))\n return false;\n const range = value as DateRange;\n if (!range.start) return false;\n const end = range.end ?? rangeHover;\n if (!end) return false;\n const [s, e] = range.start <= end ? [range.start, end] : [end, range.start];\n return date > s && date < e;\n },\n [value, mode, rangeHover],\n );\n\n const handleSelect = useCallback(\n (date: Date) => {\n if (isDisabled(date)) return;\n\n if (mode === \"single\") {\n onChange?.(date);\n } else if (mode === \"multiple\") {\n const arr = (Array.isArray(value) ? value : []) as Date[];\n const exists = arr.findIndex((d) => isSameDay(d, date));\n if (exists >= 0) {\n onChange?.(arr.filter((_, i) => i !== exists));\n } else {\n onChange?.([...arr, date]);\n }\n } else if (mode === \"range\") {\n const range = (value && typeof value === \"object\" && \"start\" in value\n ? value\n : { start: null, end: null }) as DateRange;\n\n if (!range.start || range.end) {\n onChange?.({ start: date, end: null });\n } else {\n const [s, e] =\n date >= range.start ? [range.start, date] : [date, range.start];\n onChange?.({ start: s, end: e });\n }\n }\n },\n [mode, value, onChange, isDisabled],\n );\n\n const btnBase =\n \"flex h-8 w-8 items-center justify-center rounded-lg text-sm transition-colors\";\n\n return (\n <div\n data-react-fancy-calendar=\"\"\n ref={ref}\n className={cn(\n \"inline-block w-72 rounded-xl border border-[color:var(--fancy-border,var(--color-zinc-200))] bg-[color:var(--fancy-surface,var(--color-white))] p-4 dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))] dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\",\n className,\n )}\n >\n {/* Header */}\n <div className=\"mb-3 flex items-center justify-between\">\n <button\n type=\"button\"\n onClick={prevMonth}\n className=\"rounded-lg p-1 text-zinc-400 hover:bg-[color:var(--fancy-surface-muted,var(--color-zinc-100))] dark:hover:bg-[color:var(--fancy-surface-muted-dark,var(--color-zinc-800))]\"\n aria-label=\"Previous month\"\n >\n <ChevronLeft size={16} />\n </button>\n <span className=\"text-sm font-semibold\" data-react-fancy-calendar-month=\"\">\n {MONTHS[viewMonth]} {viewYear}\n </span>\n <button\n type=\"button\"\n onClick={nextMonth}\n className=\"rounded-lg p-1 text-zinc-400 hover:bg-[color:var(--fancy-surface-muted,var(--color-zinc-100))] dark:hover:bg-[color:var(--fancy-surface-muted-dark,var(--color-zinc-800))]\"\n aria-label=\"Next month\"\n >\n <ChevronRight size={16} />\n </button>\n </div>\n\n {/* Day headers */}\n <div className=\"mb-1 grid grid-cols-7 gap-1\">\n {DAYS.map((d) => (\n <div\n key={d}\n className=\"flex h-8 items-center justify-center text-xs font-medium text-zinc-400\"\n >\n {d}\n </div>\n ))}\n </div>\n\n {/* Day grid */}\n <div className=\"grid grid-cols-7 gap-1\">\n {days.map((date, i) => {\n const isCurrentMonth = date.getMonth() === viewMonth;\n const selected = isSelected(date);\n const inRange = isInRange(date);\n const disabled = isDisabled(date);\n const isToday = isSameDay(date, today);\n const ctx: CalendarDayContext = {\n date,\n id: dateId(date),\n selected,\n disabled,\n inRange,\n outsideMonth: !isCurrentMonth,\n today: isToday,\n };\n\n return (\n <button\n key={i}\n type=\"button\"\n disabled={disabled}\n data-react-fancy-calendar-day={ctx.id}\n data-outside-month={isCurrentMonth ? undefined : \"\"}\n aria-label={dayAriaLabel?.(ctx) || undefined}\n onClick={() => handleSelect(date)}\n onMouseEnter={() =>\n mode === \"range\" && setRangeHover(date)\n }\n className={cn(\n btnBase,\n !isCurrentMonth && \"text-zinc-300 dark:text-zinc-600\",\n isCurrentMonth &&\n !selected &&\n !inRange &&\n \"text-[color:var(--fancy-text-soft,var(--color-zinc-700))] hover:bg-[color:var(--fancy-surface-muted,var(--color-zinc-100))] dark:text-[color:var(--fancy-text-soft-dark,var(--color-zinc-300))] dark:hover:bg-[color:var(--fancy-surface-muted-dark,var(--color-zinc-800))]\",\n inRange &&\n \"bg-blue-50 text-blue-700 dark:bg-blue-950 dark:text-blue-300\",\n selected &&\n \"bg-zinc-900 text-white dark:bg-white dark:text-zinc-900\",\n isToday && !selected && \"font-bold\",\n disabled && \"cursor-not-allowed opacity-30\",\n dayClassName?.(ctx),\n )}\n >\n {renderDay ? renderDay(ctx) : date.getDate()}\n </button>\n );\n })}\n </div>\n </div>\n );\n },\n);\n\nCalendar.displayName = \"Calendar\";\n"]}
|
package/dist/index.cjs
CHANGED
|
@@ -114,7 +114,7 @@ var chunkC5YX5XVL_cjs = require('./chunk-C5YX5XVL.cjs');
|
|
|
114
114
|
var chunkX2FC7ODX_cjs = require('./chunk-X2FC7ODX.cjs');
|
|
115
115
|
var chunkXCZZVRBY_cjs = require('./chunk-XCZZVRBY.cjs');
|
|
116
116
|
var chunkMXWR3T3N_cjs = require('./chunk-MXWR3T3N.cjs');
|
|
117
|
-
var
|
|
117
|
+
var chunkCQ7QXZLR_cjs = require('./chunk-CQ7QXZLR.cjs');
|
|
118
118
|
require('./chunk-3I2KWNXT.cjs');
|
|
119
119
|
var chunkLCNHEYIM_cjs = require('./chunk-LCNHEYIM.cjs');
|
|
120
120
|
var chunkCVDL6C2O_cjs = require('./chunk-CVDL6C2O.cjs');
|
|
@@ -903,7 +903,7 @@ Object.defineProperty(exports, "registerIcons", {
|
|
|
903
903
|
});
|
|
904
904
|
Object.defineProperty(exports, "Calendar", {
|
|
905
905
|
enumerable: true,
|
|
906
|
-
get: function () { return
|
|
906
|
+
get: function () { return chunkCQ7QXZLR_cjs.Calendar; }
|
|
907
907
|
});
|
|
908
908
|
Object.defineProperty(exports, "Callout", {
|
|
909
909
|
enumerable: true,
|
package/dist/index.d.cts
CHANGED
|
@@ -67,7 +67,7 @@ export { Pillbox, PillboxProps } from './pillbox.cjs';
|
|
|
67
67
|
export { OtpInput, OtpInputProps } from './otp-input.cjs';
|
|
68
68
|
export { FileUpload, FileUploadContextValue, FileUploadDropzoneProps, FileUploadListProps, FileUploadProps, useFileUpload } from './file-upload.cjs';
|
|
69
69
|
export { TimePicker, TimePickerProps } from './time-picker.cjs';
|
|
70
|
-
export { Calendar, CalendarMode, CalendarProps, DateRange } from './calendar.cjs';
|
|
70
|
+
export { Calendar, CalendarDayContext, CalendarMode, CalendarProps, DateRange } from './calendar.cjs';
|
|
71
71
|
export { Composer, ComposerProps, ComposerSubmitExtras } from './composer.cjs';
|
|
72
72
|
export { a as ComposerPasteClassNames, C as ComposerPastePreview, H as HeldImage, b as HeldPaste, c as PasteClassNames, d as PasteEventLike, e as PastePreview, U as UsePastePillsOptions, f as UsePastePillsResult, p as pasteMarker, u as usePastePills } from './PastePills.types-CDyotkUb.cjs';
|
|
73
73
|
export { I as InlinePasteEditor, a as InlinePasteEditorHandle, P as PastedFilesInput, b as PastedFilesInputProps, U as UseInlinePasteOptions, u as useInlinePaste } from './PastedFilesInput-DQ1eZaHk.cjs';
|
package/dist/index.d.ts
CHANGED
|
@@ -67,7 +67,7 @@ export { Pillbox, PillboxProps } from './pillbox.js';
|
|
|
67
67
|
export { OtpInput, OtpInputProps } from './otp-input.js';
|
|
68
68
|
export { FileUpload, FileUploadContextValue, FileUploadDropzoneProps, FileUploadListProps, FileUploadProps, useFileUpload } from './file-upload.js';
|
|
69
69
|
export { TimePicker, TimePickerProps } from './time-picker.js';
|
|
70
|
-
export { Calendar, CalendarMode, CalendarProps, DateRange } from './calendar.js';
|
|
70
|
+
export { Calendar, CalendarDayContext, CalendarMode, CalendarProps, DateRange } from './calendar.js';
|
|
71
71
|
export { Composer, ComposerProps, ComposerSubmitExtras } from './composer.js';
|
|
72
72
|
export { a as ComposerPasteClassNames, C as ComposerPastePreview, H as HeldImage, b as HeldPaste, c as PasteClassNames, d as PasteEventLike, e as PastePreview, U as UsePastePillsOptions, f as UsePastePillsResult, p as pasteMarker, u as usePastePills } from './PastePills.types-CDyotkUb.js';
|
|
73
73
|
export { I as InlinePasteEditor, a as InlinePasteEditorHandle, P as PastedFilesInput, b as PastedFilesInputProps, U as UseInlinePasteOptions, u as useInlinePaste } from './PastedFilesInput-CrgNoEBd.js';
|
package/dist/index.js
CHANGED
|
@@ -112,7 +112,7 @@ export { Action, Button } from './chunk-TLRRMYNV.js';
|
|
|
112
112
|
export { sanitizeHref, sanitizeHtml } from './chunk-6TBRBN7H.js';
|
|
113
113
|
export { EMOJI_CATEGORY_ORDER, EMOJI_DATA, EMOJI_ENTRIES, SKIN_TONES, applyTone, find, hasSkinTones, resolve, search, skinTones } from './chunk-45BBNJQD.js';
|
|
114
114
|
export { Icon, configureIcons, registerIconAddendum, registerIconSet, registerIcons } from './chunk-J3A4Z2P7.js';
|
|
115
|
-
export { Calendar } from './chunk-
|
|
115
|
+
export { Calendar } from './chunk-X2A3NAJW.js';
|
|
116
116
|
import './chunk-NMXCQOHV.js';
|
|
117
117
|
export { Callout } from './chunk-ZXZJYVWP.js';
|
|
118
118
|
export { Accordion, useAccordion } from './chunk-FRWOWDGX.js';
|
package/docs/Calendar.md
CHANGED
|
@@ -25,6 +25,29 @@ import { Calendar } from "@particle-academy/react-fancy";
|
|
|
25
25
|
| `maxDate` | `Date` | - | Latest selectable date |
|
|
26
26
|
| `disabledDates` | `Date[]` | `[]` | Specific dates to disable |
|
|
27
27
|
| `className` | `string` | - | Additional CSS classes |
|
|
28
|
+
| `dateId` | `(date: Date) => string` | `YYYY-MM-DD` (local) | Stable id per day, emitted as `data-react-fancy-calendar-day` (5.56.0) |
|
|
29
|
+
| `renderDay` | `(ctx: CalendarDayContext) => ReactNode` | day number | The day cell's content; the cell itself stays the Calendar's (5.56.0) |
|
|
30
|
+
| `dayClassName` | `(ctx: CalendarDayContext) => string \| undefined` | - | Extra classes for one day, merged after the built-in ones (5.56.0) |
|
|
31
|
+
| `dayAriaLabel` | `(ctx: CalendarDayContext) => string \| undefined` | - | The day's accessible name. Required in practice whenever `dayClassName` shades a day: colour alone is not a signal. Replaces the name, so include the date (5.56.0) |
|
|
32
|
+
| `visibleMonth` | `Date` | - | Controlled visible month (any day in it). Uncontrolled when omitted (5.56.0) |
|
|
33
|
+
| `onVisibleMonthChange` | `(month: Date) => void` | - | Called with the 1st of the month navigated to (5.56.0) |
|
|
34
|
+
|
|
35
|
+
### CalendarDayContext
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
interface CalendarDayContext {
|
|
39
|
+
date: Date;
|
|
40
|
+
id: string; // dateId(date)
|
|
41
|
+
selected: boolean;
|
|
42
|
+
disabled: boolean;
|
|
43
|
+
inRange: boolean; // strictly between a range's ends
|
|
44
|
+
outsideMonth: boolean;
|
|
45
|
+
today: boolean;
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Out-of-month day cells also carry `data-outside-month`, and the month heading
|
|
50
|
+
carries `data-react-fancy-calendar-month`.
|
|
28
51
|
|
|
29
52
|
### DateRange type
|
|
30
53
|
|
|
@@ -56,6 +79,20 @@ const [range, setRange] = useState<DateRange>({ start: null, end: null });
|
|
|
56
79
|
/>
|
|
57
80
|
```
|
|
58
81
|
|
|
82
|
+
### Coverage shading, a controlled month, open a day on click
|
|
83
|
+
|
|
84
|
+
```tsx
|
|
85
|
+
const [month, setMonth] = useState(new Date(2026, 9, 1));
|
|
86
|
+
|
|
87
|
+
<Calendar
|
|
88
|
+
visibleMonth={month}
|
|
89
|
+
onVisibleMonthChange={setMonth}
|
|
90
|
+
onChange={(d) => openDay(d as Date)}
|
|
91
|
+
dayClassName={(ctx) => (coverage[ctx.id] === "full" ? "bg-emerald-100 dark:bg-emerald-900/50" : undefined)}
|
|
92
|
+
dayAriaLabel={(ctx) => (coverage[ctx.id] ? `${ctx.date.toDateString()}, ${coverage[ctx.id]} coverage` : undefined)}
|
|
93
|
+
/>
|
|
94
|
+
```
|
|
95
|
+
|
|
59
96
|
### Multiple dates with constraints
|
|
60
97
|
|
|
61
98
|
```tsx
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/Calendar/Calendar.tsx"],"names":["Calendar"],"mappings":"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","file":"chunk-HVND2IIB.js","sourcesContent":["import { forwardRef, useCallback, useMemo, useState } from \"react\";\nimport { ChevronLeft, ChevronRight } from \"lucide-react\";\nimport { cn } from \"../../utils/cn\";\nimport type { CalendarProps, DateRange } from \"./Calendar.types\";\n\nconst DAYS = [\"Su\", \"Mo\", \"Tu\", \"We\", \"Th\", \"Fr\", \"Sa\"];\nconst MONTHS = [\n \"January\", \"February\", \"March\", \"April\", \"May\", \"June\",\n \"July\", \"August\", \"September\", \"October\", \"November\", \"December\",\n];\n\nfunction isSameDay(a: Date, b: Date): boolean {\n return (\n a.getFullYear() === b.getFullYear() &&\n a.getMonth() === b.getMonth() &&\n a.getDate() === b.getDate()\n );\n}\n\nfunction getDaysInMonth(year: number, month: number): Date[] {\n const days: Date[] = [];\n const firstDay = new Date(year, month, 1);\n const startDayOfWeek = firstDay.getDay();\n\n // Fill leading days from previous month\n for (let i = startDayOfWeek - 1; i >= 0; i--) {\n days.push(new Date(year, month, -i));\n }\n\n // Fill current month\n const lastDate = new Date(year, month + 1, 0).getDate();\n for (let d = 1; d <= lastDate; d++) {\n days.push(new Date(year, month, d));\n }\n\n // Fill trailing days to complete 6 rows\n while (days.length < 42) {\n days.push(new Date(year, month + 1, days.length - startDayOfWeek - lastDate + 1));\n }\n\n return days;\n}\n\nexport const Calendar = forwardRef<HTMLDivElement, CalendarProps>(\n function Calendar(\n {\n mode = \"single\",\n value,\n onChange,\n minDate,\n maxDate,\n disabledDates = [],\n className,\n },\n ref,\n ) {\n const today = useMemo(() => new Date(), []);\n const [viewMonth, setViewMonth] = useState(today.getMonth());\n const [viewYear, setViewYear] = useState(today.getFullYear());\n const [rangeHover, setRangeHover] = useState<Date | null>(null);\n\n const days = useMemo(\n () => getDaysInMonth(viewYear, viewMonth),\n [viewYear, viewMonth],\n );\n\n const prevMonth = useCallback(() => {\n setViewMonth((m) => {\n if (m === 0) {\n setViewYear((y) => y - 1);\n return 11;\n }\n return m - 1;\n });\n }, []);\n\n const nextMonth = useCallback(() => {\n setViewMonth((m) => {\n if (m === 11) {\n setViewYear((y) => y + 1);\n return 0;\n }\n return m + 1;\n });\n }, []);\n\n const isDisabled = useCallback(\n (date: Date): boolean => {\n if (minDate && date < minDate) return true;\n if (maxDate && date > maxDate) return true;\n return disabledDates.some((d) => isSameDay(d, date));\n },\n [minDate, maxDate, disabledDates],\n );\n\n const isSelected = useCallback(\n (date: Date): boolean => {\n if (!value) return false;\n if (mode === \"single\" && value instanceof Date) {\n return isSameDay(date, value);\n }\n if (mode === \"multiple\" && Array.isArray(value)) {\n return value.some((v) => isSameDay(date, v));\n }\n if (mode === \"range\" && value && typeof value === \"object\" && \"start\" in value) {\n const range = value as DateRange;\n if (range.start && isSameDay(date, range.start)) return true;\n if (range.end && isSameDay(date, range.end)) return true;\n }\n return false;\n },\n [value, mode],\n );\n\n const isInRange = useCallback(\n (date: Date): boolean => {\n if (mode !== \"range\" || !value || typeof value !== \"object\" || !(\"start\" in value))\n return false;\n const range = value as DateRange;\n if (!range.start) return false;\n const end = range.end ?? rangeHover;\n if (!end) return false;\n const [s, e] = range.start <= end ? [range.start, end] : [end, range.start];\n return date > s && date < e;\n },\n [value, mode, rangeHover],\n );\n\n const handleSelect = useCallback(\n (date: Date) => {\n if (isDisabled(date)) return;\n\n if (mode === \"single\") {\n onChange?.(date);\n } else if (mode === \"multiple\") {\n const arr = (Array.isArray(value) ? value : []) as Date[];\n const exists = arr.findIndex((d) => isSameDay(d, date));\n if (exists >= 0) {\n onChange?.(arr.filter((_, i) => i !== exists));\n } else {\n onChange?.([...arr, date]);\n }\n } else if (mode === \"range\") {\n const range = (value && typeof value === \"object\" && \"start\" in value\n ? value\n : { start: null, end: null }) as DateRange;\n\n if (!range.start || range.end) {\n onChange?.({ start: date, end: null });\n } else {\n const [s, e] =\n date >= range.start ? [range.start, date] : [date, range.start];\n onChange?.({ start: s, end: e });\n }\n }\n },\n [mode, value, onChange, isDisabled],\n );\n\n const btnBase =\n \"flex h-8 w-8 items-center justify-center rounded-lg text-sm transition-colors\";\n\n return (\n <div\n data-react-fancy-calendar=\"\"\n ref={ref}\n className={cn(\n \"inline-block w-72 rounded-xl border border-[color:var(--fancy-border,var(--color-zinc-200))] bg-[color:var(--fancy-surface,var(--color-white))] p-4 dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))] dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\",\n className,\n )}\n >\n {/* Header */}\n <div className=\"mb-3 flex items-center justify-between\">\n <button\n type=\"button\"\n onClick={prevMonth}\n className=\"rounded-lg p-1 text-zinc-400 hover:bg-[color:var(--fancy-surface-muted,var(--color-zinc-100))] dark:hover:bg-[color:var(--fancy-surface-muted-dark,var(--color-zinc-800))]\"\n aria-label=\"Previous month\"\n >\n <ChevronLeft size={16} />\n </button>\n <span className=\"text-sm font-semibold\">\n {MONTHS[viewMonth]} {viewYear}\n </span>\n <button\n type=\"button\"\n onClick={nextMonth}\n className=\"rounded-lg p-1 text-zinc-400 hover:bg-[color:var(--fancy-surface-muted,var(--color-zinc-100))] dark:hover:bg-[color:var(--fancy-surface-muted-dark,var(--color-zinc-800))]\"\n aria-label=\"Next month\"\n >\n <ChevronRight size={16} />\n </button>\n </div>\n\n {/* Day headers */}\n <div className=\"mb-1 grid grid-cols-7 gap-1\">\n {DAYS.map((d) => (\n <div\n key={d}\n className=\"flex h-8 items-center justify-center text-xs font-medium text-zinc-400\"\n >\n {d}\n </div>\n ))}\n </div>\n\n {/* Day grid */}\n <div className=\"grid grid-cols-7 gap-1\">\n {days.map((date, i) => {\n const isCurrentMonth = date.getMonth() === viewMonth;\n const selected = isSelected(date);\n const inRange = isInRange(date);\n const disabled = isDisabled(date);\n const isToday = isSameDay(date, today);\n\n return (\n <button\n key={i}\n type=\"button\"\n disabled={disabled}\n onClick={() => handleSelect(date)}\n onMouseEnter={() =>\n mode === \"range\" && setRangeHover(date)\n }\n className={cn(\n btnBase,\n !isCurrentMonth && \"text-zinc-300 dark:text-zinc-600\",\n isCurrentMonth &&\n !selected &&\n !inRange &&\n \"text-[color:var(--fancy-text-soft,var(--color-zinc-700))] hover:bg-[color:var(--fancy-surface-muted,var(--color-zinc-100))] dark:text-[color:var(--fancy-text-soft-dark,var(--color-zinc-300))] dark:hover:bg-[color:var(--fancy-surface-muted-dark,var(--color-zinc-800))]\",\n inRange &&\n \"bg-blue-50 text-blue-700 dark:bg-blue-950 dark:text-blue-300\",\n selected &&\n \"bg-zinc-900 text-white dark:bg-white dark:text-zinc-900\",\n isToday && !selected && \"font-bold\",\n disabled && \"cursor-not-allowed opacity-30\",\n )}\n >\n {date.getDate()}\n </button>\n );\n })}\n </div>\n </div>\n );\n },\n);\n\nCalendar.displayName = \"Calendar\";\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/Calendar/Calendar.tsx"],"names":["forwardRef","Calendar","useMemo","useState","useCallback","jsxs","cn","jsx","ChevronLeft","ChevronRight"],"mappings":"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","file":"chunk-UET6D7B3.cjs","sourcesContent":["import { forwardRef, useCallback, useMemo, useState } from \"react\";\nimport { ChevronLeft, ChevronRight } from \"lucide-react\";\nimport { cn } from \"../../utils/cn\";\nimport type { CalendarProps, DateRange } from \"./Calendar.types\";\n\nconst DAYS = [\"Su\", \"Mo\", \"Tu\", \"We\", \"Th\", \"Fr\", \"Sa\"];\nconst MONTHS = [\n \"January\", \"February\", \"March\", \"April\", \"May\", \"June\",\n \"July\", \"August\", \"September\", \"October\", \"November\", \"December\",\n];\n\nfunction isSameDay(a: Date, b: Date): boolean {\n return (\n a.getFullYear() === b.getFullYear() &&\n a.getMonth() === b.getMonth() &&\n a.getDate() === b.getDate()\n );\n}\n\nfunction getDaysInMonth(year: number, month: number): Date[] {\n const days: Date[] = [];\n const firstDay = new Date(year, month, 1);\n const startDayOfWeek = firstDay.getDay();\n\n // Fill leading days from previous month\n for (let i = startDayOfWeek - 1; i >= 0; i--) {\n days.push(new Date(year, month, -i));\n }\n\n // Fill current month\n const lastDate = new Date(year, month + 1, 0).getDate();\n for (let d = 1; d <= lastDate; d++) {\n days.push(new Date(year, month, d));\n }\n\n // Fill trailing days to complete 6 rows\n while (days.length < 42) {\n days.push(new Date(year, month + 1, days.length - startDayOfWeek - lastDate + 1));\n }\n\n return days;\n}\n\nexport const Calendar = forwardRef<HTMLDivElement, CalendarProps>(\n function Calendar(\n {\n mode = \"single\",\n value,\n onChange,\n minDate,\n maxDate,\n disabledDates = [],\n className,\n },\n ref,\n ) {\n const today = useMemo(() => new Date(), []);\n const [viewMonth, setViewMonth] = useState(today.getMonth());\n const [viewYear, setViewYear] = useState(today.getFullYear());\n const [rangeHover, setRangeHover] = useState<Date | null>(null);\n\n const days = useMemo(\n () => getDaysInMonth(viewYear, viewMonth),\n [viewYear, viewMonth],\n );\n\n const prevMonth = useCallback(() => {\n setViewMonth((m) => {\n if (m === 0) {\n setViewYear((y) => y - 1);\n return 11;\n }\n return m - 1;\n });\n }, []);\n\n const nextMonth = useCallback(() => {\n setViewMonth((m) => {\n if (m === 11) {\n setViewYear((y) => y + 1);\n return 0;\n }\n return m + 1;\n });\n }, []);\n\n const isDisabled = useCallback(\n (date: Date): boolean => {\n if (minDate && date < minDate) return true;\n if (maxDate && date > maxDate) return true;\n return disabledDates.some((d) => isSameDay(d, date));\n },\n [minDate, maxDate, disabledDates],\n );\n\n const isSelected = useCallback(\n (date: Date): boolean => {\n if (!value) return false;\n if (mode === \"single\" && value instanceof Date) {\n return isSameDay(date, value);\n }\n if (mode === \"multiple\" && Array.isArray(value)) {\n return value.some((v) => isSameDay(date, v));\n }\n if (mode === \"range\" && value && typeof value === \"object\" && \"start\" in value) {\n const range = value as DateRange;\n if (range.start && isSameDay(date, range.start)) return true;\n if (range.end && isSameDay(date, range.end)) return true;\n }\n return false;\n },\n [value, mode],\n );\n\n const isInRange = useCallback(\n (date: Date): boolean => {\n if (mode !== \"range\" || !value || typeof value !== \"object\" || !(\"start\" in value))\n return false;\n const range = value as DateRange;\n if (!range.start) return false;\n const end = range.end ?? rangeHover;\n if (!end) return false;\n const [s, e] = range.start <= end ? [range.start, end] : [end, range.start];\n return date > s && date < e;\n },\n [value, mode, rangeHover],\n );\n\n const handleSelect = useCallback(\n (date: Date) => {\n if (isDisabled(date)) return;\n\n if (mode === \"single\") {\n onChange?.(date);\n } else if (mode === \"multiple\") {\n const arr = (Array.isArray(value) ? value : []) as Date[];\n const exists = arr.findIndex((d) => isSameDay(d, date));\n if (exists >= 0) {\n onChange?.(arr.filter((_, i) => i !== exists));\n } else {\n onChange?.([...arr, date]);\n }\n } else if (mode === \"range\") {\n const range = (value && typeof value === \"object\" && \"start\" in value\n ? value\n : { start: null, end: null }) as DateRange;\n\n if (!range.start || range.end) {\n onChange?.({ start: date, end: null });\n } else {\n const [s, e] =\n date >= range.start ? [range.start, date] : [date, range.start];\n onChange?.({ start: s, end: e });\n }\n }\n },\n [mode, value, onChange, isDisabled],\n );\n\n const btnBase =\n \"flex h-8 w-8 items-center justify-center rounded-lg text-sm transition-colors\";\n\n return (\n <div\n data-react-fancy-calendar=\"\"\n ref={ref}\n className={cn(\n \"inline-block w-72 rounded-xl border border-[color:var(--fancy-border,var(--color-zinc-200))] bg-[color:var(--fancy-surface,var(--color-white))] p-4 dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))] dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\",\n className,\n )}\n >\n {/* Header */}\n <div className=\"mb-3 flex items-center justify-between\">\n <button\n type=\"button\"\n onClick={prevMonth}\n className=\"rounded-lg p-1 text-zinc-400 hover:bg-[color:var(--fancy-surface-muted,var(--color-zinc-100))] dark:hover:bg-[color:var(--fancy-surface-muted-dark,var(--color-zinc-800))]\"\n aria-label=\"Previous month\"\n >\n <ChevronLeft size={16} />\n </button>\n <span className=\"text-sm font-semibold\">\n {MONTHS[viewMonth]} {viewYear}\n </span>\n <button\n type=\"button\"\n onClick={nextMonth}\n className=\"rounded-lg p-1 text-zinc-400 hover:bg-[color:var(--fancy-surface-muted,var(--color-zinc-100))] dark:hover:bg-[color:var(--fancy-surface-muted-dark,var(--color-zinc-800))]\"\n aria-label=\"Next month\"\n >\n <ChevronRight size={16} />\n </button>\n </div>\n\n {/* Day headers */}\n <div className=\"mb-1 grid grid-cols-7 gap-1\">\n {DAYS.map((d) => (\n <div\n key={d}\n className=\"flex h-8 items-center justify-center text-xs font-medium text-zinc-400\"\n >\n {d}\n </div>\n ))}\n </div>\n\n {/* Day grid */}\n <div className=\"grid grid-cols-7 gap-1\">\n {days.map((date, i) => {\n const isCurrentMonth = date.getMonth() === viewMonth;\n const selected = isSelected(date);\n const inRange = isInRange(date);\n const disabled = isDisabled(date);\n const isToday = isSameDay(date, today);\n\n return (\n <button\n key={i}\n type=\"button\"\n disabled={disabled}\n onClick={() => handleSelect(date)}\n onMouseEnter={() =>\n mode === \"range\" && setRangeHover(date)\n }\n className={cn(\n btnBase,\n !isCurrentMonth && \"text-zinc-300 dark:text-zinc-600\",\n isCurrentMonth &&\n !selected &&\n !inRange &&\n \"text-[color:var(--fancy-text-soft,var(--color-zinc-700))] hover:bg-[color:var(--fancy-surface-muted,var(--color-zinc-100))] dark:text-[color:var(--fancy-text-soft-dark,var(--color-zinc-300))] dark:hover:bg-[color:var(--fancy-surface-muted-dark,var(--color-zinc-800))]\",\n inRange &&\n \"bg-blue-50 text-blue-700 dark:bg-blue-950 dark:text-blue-300\",\n selected &&\n \"bg-zinc-900 text-white dark:bg-white dark:text-zinc-900\",\n isToday && !selected && \"font-bold\",\n disabled && \"cursor-not-allowed opacity-30\",\n )}\n >\n {date.getDate()}\n </button>\n );\n })}\n </div>\n </div>\n );\n },\n);\n\nCalendar.displayName = \"Calendar\";\n"]}
|