flowbite-react
Version:
Official React components built for Flowbite and Tailwind CSS
250 lines (247 loc) • 8.92 kB
JavaScript
'use client';
import { jsx, jsxs } from 'react/jsx-runtime';
import { forwardRef, useState, useRef, useImperativeHandle, useEffect } from 'react';
import { HiCalendar, HiArrowLeft, HiArrowRight } from 'react-icons/hi';
import { twMerge } from 'tailwind-merge';
import { mergeDeep } from '../../helpers/merge-deep.mjs';
import { getTheme } from '../../theme-store/index.mjs';
import { TextInput } from '../TextInput/TextInput.mjs';
import { DatepickerContext } from './DatepickerContext.mjs';
import { getFirstDateInRange, Views, isDateEqual, getFormattedDate, WeekStart, startOfYearPeriod, addYears, addMonths } from './helpers.mjs';
import { DatepickerViewsDays } from './Views/Days.mjs';
import { DatepickerViewsDecades } from './Views/Decades.mjs';
import { DatepickerViewsMonth } from './Views/Months.mjs';
import { DatepickerViewsYears } from './Views/Years.mjs';
const DatepickerRender = ({
title,
open,
inline = false,
autoHide = true,
// Hide when selected the day
showClearButton = true,
labelClearButton = "Clear",
showTodayButton = true,
labelTodayButton = "Today",
defaultDate = /* @__PURE__ */ new Date(),
minDate,
maxDate,
language = "en",
weekStart = WeekStart.Sunday,
className,
theme: customTheme = {},
onSelectedDateChanged,
...props
}, ref) => {
const theme = mergeDeep(getTheme().datepicker, customTheme);
defaultDate = getFirstDateInRange(defaultDate, minDate, maxDate);
const [isOpen, setIsOpen] = useState(open);
const [view, setView] = useState(Views.Days);
const [selectedDate, setSelectedDate] = useState(defaultDate);
const [viewDate, setViewDate] = useState(defaultDate);
const inputRef = useRef(null);
const datepickerRef = useRef(null);
const changeSelectedDate = (date, useAutohide) => {
setSelectedDate(date);
if (onSelectedDateChanged) {
onSelectedDateChanged(date);
}
if (autoHide && view === Views.Days && useAutohide == true && !inline) {
setIsOpen(false);
}
};
const clearDate = () => {
changeSelectedDate(defaultDate, true);
if (defaultDate) {
setViewDate(defaultDate);
}
};
useImperativeHandle(ref, () => ({
focus() {
inputRef.current?.focus();
},
clear() {
clearDate();
}
}));
const renderView = (type) => {
switch (type) {
case Views.Decades:
return /* @__PURE__ */ jsx(DatepickerViewsDecades, { theme: theme.views.decades });
case Views.Years:
return /* @__PURE__ */ jsx(DatepickerViewsYears, { theme: theme.views.years });
case Views.Months:
return /* @__PURE__ */ jsx(DatepickerViewsMonth, { theme: theme.views.months });
case Views.Days:
default:
return /* @__PURE__ */ jsx(DatepickerViewsDays, { theme: theme.views.days });
}
};
const getNextView = () => {
switch (view) {
case Views.Days:
return Views.Months;
case Views.Months:
return Views.Years;
case Views.Years:
return Views.Decades;
}
return view;
};
const getViewTitle = () => {
switch (view) {
case Views.Decades:
return `${startOfYearPeriod(viewDate, 100)} - ${startOfYearPeriod(viewDate, 100) + 90}`;
case Views.Years:
return `${startOfYearPeriod(viewDate, 10)} - ${startOfYearPeriod(viewDate, 10) + 9}`;
case Views.Months:
return getFormattedDate(language, viewDate, { year: "numeric" });
case Views.Days:
default:
return getFormattedDate(language, viewDate, { month: "long", year: "numeric" });
}
};
const getViewDatePage = (view2, date, value) => {
switch (view2) {
case Views.Days:
return new Date(addMonths(date, value));
case Views.Months:
return new Date(addYears(date, value));
case Views.Years:
return new Date(addYears(date, value * 10));
case Views.Decades:
return new Date(addYears(date, value * 100));
default:
return new Date(addYears(date, value * 10));
}
};
useEffect(() => {
const handleClickOutside = (event) => {
const clickedInsideDatepicker = datepickerRef?.current?.contains(event.target);
const clickedInsideInput = inputRef?.current?.contains(event.target);
if (!clickedInsideDatepicker && !clickedInsideInput) {
setIsOpen(false);
}
};
document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, [inputRef, datepickerRef, setIsOpen]);
return /* @__PURE__ */ jsx(
DatepickerContext.Provider,
{
value: {
theme,
language,
minDate,
maxDate,
weekStart,
isOpen,
setIsOpen,
view,
setView,
viewDate,
setViewDate,
selectedDate,
setSelectedDate,
changeSelectedDate
},
children: /* @__PURE__ */ jsxs("div", { className: twMerge(theme.root.base, className), children: [
!inline && /* @__PURE__ */ jsx(
TextInput,
{
theme: theme.root.input,
icon: HiCalendar,
ref: inputRef,
onFocus: () => {
if (!isDateEqual(viewDate, selectedDate)) {
setViewDate(selectedDate);
}
setIsOpen(true);
},
value: selectedDate && getFormattedDate(language, selectedDate),
readOnly: true,
...props
}
),
(isOpen || inline) && /* @__PURE__ */ jsx("div", { ref: datepickerRef, className: twMerge(theme.popup.root.base, inline && theme.popup.root.inline), children: /* @__PURE__ */ jsxs("div", { className: theme.popup.root.inner, children: [
/* @__PURE__ */ jsxs("div", { className: theme.popup.header.base, children: [
title && /* @__PURE__ */ jsx("div", { className: theme.popup.header.title, children: title }),
/* @__PURE__ */ jsxs("div", { className: theme.popup.header.selectors.base, children: [
/* @__PURE__ */ jsx(
"button",
{
type: "button",
className: twMerge(
theme.popup.header.selectors.button.base,
theme.popup.header.selectors.button.prev
),
onClick: () => setViewDate(getViewDatePage(view, viewDate, -1)),
children: /* @__PURE__ */ jsx(HiArrowLeft, {})
}
),
/* @__PURE__ */ jsx(
"button",
{
type: "button",
className: twMerge(
theme.popup.header.selectors.button.base,
theme.popup.header.selectors.button.view
),
onClick: () => setView(getNextView()),
children: getViewTitle()
}
),
/* @__PURE__ */ jsx(
"button",
{
type: "button",
className: twMerge(
theme.popup.header.selectors.button.base,
theme.popup.header.selectors.button.next
),
onClick: () => setViewDate(getViewDatePage(view, viewDate, 1)),
children: /* @__PURE__ */ jsx(HiArrowRight, {})
}
)
] })
] }),
/* @__PURE__ */ jsx("div", { className: theme.popup.view.base, children: renderView(view) }),
(showClearButton || showTodayButton) && /* @__PURE__ */ jsxs("div", { className: theme.popup.footer.base, children: [
showTodayButton && /* @__PURE__ */ jsx(
"button",
{
type: "button",
className: twMerge(theme.popup.footer.button.base, theme.popup.footer.button.today),
onClick: () => {
const today = /* @__PURE__ */ new Date();
changeSelectedDate(today, true);
setViewDate(today);
},
children: labelTodayButton
}
),
showClearButton && /* @__PURE__ */ jsx(
"button",
{
type: "button",
className: twMerge(theme.popup.footer.button.base, theme.popup.footer.button.clear),
onClick: () => {
changeSelectedDate(defaultDate, true);
if (defaultDate) {
setViewDate(defaultDate);
}
},
children: labelClearButton
}
)
] })
] }) })
] })
}
);
};
const Datepicker = forwardRef(DatepickerRender);
Datepicker.displayName = "Datepicker";
export { Datepicker };
//# sourceMappingURL=Datepicker.mjs.map