@codecademy/gamut 68.1.3-alpha.bcf87d.0 → 68.1.3-alpha.f719db.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/dist/Alert/elements.d.ts +4 -4
- package/dist/Anchor/index.d.ts +18 -9
- package/dist/Anchor/index.js +9 -6
- package/dist/Box/Box.d.ts +1 -1
- package/dist/Box/FlexBox.d.ts +1 -1
- package/dist/Box/GridBox.d.ts +2 -1
- package/dist/Box/GridBox.js +1 -1
- package/dist/Box/props.d.ts +1 -1
- package/dist/Button/CTAButton.d.ts +2 -2
- package/dist/Button/FillButton.d.ts +4 -4
- package/dist/Button/IconButton.d.ts +4 -4
- package/dist/Button/StrokeButton.d.ts +4 -4
- package/dist/Button/TextButton.d.ts +4 -4
- package/dist/Button/shared/InlineIconButton.d.ts +2 -2
- package/dist/Button/shared/styles.d.ts +3 -3
- package/dist/Button/shared/types.d.ts +1 -1
- package/dist/ButtonBase/ButtonBase.d.ts +9 -4
- package/dist/ButtonBase/ButtonBase.js +11 -4
- package/dist/Card/elements.d.ts +187 -139
- package/dist/Card/styles.d.ts +8 -8
- package/dist/Coachmark/index.d.ts +1 -1
- package/dist/ConnectedForm/ConnectedForm.d.ts +1 -1
- package/dist/ConnectedForm/utils.d.ts +3 -3
- package/dist/ContentContainer/index.d.ts +1 -1
- package/dist/Disclosure/elements.d.ts +20 -14
- package/dist/FeatureShimmer/index.js +1 -1
- package/dist/FocusTrap/index.d.ts +2 -2
- package/dist/Form/SelectDropdown/elements/controls.js +2 -2
- package/dist/Form/SelectDropdown/elements/multi-value.js +2 -2
- package/dist/Form/SelectDropdown/types/internal.d.ts +2 -2
- package/dist/Form/elements/Form.d.ts +15 -15
- package/dist/Form/elements/FormGroup.d.ts +2 -2
- package/dist/GridForm/GridFormButtons/index.d.ts +4 -4
- package/dist/InternalFloatingCard/InternalFloatingCard.d.ts +1 -1
- package/dist/Layout/Column.d.ts +1 -1
- package/dist/Layout/LayoutGrid.d.ts +1 -1
- package/dist/List/ListProvider.d.ts +1 -1
- package/dist/List/elements.d.ts +76 -60
- package/dist/List/hooks.d.ts +1 -1
- package/dist/Menu/Menu.d.ts +1 -1
- package/dist/Menu/MenuItem.js +10 -6
- package/dist/Menu/elements.d.ts +4 -4
- package/dist/Modals/elements.d.ts +1 -1
- package/dist/Pagination/AnimatedPaginationButtons.d.ts +61 -45
- package/dist/Pagination/EllipsisButton.d.ts +4 -4
- package/dist/Pagination/PaginationButton.d.ts +6 -6
- package/dist/Pagination/utils.d.ts +59 -43
- package/dist/Pagination/utils.js +14 -11
- package/dist/Popover/Popover.js +4 -4
- package/dist/Popover/elements.d.ts +2 -2
- package/dist/Popover/types.d.ts +3 -2
- package/dist/PopoverContainer/PopoverContainer.js +9 -13
- package/dist/PopoverContainer/hooks.d.ts +16 -4
- package/dist/PopoverContainer/hooks.js +31 -24
- package/dist/PopoverContainer/types.d.ts +3 -7
- package/dist/Tabs/TabButton.d.ts +2 -2
- package/dist/Tabs/TabNav.d.ts +1 -1
- package/dist/Tabs/TabNavLink.d.ts +2 -2
- package/dist/Tag/elements.d.ts +18 -12
- package/dist/Tip/InfoTip/InfoTipButton.d.ts +4 -4
- package/dist/Tip/InfoTip/styles.d.ts +1 -1
- package/dist/Tip/PreviewTip/elements.d.ts +13 -7
- package/dist/Tip/ToolTip/elements.d.ts +1 -1
- package/dist/Tip/__tests__/helpers.d.ts +3 -3
- package/dist/Tip/shared/FloatingTip.js +2 -2
- package/dist/Tip/shared/elements.d.ts +3 -3
- package/dist/Tip/shared/types.d.ts +2 -2
- package/dist/Toggle/elements.d.ts +1 -1
- package/dist/Typography/Text.d.ts +3 -3
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/utils/react.js +2 -1
- package/package.json +10 -10
- package/dist/DatePicker/Calendar/Calendar.d.ts +0 -11
- package/dist/DatePicker/Calendar/Calendar.js +0 -15
- package/dist/DatePicker/Calendar/CalendarBody.d.ts +0 -3
- package/dist/DatePicker/Calendar/CalendarBody.js +0 -155
- package/dist/DatePicker/Calendar/CalendarFooter.d.ts +0 -3
- package/dist/DatePicker/Calendar/CalendarFooter.js +0 -60
- package/dist/DatePicker/Calendar/CalendarHeader.d.ts +0 -3
- package/dist/DatePicker/Calendar/CalendarHeader.js +0 -63
- package/dist/DatePicker/Calendar/index.d.ts +0 -6
- package/dist/DatePicker/Calendar/index.js +0 -5
- package/dist/DatePicker/Calendar/types.d.ts +0 -59
- package/dist/DatePicker/Calendar/types.js +0 -1
- package/dist/DatePicker/Calendar/utils/dateGrid.d.ts +0 -30
- package/dist/DatePicker/Calendar/utils/dateGrid.js +0 -93
- package/dist/DatePicker/Calendar/utils/format.d.ts +0 -39
- package/dist/DatePicker/Calendar/utils/format.js +0 -130
- package/dist/DatePicker/Calendar/utils/index.d.ts +0 -3
- package/dist/DatePicker/Calendar/utils/index.js +0 -3
- package/dist/DatePicker/Calendar/utils/keyHandler.d.ts +0 -13
- package/dist/DatePicker/Calendar/utils/keyHandler.js +0 -116
- package/dist/DatePicker/Calendar/utils/validation.d.ts +0 -13
- package/dist/DatePicker/Calendar/utils/validation.js +0 -23
- package/dist/DatePicker/DatePicker.d.ts +0 -8
- package/dist/DatePicker/DatePicker.js +0 -127
- package/dist/DatePicker/DatePickerCalendar.d.ts +0 -13
- package/dist/DatePicker/DatePickerCalendar.js +0 -127
- package/dist/DatePicker/DatePickerContext.d.ts +0 -11
- package/dist/DatePicker/DatePickerContext.js +0 -18
- package/dist/DatePicker/DatePickerInput.d.ts +0 -16
- package/dist/DatePicker/DatePickerInput.js +0 -126
- package/dist/DatePicker/index.d.ts +0 -13
- package/dist/DatePicker/index.js +0 -10
- package/dist/DatePicker/types.d.ts +0 -76
- package/dist/DatePicker/types.js +0 -1
- package/dist/DatePicker/utils.d.ts +0 -3
- package/dist/DatePicker/utils.js +0 -71
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Builds a grid of days for a calendar month using native Date and Intl.
|
|
3
|
-
* Each row has 7 cells; leading/trailing cells may be null (padding from adjacent months).
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const DAYS_PER_WEEK = 7;
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Normalize to start of day in local time for comparison.
|
|
10
|
-
*/
|
|
11
|
-
const toDateOnly = date => {
|
|
12
|
-
return new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Get the weekday for a date (0 = Sunday, 6 = Saturday).
|
|
17
|
-
* Optionally use weekStartsOn to compute "offset" for display (e.g. Monday = 0).
|
|
18
|
-
*/
|
|
19
|
-
export const getDayOfWeek = (date, weekStartsOn = 0) => {
|
|
20
|
-
const sundayBased = date.getDay();
|
|
21
|
-
if (weekStartsOn === 0) return sundayBased;
|
|
22
|
-
return (sundayBased + 6) % 7; // Monday = 0
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Returns an array of weeks for the given month. Each week is an array of 7 items:
|
|
27
|
-
* each item is either a Date (that day) or null (padding from previous/next month).
|
|
28
|
-
*
|
|
29
|
-
* @param year - Full year (e.g. 2026)
|
|
30
|
-
* @param month - Month 0-11 (0 = January)
|
|
31
|
-
* @param weekStartsOn - 0 = Sunday, 1 = Monday
|
|
32
|
-
*/
|
|
33
|
-
export const getMonthGrid = (year, month, weekStartsOn = 0) => {
|
|
34
|
-
const first = new Date(year, month, 1);
|
|
35
|
-
const last = new Date(year, month + 1, 0);
|
|
36
|
-
const firstDayOfWeek = getDayOfWeek(first, weekStartsOn);
|
|
37
|
-
const daysInMonth = last.getDate();
|
|
38
|
-
const weeks = [];
|
|
39
|
-
let currentWeek = [];
|
|
40
|
-
|
|
41
|
-
// Pad start of first week with nulls
|
|
42
|
-
// eslint-disable-next-line no-plusplus
|
|
43
|
-
for (let i = 0; i < firstDayOfWeek; i++) {
|
|
44
|
-
currentWeek.push(null);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// fix these
|
|
48
|
-
// eslint-disable-next-line no-plusplus
|
|
49
|
-
for (let day = 1; day <= daysInMonth; day++) {
|
|
50
|
-
currentWeek.push(new Date(year, month, day));
|
|
51
|
-
if (currentWeek.length === DAYS_PER_WEEK) {
|
|
52
|
-
weeks.push(currentWeek);
|
|
53
|
-
currentWeek = [];
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Pad end of last week with nulls
|
|
58
|
-
if (currentWeek.length > 0) {
|
|
59
|
-
while (currentWeek.length < DAYS_PER_WEEK) {
|
|
60
|
-
currentWeek.push(null);
|
|
61
|
-
}
|
|
62
|
-
weeks.push(currentWeek);
|
|
63
|
-
}
|
|
64
|
-
return weeks;
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Check if two dates are the same calendar day (ignoring time).
|
|
69
|
-
*/
|
|
70
|
-
export const isSameDay = (a, b) => {
|
|
71
|
-
if (a === null || b === null) return false;
|
|
72
|
-
return toDateOnly(a).getTime() === toDateOnly(b).getTime();
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Check if `date` is between `start` and `end` (exclusive), ignoring time.
|
|
77
|
-
*/
|
|
78
|
-
export const isDateInRange = (date, start, end) => {
|
|
79
|
-
if (start === null) return false;
|
|
80
|
-
const normalizedDateTime = toDateOnly(date).getTime();
|
|
81
|
-
const normalizedStartDateTime = toDateOnly(start).getTime();
|
|
82
|
-
const normalizedEndDateTime = end !== null ? toDateOnly(end).getTime() : normalizedStartDateTime;
|
|
83
|
-
const low = Math.min(normalizedStartDateTime, normalizedEndDateTime);
|
|
84
|
-
const high = Math.max(normalizedStartDateTime, normalizedEndDateTime);
|
|
85
|
-
return normalizedDateTime > low && normalizedDateTime < high;
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Check if `date` is in the `disabledDates` list (by calendar day).
|
|
90
|
-
*/
|
|
91
|
-
export const isDateDisabled = (date, disabledDates = []) => {
|
|
92
|
-
return disabledDates.some(d => isSameDay(date, d));
|
|
93
|
-
};
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Date formatting for the calendar using Intl.DateTimeFormat.
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* Format month and year for the calendar header (e.g. "February 2026").
|
|
6
|
-
*/
|
|
7
|
-
export declare const formatMonthYear: (date: Date, locale?: string) => string;
|
|
8
|
-
/**
|
|
9
|
-
* Get short weekday labels for column headers (e.g. ["Su", "Mo", ...]).
|
|
10
|
-
* Order depends on weekStartsOn: 0 = Sunday first, 1 = Monday first.
|
|
11
|
-
*/
|
|
12
|
-
export declare const getWeekdayLabels: (locale?: string, weekStartsOn?: 0 | 1) => string[];
|
|
13
|
-
/**
|
|
14
|
-
* Get full weekday names for abbr attributes (e.g. "Sunday", "Monday").
|
|
15
|
-
* Same order as getWeekdayLabels.
|
|
16
|
-
*/
|
|
17
|
-
export declare const getWeekdayFullNames: (locale?: string, weekStartsOn?: 0 | 1) => string[];
|
|
18
|
-
/**
|
|
19
|
-
* Format a date for display in the date picker input (e.g. "2/15/2026").
|
|
20
|
-
*/
|
|
21
|
-
export declare const formatDateForInput: (date: Date, locale?: string) => string;
|
|
22
|
-
/**
|
|
23
|
-
* Parse a string from the date input into a Date, or null if invalid.
|
|
24
|
-
* Only returns a date when the input is a complete valid date (e.g. "2/15/2026").
|
|
25
|
-
* Partial input like "1" or "2/15" returns null even though Date("1") would parse.
|
|
26
|
-
*/
|
|
27
|
-
export declare const parseDateFromInput: (value: string, locale?: string) => Date | null;
|
|
28
|
-
/**
|
|
29
|
-
* Format a date range for the input (e.g. "2/15/2026 – 2/20/2026").
|
|
30
|
-
*/
|
|
31
|
-
export declare const formatDateRangeForInput: (startDate: Date | null, endDate: Date | null, locale?: string) => string;
|
|
32
|
-
/**
|
|
33
|
-
* Parse a range string (e.g. "2/15/2026 – 2/20/2026") into { startDate, endDate }.
|
|
34
|
-
* Returns null if invalid. Single date is allowed and yields startDate = endDate.
|
|
35
|
-
*/
|
|
36
|
-
export declare const parseDateRangeFromInput: (value: string, locale?: string) => {
|
|
37
|
-
startDate: Date;
|
|
38
|
-
endDate: Date;
|
|
39
|
-
} | null;
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Date formatting for the calendar using Intl.DateTimeFormat.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Format month and year for the calendar header (e.g. "February 2026").
|
|
7
|
-
*/
|
|
8
|
-
export const formatMonthYear = (date, locale) => {
|
|
9
|
-
return new Intl.DateTimeFormat(locale ?? 'en-US', {
|
|
10
|
-
month: 'long',
|
|
11
|
-
year: 'numeric'
|
|
12
|
-
}).format(date);
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Get short weekday labels for column headers (e.g. ["Su", "Mo", ...]).
|
|
17
|
-
* Order depends on weekStartsOn: 0 = Sunday first, 1 = Monday first.
|
|
18
|
-
*/
|
|
19
|
-
export const getWeekdayLabels = (locale, weekStartsOn = 0) => {
|
|
20
|
-
const formatter = new Intl.DateTimeFormat(locale ?? 'en-US', {
|
|
21
|
-
weekday: 'short'
|
|
22
|
-
});
|
|
23
|
-
// Jan 7, 2024 is a Sunday; add 0..6 days to get Sun..Sat
|
|
24
|
-
const sunday = new Date(2024, 0, 7);
|
|
25
|
-
const labels = Array.from({
|
|
26
|
-
length: 7
|
|
27
|
-
}, (_, i) => {
|
|
28
|
-
const d = new Date(sunday);
|
|
29
|
-
d.setDate(sunday.getDate() + i);
|
|
30
|
-
return formatter.format(d);
|
|
31
|
-
});
|
|
32
|
-
if (weekStartsOn === 1) {
|
|
33
|
-
return [...labels.slice(1), labels[0]];
|
|
34
|
-
}
|
|
35
|
-
return labels;
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Get full weekday names for abbr attributes (e.g. "Sunday", "Monday").
|
|
40
|
-
* Same order as getWeekdayLabels.
|
|
41
|
-
*/
|
|
42
|
-
export const getWeekdayFullNames = (locale, weekStartsOn = 0) => {
|
|
43
|
-
const formatter = new Intl.DateTimeFormat(locale ?? 'en-US', {
|
|
44
|
-
weekday: 'long'
|
|
45
|
-
});
|
|
46
|
-
const sunday = new Date(2024, 0, 7);
|
|
47
|
-
const names = Array.from({
|
|
48
|
-
length: 7
|
|
49
|
-
}, (_, i) => {
|
|
50
|
-
const d = new Date(sunday);
|
|
51
|
-
d.setDate(sunday.getDate() + i);
|
|
52
|
-
return formatter.format(d);
|
|
53
|
-
});
|
|
54
|
-
if (weekStartsOn === 1) {
|
|
55
|
-
return [...names.slice(1), names[0]];
|
|
56
|
-
}
|
|
57
|
-
return names;
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Format a date for display in the date picker input (e.g. "2/15/2026").
|
|
62
|
-
*/
|
|
63
|
-
export const formatDateForInput = (date, locale) => {
|
|
64
|
-
return new Intl.DateTimeFormat(locale ?? 'en-US', {
|
|
65
|
-
month: 'numeric',
|
|
66
|
-
day: 'numeric',
|
|
67
|
-
year: 'numeric'
|
|
68
|
-
}).format(date);
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Parse a string from the date input into a Date, or null if invalid.
|
|
73
|
-
* Only returns a date when the input is a complete valid date (e.g. "2/15/2026").
|
|
74
|
-
* Partial input like "1" or "2/15" returns null even though Date("1") would parse.
|
|
75
|
-
*/
|
|
76
|
-
|
|
77
|
-
// this logic needs some work
|
|
78
|
-
export const parseDateFromInput = (value, locale) => {
|
|
79
|
-
const trimmed = value.trim();
|
|
80
|
-
if (!trimmed) return null;
|
|
81
|
-
const parsed = new Date(trimmed);
|
|
82
|
-
if (Number.isNaN(parsed.getTime())) return null;
|
|
83
|
-
const formatted = formatDateForInput(parsed, locale);
|
|
84
|
-
if (formatted === trimmed) return parsed;
|
|
85
|
-
const parts = trimmed.split(/[/-]/);
|
|
86
|
-
if (parts.length >= 3) return parsed;
|
|
87
|
-
return null;
|
|
88
|
-
};
|
|
89
|
-
const RANGE_SEPARATOR = ' – ';
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Format a date range for the input (e.g. "2/15/2026 – 2/20/2026").
|
|
93
|
-
*/
|
|
94
|
-
export const formatDateRangeForInput = (startDate, endDate, locale) => {
|
|
95
|
-
if (!startDate && !endDate) return '';
|
|
96
|
-
if (!startDate) return formatDateForInput(endDate, locale);
|
|
97
|
-
if (!endDate) return formatDateForInput(startDate, locale);
|
|
98
|
-
return `${formatDateForInput(startDate, locale)}${RANGE_SEPARATOR}${formatDateForInput(endDate, locale)}`;
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Parse a range string (e.g. "2/15/2026 – 2/20/2026") into { startDate, endDate }.
|
|
103
|
-
* Returns null if invalid. Single date is allowed and yields startDate = endDate.
|
|
104
|
-
*/
|
|
105
|
-
export const parseDateRangeFromInput = (value, locale) => {
|
|
106
|
-
const trimmed = value.trim();
|
|
107
|
-
if (!trimmed) return null;
|
|
108
|
-
const parts = trimmed.split(RANGE_SEPARATOR).map(s => s.trim());
|
|
109
|
-
if (parts.length === 1) {
|
|
110
|
-
const d = parseDateFromInput(parts[0], locale);
|
|
111
|
-
if (!d) return null;
|
|
112
|
-
return {
|
|
113
|
-
startDate: d,
|
|
114
|
-
endDate: new Date(d)
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
if (parts.length === 2) {
|
|
118
|
-
const start = parseDateFromInput(parts[0], locale);
|
|
119
|
-
const end = parseDateFromInput(parts[1], locale);
|
|
120
|
-
if (!start || !end) return null;
|
|
121
|
-
return start.getTime() <= end.getTime() ? {
|
|
122
|
-
startDate: start,
|
|
123
|
-
endDate: end
|
|
124
|
-
} : {
|
|
125
|
-
startDate: end,
|
|
126
|
-
endDate: start
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
return null;
|
|
130
|
-
};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Clamp a day to the last day of the given month (e.g. Jan 31 -> Feb 28).
|
|
3
|
-
*/
|
|
4
|
-
export declare const clampToMonth: (year: number, month: number, day: number) => Date;
|
|
5
|
-
/** Flat list of dates in grid order (row-major, non-null only) with row index for Home/End */
|
|
6
|
-
export declare const getDatesWithRow: (weeks: (Date | null)[][]) => {
|
|
7
|
-
date: Date;
|
|
8
|
-
rowIndex: number;
|
|
9
|
-
}[];
|
|
10
|
-
export declare const keyHandler: (e: React.KeyboardEvent, date: Date, onFocusedDateChange: (date: Date | null) => void, datesWithRow: {
|
|
11
|
-
date: Date;
|
|
12
|
-
rowIndex: number;
|
|
13
|
-
}[], month: number, year: number, disabledDates: Date[], onDateSelect: (date: Date) => void, onEscapeKeyPress?: () => void, onVisibleDateChange?: ((newDate: Date) => void) | undefined) => void;
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import { isDateDisabled } from './dateGrid';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Clamp a day to the last day of the given month (e.g. Jan 31 -> Feb 28).
|
|
5
|
-
*/
|
|
6
|
-
export const clampToMonth = (year, month, day) => {
|
|
7
|
-
const last = new Date(year, month + 1, 0).getDate();
|
|
8
|
-
return new Date(year, month, Math.min(day, last));
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
/** Flat list of dates in grid order (row-major, non-null only) with row index for Home/End */
|
|
12
|
-
export const getDatesWithRow = weeks => {
|
|
13
|
-
const result = [];
|
|
14
|
-
weeks.forEach((week, rowIndex) => {
|
|
15
|
-
week.forEach(date => {
|
|
16
|
-
if (date !== null) result.push({
|
|
17
|
-
date,
|
|
18
|
-
rowIndex
|
|
19
|
-
});
|
|
20
|
-
});
|
|
21
|
-
});
|
|
22
|
-
return result;
|
|
23
|
-
};
|
|
24
|
-
export const keyHandler = (e, date, onFocusedDateChange, datesWithRow, month, year, disabledDates, onDateSelect, onEscapeKeyPress, onVisibleDateChange) => {
|
|
25
|
-
const key = date.getTime();
|
|
26
|
-
const idx = datesWithRow.findIndex(({
|
|
27
|
-
date: d
|
|
28
|
-
}) => d.getTime() === key);
|
|
29
|
-
if (idx < 0) return;
|
|
30
|
-
const currentRow = datesWithRow[idx].rowIndex;
|
|
31
|
-
const day = date.getDate();
|
|
32
|
-
let newDate = null;
|
|
33
|
-
let newVisibleDate = null;
|
|
34
|
-
switch (e.key) {
|
|
35
|
-
case 'ArrowLeft':
|
|
36
|
-
e.preventDefault();
|
|
37
|
-
if (idx > 0) {
|
|
38
|
-
newDate = datesWithRow[idx - 1].date;
|
|
39
|
-
} else {
|
|
40
|
-
const lastDayPrevMonth = new Date(year, month, 0);
|
|
41
|
-
newDate = lastDayPrevMonth;
|
|
42
|
-
newVisibleDate = new Date(year, month - 1, 1);
|
|
43
|
-
}
|
|
44
|
-
break;
|
|
45
|
-
case 'ArrowRight':
|
|
46
|
-
e.preventDefault();
|
|
47
|
-
if (idx < datesWithRow.length - 1) {
|
|
48
|
-
newDate = datesWithRow[idx + 1].date;
|
|
49
|
-
} else {
|
|
50
|
-
newDate = new Date(year, month + 1, 1);
|
|
51
|
-
newVisibleDate = new Date(year, month + 1, 1);
|
|
52
|
-
}
|
|
53
|
-
break;
|
|
54
|
-
case 'ArrowUp':
|
|
55
|
-
e.preventDefault();
|
|
56
|
-
newDate = new Date(date);
|
|
57
|
-
newDate.setDate(newDate.getDate() - 7);
|
|
58
|
-
if (newDate.getMonth() !== month || newDate.getFullYear() !== year) {
|
|
59
|
-
newVisibleDate = new Date(newDate.getFullYear(), newDate.getMonth(), 1);
|
|
60
|
-
}
|
|
61
|
-
break;
|
|
62
|
-
case 'ArrowDown':
|
|
63
|
-
e.preventDefault();
|
|
64
|
-
newDate = new Date(date);
|
|
65
|
-
newDate.setDate(newDate.getDate() + 7);
|
|
66
|
-
if (newDate.getMonth() !== month || newDate.getFullYear() !== year) {
|
|
67
|
-
newVisibleDate = new Date(newDate.getFullYear(), newDate.getMonth(), 1);
|
|
68
|
-
}
|
|
69
|
-
break;
|
|
70
|
-
case 'Home':
|
|
71
|
-
e.preventDefault();
|
|
72
|
-
newDate = datesWithRow.find(({
|
|
73
|
-
rowIndex
|
|
74
|
-
}) => rowIndex === currentRow)?.date ?? date;
|
|
75
|
-
break;
|
|
76
|
-
case 'End':
|
|
77
|
-
e.preventDefault();
|
|
78
|
-
newDate = [...datesWithRow].reverse().find(({
|
|
79
|
-
rowIndex
|
|
80
|
-
}) => rowIndex === currentRow)?.date ?? date;
|
|
81
|
-
break;
|
|
82
|
-
case 'PageDown':
|
|
83
|
-
e.preventDefault();
|
|
84
|
-
if (e.shiftKey) {
|
|
85
|
-
newDate = clampToMonth(year + 1, month, day);
|
|
86
|
-
} else {
|
|
87
|
-
newDate = clampToMonth(year, month + 1, day);
|
|
88
|
-
}
|
|
89
|
-
newVisibleDate = new Date(newDate.getFullYear(), newDate.getMonth(), 1);
|
|
90
|
-
break;
|
|
91
|
-
case 'PageUp':
|
|
92
|
-
e.preventDefault();
|
|
93
|
-
if (e.shiftKey) {
|
|
94
|
-
newDate = clampToMonth(year - 1, month, day);
|
|
95
|
-
} else {
|
|
96
|
-
newDate = clampToMonth(year, month - 1, day);
|
|
97
|
-
}
|
|
98
|
-
newVisibleDate = new Date(newDate.getFullYear(), newDate.getMonth(), 1);
|
|
99
|
-
break;
|
|
100
|
-
case 'Enter':
|
|
101
|
-
case ' ':
|
|
102
|
-
e.preventDefault();
|
|
103
|
-
if (!isDateDisabled(date, disabledDates)) onDateSelect(date);
|
|
104
|
-
return;
|
|
105
|
-
case 'Escape':
|
|
106
|
-
e.preventDefault();
|
|
107
|
-
onEscapeKeyPress?.();
|
|
108
|
-
return;
|
|
109
|
-
default:
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
if (newDate !== null) {
|
|
113
|
-
onFocusedDateChange(newDate);
|
|
114
|
-
if (newVisibleDate !== null) onVisibleDateChange?.(newVisibleDate);
|
|
115
|
-
}
|
|
116
|
-
};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Validation helpers for DatePicker (single-date).
|
|
3
|
-
* Used to mark invalid dates as unselectable and for manual entry validation.
|
|
4
|
-
*/
|
|
5
|
-
/**
|
|
6
|
-
* Check if a date is in the past (before today at start of day).
|
|
7
|
-
* Useful for disabling past dates in the calendar.
|
|
8
|
-
*/
|
|
9
|
-
export declare const isPastDate: (date: Date) => boolean;
|
|
10
|
-
/**
|
|
11
|
-
* Check if a date is valid (finite and not NaN).
|
|
12
|
-
*/
|
|
13
|
-
export declare const isValidDate: (date: Date) => boolean;
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Validation helpers for DatePicker (single-date).
|
|
3
|
-
* Used to mark invalid dates as unselectable and for manual entry validation.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Check if a date is in the past (before today at start of day).
|
|
8
|
-
* Useful for disabling past dates in the calendar.
|
|
9
|
-
*/
|
|
10
|
-
export const isPastDate = date => {
|
|
11
|
-
const today = new Date();
|
|
12
|
-
today.setHours(0, 0, 0, 0);
|
|
13
|
-
const normalizedDate = new Date(date);
|
|
14
|
-
normalizedDate.setHours(0, 0, 0, 0);
|
|
15
|
-
return normalizedDate.getTime() < today.getTime();
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Check if a date is valid (finite and not NaN).
|
|
20
|
-
*/
|
|
21
|
-
export const isValidDate = date => {
|
|
22
|
-
return date instanceof Date && !Number.isNaN(date.getTime());
|
|
23
|
-
};
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/// <reference types="react" />
|
|
2
|
-
import type { DatePickerProps } from './types';
|
|
3
|
-
/**
|
|
4
|
-
* DatePicker: single-date or range. Holds shared state and provides it via context.
|
|
5
|
-
* Single: selectedDate, setSelectedDate. Range: startDate, endDate, setStartDate, setEndDate.
|
|
6
|
-
* With no children, renders default layout (input + calendar popover).
|
|
7
|
-
*/
|
|
8
|
-
export declare const DatePicker: React.FC<DatePickerProps>;
|
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import { useCallback, useId, useMemo, useRef, useState } from 'react';
|
|
2
|
-
import { FlexBox } from '../Box';
|
|
3
|
-
import { PopoverContainer } from '../PopoverContainer';
|
|
4
|
-
import { DatePickerCalendar } from './DatePickerCalendar';
|
|
5
|
-
import { DatePickerProvider } from './DatePickerContext';
|
|
6
|
-
import { DatePickerInput } from './DatePickerInput';
|
|
7
|
-
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
8
|
-
function isRangeProps(props) {
|
|
9
|
-
return props.mode === 'range';
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* DatePicker: single-date or range. Holds shared state and provides it via context.
|
|
14
|
-
* Single: selectedDate, setSelectedDate. Range: startDate, endDate, setStartDate, setEndDate.
|
|
15
|
-
* With no children, renders default layout (input + calendar popover).
|
|
16
|
-
*/
|
|
17
|
-
export const DatePicker = props => {
|
|
18
|
-
const {
|
|
19
|
-
locale = 'en-US',
|
|
20
|
-
disabledDates = [],
|
|
21
|
-
placeholder,
|
|
22
|
-
mode,
|
|
23
|
-
children
|
|
24
|
-
} = props;
|
|
25
|
-
const [isCalendarOpen, setIsCalendarOpen] = useState(false);
|
|
26
|
-
const [activeRangePart, setActiveRangePart] = useState(null);
|
|
27
|
-
const inputRef = useRef(null);
|
|
28
|
-
const dialogId = useId();
|
|
29
|
-
const calendarDialogId = `datepicker-dialog-${dialogId.replace(/:/g, '')}`;
|
|
30
|
-
const openCalendar = useCallback(() => setIsCalendarOpen(true), []);
|
|
31
|
-
const closeCalendar = useCallback(() => {
|
|
32
|
-
setIsCalendarOpen(false);
|
|
33
|
-
setActiveRangePart(null);
|
|
34
|
-
inputRef.current?.focus();
|
|
35
|
-
}, []);
|
|
36
|
-
const startOrSelectedDate = isRangeProps(props) ? props.startDate : props.selectedDate;
|
|
37
|
-
const endDate = isRangeProps(props) ? props.endDate : null;
|
|
38
|
-
const setSelection = useCallback((start, end) => {
|
|
39
|
-
if (isRangeProps(props)) {
|
|
40
|
-
props.setStartDate(start);
|
|
41
|
-
props.setEndDate(end ?? null);
|
|
42
|
-
} else {
|
|
43
|
-
props.setSelectedDate(start);
|
|
44
|
-
}
|
|
45
|
-
}, [props]);
|
|
46
|
-
const contextValue = useMemo(() => {
|
|
47
|
-
const base = {
|
|
48
|
-
startOrSelectedDate,
|
|
49
|
-
setSelection,
|
|
50
|
-
isCalendarOpen,
|
|
51
|
-
openCalendar,
|
|
52
|
-
closeCalendar,
|
|
53
|
-
locale,
|
|
54
|
-
disabledDates,
|
|
55
|
-
calendarDialogId
|
|
56
|
-
};
|
|
57
|
-
return mode === 'range' ? {
|
|
58
|
-
...base,
|
|
59
|
-
mode: 'range',
|
|
60
|
-
endDate,
|
|
61
|
-
activeRangePart,
|
|
62
|
-
setActiveRangePart
|
|
63
|
-
} : {
|
|
64
|
-
...base,
|
|
65
|
-
mode: 'single'
|
|
66
|
-
};
|
|
67
|
-
}, [mode, startOrSelectedDate, endDate, setSelection, activeRangePart, setActiveRangePart, isCalendarOpen, openCalendar, closeCalendar, locale, disabledDates, calendarDialogId]);
|
|
68
|
-
|
|
69
|
-
// what is this doing
|
|
70
|
-
// useEffect(() => {
|
|
71
|
-
// if (!isCalendarOpen) return;
|
|
72
|
-
// const id = setTimeout(() => inputRef.current?.focus(), 0);
|
|
73
|
-
// return () => clearTimeout(id);
|
|
74
|
-
// }, [isCalendarOpen]);
|
|
75
|
-
|
|
76
|
-
const content = children !== undefined ? children : /*#__PURE__*/_jsxs(_Fragment, {
|
|
77
|
-
children: [/*#__PURE__*/_jsx(FlexBox, {
|
|
78
|
-
gap: 8,
|
|
79
|
-
width: "fit-content",
|
|
80
|
-
wrap: true,
|
|
81
|
-
children: mode === 'range' ? /*#__PURE__*/_jsxs(_Fragment, {
|
|
82
|
-
children: [/*#__PURE__*/_jsx(DatePickerInput, {
|
|
83
|
-
label: props.startLabel,
|
|
84
|
-
placeholder: placeholder,
|
|
85
|
-
rangePart: "start",
|
|
86
|
-
ref: inputRef
|
|
87
|
-
}), /*#__PURE__*/_jsx(DatePickerInput, {
|
|
88
|
-
label: props.endLabel,
|
|
89
|
-
placeholder: placeholder,
|
|
90
|
-
rangePart: "end"
|
|
91
|
-
// does this need a ref?
|
|
92
|
-
})]
|
|
93
|
-
}) : /*#__PURE__*/_jsx(DatePickerInput, {
|
|
94
|
-
label: props.label,
|
|
95
|
-
placeholder: placeholder,
|
|
96
|
-
ref: inputRef
|
|
97
|
-
})
|
|
98
|
-
}), /*#__PURE__*/_jsx(PopoverContainer, {
|
|
99
|
-
alignment: "bottom-left",
|
|
100
|
-
allowPageInteraction: true
|
|
101
|
-
// look into if we can kill this and mess with where we are focusing instead
|
|
102
|
-
,
|
|
103
|
-
focusOnProps: {
|
|
104
|
-
autoFocus: false,
|
|
105
|
-
focusLock: false
|
|
106
|
-
},
|
|
107
|
-
invertAxis: "x",
|
|
108
|
-
isOpen: isCalendarOpen,
|
|
109
|
-
offset: 10,
|
|
110
|
-
targetRef: inputRef,
|
|
111
|
-
onRequestClose: closeCalendar // without this we cant type in the input but there has to be a better way
|
|
112
|
-
,
|
|
113
|
-
children: /*#__PURE__*/_jsx("div", {
|
|
114
|
-
"aria-label": "Choose date",
|
|
115
|
-
id: calendarDialogId,
|
|
116
|
-
role: "dialog",
|
|
117
|
-
children: /*#__PURE__*/_jsx(DatePickerCalendar, {
|
|
118
|
-
dialogId: calendarDialogId
|
|
119
|
-
})
|
|
120
|
-
})
|
|
121
|
-
})]
|
|
122
|
-
});
|
|
123
|
-
return /*#__PURE__*/_jsx(DatePickerProvider, {
|
|
124
|
-
value: contextValue,
|
|
125
|
-
children: content
|
|
126
|
-
});
|
|
127
|
-
};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/// <reference types="react" />
|
|
2
|
-
export type DatePickerCalendarProps = {
|
|
3
|
-
/** id for the dialog (for aria-controls from input). */
|
|
4
|
-
dialogId: string;
|
|
5
|
-
/** Whether to start the calendar on Sunday (0) or Monday (1). Default is Sunday. */
|
|
6
|
-
weekStartsOn?: 0 | 1;
|
|
7
|
-
};
|
|
8
|
-
/**
|
|
9
|
-
* Calendar that composes Calendar, CalendarHeader, CalendarBody, CalendarFooter.
|
|
10
|
-
* When inside DatePicker: owns local visibleDate and focusedDate; updates shared
|
|
11
|
-
* state via context. Supports single-date and range modes.
|
|
12
|
-
*/
|
|
13
|
-
export declare const DatePickerCalendar: React.FC<DatePickerCalendarProps>;
|