react-datepicker-lite
Version:
A lightweight, accessible, and customizable React date picker component with TypeScript support
981 lines (980 loc) • 30.7 kB
JavaScript
import { jsxs, jsx } from "react/jsx-runtime";
import React, { forwardRef, useState, useCallback, useMemo, useRef, useEffect } from "react";
class NativeDateAdapter {
format(date, format) {
if (!this.isValid(date)) {
return "";
}
try {
const monthNames = [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
];
const monthNamesShort = [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
];
const dayNames = [
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday"
];
const dayNamesShort = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
let result = format;
const formatMap = {
EEEE: dayNames[date.getDay()] || "",
EEE: dayNamesShort[date.getDay()] || "",
MMMM: monthNames[date.getMonth()] || "",
MMM: monthNamesShort[date.getMonth()] || "",
yyyy: date.getFullYear().toString(),
YYYY: date.getFullYear().toString(),
MM: (date.getMonth() + 1).toString().padStart(2, "0"),
dd: date.getDate().toString().padStart(2, "0"),
DD: date.getDate().toString().padStart(2, "0"),
HH: date.getHours().toString().padStart(2, "0"),
mm: date.getMinutes().toString().padStart(2, "0"),
ss: date.getSeconds().toString().padStart(2, "0"),
YY: date.getFullYear().toString().slice(-2),
M: (date.getMonth() + 1).toString(),
D: date.getDate().toString(),
H: date.getHours().toString(),
m: date.getMinutes().toString(),
s: date.getSeconds().toString()
};
const patterns = [
"EEEE",
"EEE",
"MMMM",
"MMM",
"yyyy",
"YYYY",
"MM",
"dd",
"DD",
"HH",
"mm",
"ss",
"YY",
"M",
"D",
"H",
"m",
"s"
];
for (const pattern of patterns) {
const value = formatMap[pattern];
if (value !== void 0) {
if (pattern.length === 1) {
result = result.replace(new RegExp(`\\b${pattern}\\b`, "g"), value);
} else {
result = result.replace(new RegExp(pattern, "g"), value);
}
}
}
return result;
} catch {
return "";
}
}
parse(dateString, format) {
if (!dateString) {
return null;
}
try {
if (format === "MM/dd/yyyy") {
const match = dateString.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/);
if (match && match[1] && match[2] && match[3]) {
const month = parseInt(match[1]);
const day = parseInt(match[2]);
const year = parseInt(match[3]);
if (month < 1 || month > 12 || day < 1 || day > 31 || year < 1) {
return null;
}
const date = new Date(year, month - 1, day);
if (date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day) {
return date;
}
return null;
}
} else if (format === "dd/MM/yyyy") {
const match = dateString.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/);
if (match && match[1] && match[2] && match[3]) {
const day = parseInt(match[1]);
const month = parseInt(match[2]);
const year = parseInt(match[3]);
const date = new Date(year, month - 1, day);
if (date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day) {
return date;
}
}
} else if (format === "yyyy-MM-dd") {
const match = dateString.match(/^(\d{4})-(\d{1,2})-(\d{1,2})$/);
if (match && match[1] && match[2] && match[3]) {
const year = parseInt(match[1]);
const month = parseInt(match[2]);
const day = parseInt(match[3]);
const date = new Date(year, month - 1, day);
if (date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day) {
return date;
}
}
} else if (format === "MMM dd, yyyy") {
const monthNames = [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
];
const match = dateString.match(
/^([A-Za-z]{3})\s+(\d{1,2}),\s+(\d{4})$/
);
if (match && match[1] && match[2] && match[3]) {
const monthStr = match[1];
const day = parseInt(match[2]);
const year = parseInt(match[3]);
const monthIndex = monthNames.indexOf(monthStr);
if (monthIndex !== -1) {
const date = new Date(year, monthIndex, day);
if (date.getFullYear() === year && date.getMonth() === monthIndex && date.getDate() === day) {
return date;
}
}
}
}
const parsed = new Date(dateString);
return this.isValid(parsed) ? parsed : null;
} catch {
return null;
}
}
isValid(date) {
return date instanceof Date && !isNaN(date.getTime());
}
addDays(date, days) {
const result = new Date(date);
result.setDate(result.getDate() + days);
return result;
}
addMonths(date, months) {
const result = new Date(date);
const _originalDay = result.getDate();
result.setMonth(result.getMonth() + months);
if (result.getDate() !== _originalDay) {
result.setDate(0);
}
return result;
}
addYears(date, years) {
const result = new Date(date);
const originalMonth = result.getMonth();
result.setFullYear(result.getFullYear() + years);
if (result.getMonth() !== originalMonth) {
result.setDate(0);
}
return result;
}
startOfDay(date) {
const result = new Date(date);
result.setHours(0, 0, 0, 0);
return result;
}
startOfMonth(date) {
const result = new Date(date);
result.setDate(1);
result.setHours(0, 0, 0, 0);
return result;
}
startOfYear(date) {
const result = new Date(date);
result.setMonth(0, 1);
result.setHours(0, 0, 0, 0);
return result;
}
endOfDay(date) {
const result = new Date(date);
result.setHours(23, 59, 59, 999);
return result;
}
endOfMonth(date) {
const result = new Date(date);
result.setMonth(result.getMonth() + 1, 0);
result.setHours(23, 59, 59, 999);
return result;
}
endOfYear(date) {
const result = new Date(date);
result.setMonth(11, 31);
result.setHours(23, 59, 59, 999);
return result;
}
isSameDay(date1, date2) {
if (!this.isValid(date1) || !this.isValid(date2)) {
return false;
}
return date1.getFullYear() === date2.getFullYear() && date1.getMonth() === date2.getMonth() && date1.getDate() === date2.getDate();
}
isSameMonth(date1, date2) {
if (!this.isValid(date1) || !this.isValid(date2)) {
return false;
}
return date1.getFullYear() === date2.getFullYear() && date1.getMonth() === date2.getMonth();
}
isSameYear(date1, date2) {
if (!this.isValid(date1) || !this.isValid(date2)) {
return false;
}
return date1.getFullYear() === date2.getFullYear();
}
isAfter(date1, date2) {
if (!this.isValid(date1) || !this.isValid(date2)) {
return false;
}
return date1.getTime() > date2.getTime();
}
isBefore(date1, date2) {
if (!this.isValid(date1) || !this.isValid(date2)) {
return false;
}
return date1.getTime() < date2.getTime();
}
getDay(date) {
return date.getDay();
}
getMonth(date) {
return date.getMonth();
}
getYear(date) {
return date.getFullYear();
}
getDaysInMonth(date) {
return new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();
}
today() {
return /* @__PURE__ */ new Date();
}
}
const nativeDateAdapter = new NativeDateAdapter();
const enUS = {
code: "en-US",
name: "English (US)",
months: [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
],
monthsShort: [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
],
weekdays: [
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday"
],
weekdaysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
weekdaysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
firstDayOfWeek: 0,
// Sunday
rtl: false,
dateFormat: "MM/DD/YYYY",
timeFormat: "HH:mm",
dateTimeFormat: "MM/DD/YYYY HH:mm"
};
const defaultLocale = enUS;
function getLocale(_code) {
return defaultLocale;
}
const DateInput = forwardRef(
({
value,
defaultValue,
onChange,
dateAdapter = nativeDateAdapter,
format,
placeholder = "Select date",
disabled = false,
readOnly = false,
autoFocus = false,
className = "",
locale = defaultLocale,
minDate: _minDate,
maxDate: _maxDate,
disabledDates: _disabledDates,
onFocus,
onBlur,
onKeyDown,
onCalendarToggle,
isCalendarOpen = false,
"aria-label": ariaLabel,
"aria-describedby": ariaDescribedBy,
id,
...rest
}, ref) => {
const [inputValue, setInputValue] = useState(() => {
if (value && dateAdapter.isValid(value)) {
return dateAdapter.format(value, format || locale.dateFormat);
}
if (defaultValue && dateAdapter.isValid(defaultValue)) {
return dateAdapter.format(defaultValue, format || locale.dateFormat);
}
return "";
});
const [isFocused, setIsFocused] = useState(false);
const handleInputChange = useCallback(
(event) => {
const newValue = event.target.value;
setInputValue(newValue);
if (newValue === "") {
onChange == null ? void 0 : onChange(null);
return;
}
const parsedDate = dateAdapter.parse(
newValue,
format || locale.dateFormat
);
if (parsedDate && dateAdapter.isValid(parsedDate)) {
onChange == null ? void 0 : onChange(parsedDate);
}
},
[dateAdapter, format, locale.dateFormat, onChange]
);
const handleFocus = useCallback(
(event) => {
setIsFocused(true);
onFocus == null ? void 0 : onFocus(event);
onCalendarToggle == null ? void 0 : onCalendarToggle(true);
},
[onFocus, onCalendarToggle]
);
const handleBlur = useCallback(
(event) => {
setIsFocused(false);
onBlur == null ? void 0 : onBlur(event);
if (inputValue && value && dateAdapter.isValid(value)) {
const formattedValue = dateAdapter.format(
value,
format || locale.dateFormat
);
setInputValue(formattedValue);
}
},
[onBlur, inputValue, value, dateAdapter, format, locale.dateFormat]
);
const handleKeyDown = useCallback(
(event) => {
onKeyDown == null ? void 0 : onKeyDown(event);
if (event.key === "Escape") {
onCalendarToggle == null ? void 0 : onCalendarToggle(false);
} else if (event.key === "Enter" || event.key === "ArrowDown") {
event.preventDefault();
onCalendarToggle == null ? void 0 : onCalendarToggle(true);
}
},
[onKeyDown, onCalendarToggle]
);
React.useEffect(() => {
if (value && dateAdapter.isValid(value)) {
const formattedValue = dateAdapter.format(
value,
format || locale.dateFormat
);
setInputValue(formattedValue);
} else if (value === null || value === void 0) {
setInputValue("");
}
}, [value, dateAdapter, format, locale.dateFormat]);
const inputClassName = [
"rdl-date-input",
isFocused && "rdl-date-input--focused",
disabled && "rdl-date-input--disabled",
readOnly && "rdl-date-input--readonly",
isCalendarOpen && "rdl-date-input--calendar-open",
className
].filter(Boolean).join(" ");
return /* @__PURE__ */ jsxs("div", { className: "rdl-date-input-wrapper", children: [
/* @__PURE__ */ jsx(
"input",
{
ref,
type: "text",
value: inputValue,
onChange: handleInputChange,
onFocus: handleFocus,
onBlur: handleBlur,
onKeyDown: handleKeyDown,
placeholder,
disabled,
readOnly,
autoFocus,
className: inputClassName,
"aria-label": ariaLabel || "Date input",
"aria-describedby": ariaDescribedBy,
"aria-expanded": isCalendarOpen,
"aria-haspopup": "dialog",
"aria-controls": isCalendarOpen ? `${id || "datepicker"}-calendar` : void 0,
role: "combobox",
id,
...rest
}
),
/* @__PURE__ */ jsx(
"button",
{
type: "button",
className: "rdl-date-input-toggle",
onClick: () => onCalendarToggle == null ? void 0 : onCalendarToggle(!isCalendarOpen),
disabled,
"aria-label": "Open calendar",
tabIndex: -1,
children: /* @__PURE__ */ jsx(
"svg",
{
width: "16",
height: "16",
viewBox: "0 0 16 16",
fill: "currentColor",
"aria-hidden": "true",
children: /* @__PURE__ */ jsx("path", { d: "M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5zM2 2a1 1 0 0 0-1 1v1h14V3a1 1 0 0 0-1-1H2zM1 5v9a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V5H1z" })
}
)
}
)
] });
}
);
DateInput.displayName = "DateInput";
const Calendar = ({
currentDate,
onCurrentDateChange,
selectedDate,
selectedRange,
onDateSelect,
dateAdapter = nativeDateAdapter,
minDate,
maxDate,
disabledDates,
locale = defaultLocale,
showWeekNumbers = false,
className = "",
isRangeSelection = false,
rangeHoverDate,
onRangeHover
}) => {
const calendarDays = useMemo(() => {
const startOfMonth = dateAdapter.startOfMonth(currentDate);
const startOfCalendar = dateAdapter.addDays(
startOfMonth,
-((dateAdapter.getDay(startOfMonth) - locale.firstDayOfWeek + 7) % 7)
);
const endOfCalendar = dateAdapter.addDays(startOfCalendar, 41);
const days = [];
let current = startOfCalendar;
while (dateAdapter.isBefore(current, endOfCalendar)) {
const isToday = dateAdapter.isSameDay(current, dateAdapter.today());
const isSelected = selectedDate ? dateAdapter.isSameDay(current, selectedDate) : false;
const isOutsideMonth = !dateAdapter.isSameMonth(current, currentDate);
const isWeekend = dateAdapter.getDay(current) === 0 || dateAdapter.getDay(current) === 6;
let isDisabled = false;
if (minDate && dateAdapter.isBefore(current, dateAdapter.startOfDay(minDate))) {
isDisabled = true;
}
if (maxDate && dateAdapter.isAfter(current, dateAdapter.startOfDay(maxDate))) {
isDisabled = true;
}
if (disabledDates && !isDisabled) {
if (Array.isArray(disabledDates)) {
isDisabled = disabledDates.some(
(disabledDate) => dateAdapter.isSameDay(current, disabledDate)
);
} else {
isDisabled = disabledDates(current);
}
}
let isInRange = false;
let isRangeStart = false;
let isRangeEnd = false;
if (isRangeSelection && selectedRange) {
const { start, end } = selectedRange;
if (start && end) {
isInRange = (dateAdapter.isAfter(current, start) || dateAdapter.isSameDay(current, start)) && (dateAdapter.isBefore(current, end) || dateAdapter.isSameDay(current, end));
isRangeStart = dateAdapter.isSameDay(current, start);
isRangeEnd = dateAdapter.isSameDay(current, end);
} else if (start && rangeHoverDate) {
const rangeStart = dateAdapter.isBefore(start, rangeHoverDate) ? start : rangeHoverDate;
const rangeEnd = dateAdapter.isAfter(start, rangeHoverDate) ? start : rangeHoverDate;
isInRange = (dateAdapter.isAfter(current, rangeStart) || dateAdapter.isSameDay(current, rangeStart)) && (dateAdapter.isBefore(current, rangeEnd) || dateAdapter.isSameDay(current, rangeEnd));
}
}
days.push({
date: current,
isToday,
isSelected,
isInRange,
isRangeStart,
isRangeEnd,
isDisabled,
isOutsideMonth,
isWeekend
});
current = dateAdapter.addDays(current, 1);
}
return days;
}, [
currentDate,
selectedDate,
selectedRange,
dateAdapter,
locale.firstDayOfWeek,
minDate,
maxDate,
disabledDates,
isRangeSelection,
rangeHoverDate
]);
const handlePreviousMonth = useCallback(() => {
onCurrentDateChange(dateAdapter.addMonths(currentDate, -1));
}, [currentDate, dateAdapter, onCurrentDateChange]);
const handleNextMonth = useCallback(() => {
onCurrentDateChange(dateAdapter.addMonths(currentDate, 1));
}, [currentDate, dateAdapter, onCurrentDateChange]);
const handleDateClick = useCallback(
(day) => {
if (day.isDisabled) return;
onDateSelect(day.date);
},
[onDateSelect]
);
const handleDateHover = useCallback(
(day) => {
if (isRangeSelection && onRangeHover && !day.isDisabled) {
onRangeHover(day.date);
}
},
[isRangeSelection, onRangeHover]
);
const handleDateMouseLeave = useCallback(() => {
if (isRangeSelection && onRangeHover) {
onRangeHover(null);
}
}, [isRangeSelection, onRangeHover]);
const handleHeaderClick = useCallback(
(event) => {
if (event.shiftKey) {
onCurrentDateChange(dateAdapter.addYears(currentDate, -1));
} else {
onCurrentDateChange(dateAdapter.addYears(currentDate, 1));
}
},
[currentDate, dateAdapter, onCurrentDateChange]
);
const handleKeyDown = useCallback(
(event, day) => {
if (day.isDisabled) return;
const currentIndex = calendarDays.findIndex(
(d) => dateAdapter.isSameDay(d.date, day.date)
);
let newIndex = currentIndex;
switch (event.key) {
case "Enter":
case " ":
event.preventDefault();
onDateSelect(day.date);
break;
case "ArrowRight":
event.preventDefault();
newIndex = Math.min(currentIndex + 1, calendarDays.length - 1);
break;
case "ArrowLeft":
event.preventDefault();
newIndex = Math.max(currentIndex - 1, 0);
break;
case "ArrowDown":
event.preventDefault();
newIndex = Math.min(currentIndex + 7, calendarDays.length - 1);
break;
case "ArrowUp":
event.preventDefault();
newIndex = Math.max(currentIndex - 7, 0);
break;
case "Home":
event.preventDefault();
newIndex = currentIndex - currentIndex % 7;
break;
case "End":
event.preventDefault();
newIndex = currentIndex + (6 - currentIndex % 7);
break;
case "PageUp":
event.preventDefault();
onCurrentDateChange(dateAdapter.addMonths(currentDate, -1));
break;
case "PageDown":
event.preventDefault();
onCurrentDateChange(dateAdapter.addMonths(currentDate, 1));
break;
default:
return;
}
if (newIndex !== currentIndex && newIndex >= 0 && newIndex < calendarDays.length) {
const newDay = calendarDays[newIndex];
if (newDay && !newDay.isDisabled) {
const buttons = document.querySelectorAll(".rdl-calendar-day");
const targetButton = buttons[newIndex];
if (targetButton) {
targetButton.focus();
}
}
}
},
[calendarDays, dateAdapter, onDateSelect, onCurrentDateChange, currentDate]
);
const weekdays = useMemo(() => {
const days = [];
for (let i = 0; i < 7; i++) {
const dayIndex = (locale.firstDayOfWeek + i) % 7;
days.push(locale.weekdaysMin[dayIndex]);
}
return days;
}, [locale]);
const calendarClassName = [
"rdl-calendar",
showWeekNumbers && "rdl-calendar--with-week-numbers",
isRangeSelection && "rdl-calendar--range-selection",
className
].filter(Boolean).join(" ");
return /* @__PURE__ */ jsxs("div", { className: calendarClassName, children: [
/* @__PURE__ */ jsxs("div", { className: "rdl-calendar-header", children: [
/* @__PURE__ */ jsx(
"button",
{
type: "button",
className: "rdl-calendar-nav rdl-calendar-nav--prev",
onClick: handlePreviousMonth,
"aria-label": "Previous month",
children: /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { d: "M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z" }) })
}
),
/* @__PURE__ */ jsxs(
"button",
{
type: "button",
className: "rdl-calendar-title",
onClick: handleHeaderClick,
"aria-label": `${locale.months[dateAdapter.getMonth(currentDate)]} ${dateAdapter.getYear(currentDate)}, click to navigate years`,
children: [
/* @__PURE__ */ jsx("span", { className: "rdl-calendar-month", children: locale.months[dateAdapter.getMonth(currentDate)] }),
/* @__PURE__ */ jsx("span", { className: "rdl-calendar-year", children: dateAdapter.getYear(currentDate) })
]
}
),
/* @__PURE__ */ jsx(
"button",
{
type: "button",
className: "rdl-calendar-nav rdl-calendar-nav--next",
onClick: handleNextMonth,
"aria-label": "Next month",
children: /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { d: "M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z" }) })
}
)
] }),
/* @__PURE__ */ jsxs(
"div",
{
className: "rdl-calendar-grid",
role: "grid",
"aria-label": `Calendar for ${locale.months[dateAdapter.getMonth(currentDate)]} ${dateAdapter.getYear(currentDate)}`,
children: [
/* @__PURE__ */ jsxs("div", { className: "rdl-calendar-weekdays", role: "row", children: [
showWeekNumbers && /* @__PURE__ */ jsx(
"div",
{
className: "rdl-calendar-weekday rdl-calendar-week-number-header",
role: "columnheader",
children: "Wk"
}
),
weekdays.map((weekday, index) => /* @__PURE__ */ jsx(
"div",
{
className: "rdl-calendar-weekday",
role: "columnheader",
children: weekday
},
index
))
] }),
/* @__PURE__ */ jsx("div", { className: "rdl-calendar-days", children: Array.from({ length: 6 }, (_, weekIndex) => /* @__PURE__ */ jsxs("div", { className: "rdl-calendar-week", role: "row", children: [
showWeekNumbers && /* @__PURE__ */ jsx("div", { className: "rdl-calendar-week-number", role: "rowheader", children: weekIndex + 1 }),
calendarDays.slice(weekIndex * 7, (weekIndex + 1) * 7).map((day, dayIndex) => {
const dayClassName = [
"rdl-calendar-day",
day.isToday && "rdl-calendar-day--today",
day.isSelected && "rdl-calendar-day--selected",
day.isInRange && "rdl-calendar-day--in-range",
day.isRangeStart && "rdl-calendar-day--range-start",
day.isRangeEnd && "rdl-calendar-day--range-end",
day.isDisabled && "rdl-calendar-day--disabled",
day.isOutsideMonth && "rdl-calendar-day--outside-month",
day.isWeekend && "rdl-calendar-day--weekend"
].filter(Boolean).join(" ");
return /* @__PURE__ */ jsx("div", { role: "gridcell", children: /* @__PURE__ */ jsx(
"button",
{
type: "button",
className: dayClassName,
onClick: () => handleDateClick(day),
onMouseEnter: () => handleDateHover(day),
onMouseLeave: handleDateMouseLeave,
onKeyDown: (e) => handleKeyDown(e, day),
disabled: day.isDisabled,
"aria-label": dateAdapter.format(
day.date,
locale.dateFormat
),
"aria-pressed": day.isSelected,
"aria-disabled": day.isDisabled,
tabIndex: day.isSelected ? 0 : -1,
children: dateAdapter.format(day.date, "D")
}
) }, dayIndex);
})
] }, weekIndex)) })
]
}
)
] });
};
const DatePicker = ({
value,
defaultValue,
onChange,
dateAdapter = nativeDateAdapter,
format,
placeholder,
disabled = false,
readOnly = false,
autoFocus = false,
className = "",
locale = defaultLocale,
minDate,
maxDate,
disabledDates,
showWeekNumbers = false,
showToday = true,
closeOnSelect = true,
onFocus,
onBlur,
onKeyDown,
"aria-label": ariaLabel,
"aria-describedby": ariaDescribedBy,
id
}) => {
const [isOpen, setIsOpen] = useState(false);
const [currentDate, setCurrentDate] = useState(() => {
if (value && dateAdapter.isValid(value)) {
return value;
}
if (defaultValue && dateAdapter.isValid(defaultValue)) {
return defaultValue;
}
return dateAdapter.today();
});
const containerRef = useRef(null);
const inputRef = useRef(null);
const [internalValue, setInternalValue] = useState(
() => defaultValue || null
);
const currentValue = value !== void 0 ? value : internalValue;
const isControlled = value !== void 0;
const handleDateChange = useCallback(
(newDate) => {
if (value === void 0) {
setInternalValue(newDate);
}
onChange == null ? void 0 : onChange(newDate);
},
[value, onChange]
);
const handleCalendarToggle = useCallback(
(open) => {
if (disabled || readOnly) return;
setIsOpen(open);
},
[disabled, readOnly]
);
const handleDateSelect = useCallback(
(selectedDate) => {
handleDateChange(selectedDate);
setCurrentDate(selectedDate);
if (closeOnSelect) {
setIsOpen(false);
requestAnimationFrame(() => {
var _a;
(_a = inputRef.current) == null ? void 0 : _a.focus();
});
}
},
[handleDateChange, closeOnSelect]
);
const handleCurrentDateChange = useCallback((newCurrentDate) => {
setCurrentDate(newCurrentDate);
}, []);
useEffect(() => {
const handleClickOutside = (event) => {
if (containerRef.current && !containerRef.current.contains(event.target)) {
setIsOpen(false);
}
};
if (isOpen) {
document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}
return void 0;
}, [isOpen]);
const handleKeyDown = useCallback(
(event) => {
onKeyDown == null ? void 0 : onKeyDown(event);
if (event.key === "Escape" && isOpen) {
setIsOpen(false);
event.preventDefault();
}
},
[onKeyDown, isOpen]
);
useEffect(() => {
if (currentValue && dateAdapter.isValid(currentValue)) {
setCurrentDate(currentValue);
}
}, [currentValue, dateAdapter]);
const pickerClassName = [
"rdl-date-picker",
isOpen && "rdl-date-picker--open",
disabled && "rdl-date-picker--disabled",
className
].filter(Boolean).join(" ");
const dateInputProps = {
ref: inputRef,
onChange: handleDateChange,
dateAdapter,
disabled,
readOnly,
autoFocus,
locale,
onCalendarToggle: handleCalendarToggle,
isCalendarOpen: isOpen,
onKeyDown: handleKeyDown,
...placeholder && { placeholder },
...format && { format },
...minDate !== void 0 && { minDate },
...maxDate !== void 0 && { maxDate },
...disabledDates && { disabledDates },
...onFocus && { onFocus },
...onBlur && { onBlur },
...ariaLabel && { "aria-label": ariaLabel },
...ariaDescribedBy && { "aria-describedby": ariaDescribedBy },
...id && { id }
};
if (isControlled) {
dateInputProps.value = value;
} else {
dateInputProps.value = internalValue;
}
const calendarProps = {
currentDate,
onCurrentDateChange: handleCurrentDateChange,
selectedDate: currentValue,
onDateSelect: handleDateSelect,
dateAdapter,
locale,
showWeekNumbers,
...minDate !== void 0 && { minDate },
...maxDate !== void 0 && { maxDate },
...disabledDates && { disabledDates }
};
return /* @__PURE__ */ jsxs("div", { ref: containerRef, className: pickerClassName, children: [
/* @__PURE__ */ jsx(DateInput, { ...dateInputProps }),
isOpen && /* @__PURE__ */ jsxs("div", { className: "rdl-date-picker-dropdown", children: [
/* @__PURE__ */ jsx(Calendar, { ...calendarProps }),
showToday && /* @__PURE__ */ jsx("div", { className: "rdl-date-picker-footer", children: /* @__PURE__ */ jsx(
"button",
{
type: "button",
className: "rdl-date-picker-today-button",
onClick: () => handleDateSelect(dateAdapter.today()),
children: "Today"
}
) })
] })
] });
};
const version = "1.0.2";
export {
Calendar,
DateInput,
DatePicker,
NativeDateAdapter,
defaultLocale,
enUS,
getLocale,
nativeDateAdapter,
version
};
//# sourceMappingURL=index.esm.js.map