@wordpress/components
Version:
UI components for WordPress.
209 lines (208 loc) • 7.53 kB
JavaScript
// packages/components/src/date-time/date/index.tsx
import { isSameDay, subMonths, addMonths, isEqual, addDays, subDays, subWeeks, addWeeks, isSameMonth } from "date-fns";
import { __, _n, sprintf, isRTL } from "@wordpress/i18n";
import { arrowLeft, arrowRight } from "@wordpress/icons";
import { dateI18n, date as formatDate, getSettings } from "@wordpress/date";
import { useState, useRef, useEffect } from "@wordpress/element";
import { useLilius } from "./use-lilius/index.mjs";
import { Wrapper, Navigator, ViewPreviousMonthButton, ViewNextMonthButton, NavigatorHeading, Calendar, DayOfWeek, DayButton } from "./styles.mjs";
import { inputToDate, setInConfiguredTimezone, startOfDayInConfiguredTimezone } from "../utils.mjs";
import { TIMEZONELESS_FORMAT } from "../constants.mjs";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
function DatePicker({
currentDate,
onChange,
events = [],
isInvalidDate,
onMonthPreviewed,
startOfWeek: weekStartsOn = 0
}) {
const date = inputToDate(currentDate ?? /* @__PURE__ */ new Date());
const {
calendar,
viewing,
setSelected,
setViewing,
isSelected,
viewPreviousMonth,
viewNextMonth
} = useLilius({
selected: [startOfDayInConfiguredTimezone(date)],
viewing: startOfDayInConfiguredTimezone(date),
weekStartsOn
});
const [focusable, setFocusable] = useState(startOfDayInConfiguredTimezone(date));
const [isFocusWithinCalendar, setIsFocusWithinCalendar] = useState(false);
const [prevCurrentDate, setPrevCurrentDate] = useState(currentDate);
if (currentDate !== prevCurrentDate) {
setPrevCurrentDate(currentDate);
setSelected([startOfDayInConfiguredTimezone(date)]);
setViewing(startOfDayInConfiguredTimezone(date));
setFocusable(startOfDayInConfiguredTimezone(date));
}
return /* @__PURE__ */ _jsxs(Wrapper, {
className: "components-datetime__date",
role: "application",
"aria-label": __("Calendar"),
children: [/* @__PURE__ */ _jsxs(Navigator, {
children: [/* @__PURE__ */ _jsx(ViewPreviousMonthButton, {
icon: isRTL() ? arrowRight : arrowLeft,
variant: "tertiary",
"aria-label": __("View previous month"),
onClick: () => {
viewPreviousMonth();
setFocusable(subMonths(focusable, 1));
const prevMonth = subMonths(viewing, 1);
onMonthPreviewed?.(dateI18n(TIMEZONELESS_FORMAT, prevMonth, -prevMonth.getTimezoneOffset()));
},
size: "compact"
}), /* @__PURE__ */ _jsxs(NavigatorHeading, {
level: 3,
children: [/* @__PURE__ */ _jsx("strong", {
children: dateI18n("F", viewing, -viewing.getTimezoneOffset())
}), " ", dateI18n("Y", viewing, -viewing.getTimezoneOffset())]
}), /* @__PURE__ */ _jsx(ViewNextMonthButton, {
icon: isRTL() ? arrowLeft : arrowRight,
variant: "tertiary",
"aria-label": __("View next month"),
onClick: () => {
viewNextMonth();
setFocusable(addMonths(focusable, 1));
const nextMonth = addMonths(viewing, 1);
onMonthPreviewed?.(dateI18n(TIMEZONELESS_FORMAT, nextMonth, -nextMonth.getTimezoneOffset()));
},
size: "compact"
})]
}), /* @__PURE__ */ _jsxs(Calendar, {
onFocus: () => setIsFocusWithinCalendar(true),
onBlur: () => setIsFocusWithinCalendar(false),
children: [calendar[0][0].map((day) => /* @__PURE__ */ _jsx(DayOfWeek, {
children: dateI18n("D", day, -day.getTimezoneOffset())
}, day.toString())), calendar[0].map((week) => week.map((day, index) => {
if (!isSameMonth(day, viewing)) {
return null;
}
return /* @__PURE__ */ _jsx(Day, {
day,
column: index + 1,
isSelected: isSelected(day),
isFocusable: isEqual(day, focusable),
isFocusAllowed: isFocusWithinCalendar,
isToday: isSameDay(day, startOfDayInConfiguredTimezone(/* @__PURE__ */ new Date())),
isInvalid: isInvalidDate ? isInvalidDate(day) : false,
numEvents: events.filter((event) => isSameDay(event.date, day)).length,
onClick: () => {
setSelected([day]);
setFocusable(day);
const newDate = setInConfiguredTimezone(date, {
year: day.getFullYear(),
month: day.getMonth(),
date: day.getDate()
});
onChange?.(formatDate(TIMEZONELESS_FORMAT, newDate));
},
onKeyDown: (event) => {
let nextFocusable;
if (event.key === "ArrowLeft") {
nextFocusable = addDays(day, isRTL() ? 1 : -1);
}
if (event.key === "ArrowRight") {
nextFocusable = addDays(day, isRTL() ? -1 : 1);
}
if (event.key === "ArrowUp") {
nextFocusable = subWeeks(day, 1);
}
if (event.key === "ArrowDown") {
nextFocusable = addWeeks(day, 1);
}
if (event.key === "PageUp") {
nextFocusable = subMonths(day, 1);
}
if (event.key === "PageDown") {
nextFocusable = addMonths(day, 1);
}
if (event.key === "Home") {
const dayOfWeek = day.getDay();
const daysToSubtract = (dayOfWeek - weekStartsOn + 7) % 7;
nextFocusable = subDays(day, daysToSubtract);
}
if (event.key === "End") {
const dayOfWeek = day.getDay();
const daysToAdd = (weekStartsOn + 6 - dayOfWeek) % 7;
nextFocusable = addDays(day, daysToAdd);
}
if (nextFocusable) {
event.preventDefault();
setFocusable(nextFocusable);
if (!isSameMonth(nextFocusable, viewing)) {
setViewing(nextFocusable);
onMonthPreviewed?.(dateI18n(TIMEZONELESS_FORMAT, nextFocusable, -nextFocusable.getTimezoneOffset()));
}
}
}
}, day.toString());
}))]
})]
});
}
function Day({
day,
column,
isSelected,
isFocusable,
isFocusAllowed,
isToday,
isInvalid,
numEvents,
onClick,
onKeyDown
}) {
const ref = useRef(null);
useEffect(() => {
if (ref.current && isFocusable && isFocusAllowed) {
ref.current.focus();
}
}, [isFocusable]);
return /* @__PURE__ */ _jsx(DayButton, {
__next40pxDefaultSize: true,
ref,
className: "components-datetime__date__day",
disabled: isInvalid,
tabIndex: isFocusable ? 0 : -1,
"aria-label": getDayLabel(day, isSelected, isToday, numEvents),
column,
isSelected,
isToday,
hasEvents: numEvents > 0,
onClick,
onKeyDown,
children: dateI18n("j", day, -day.getTimezoneOffset())
});
}
function getDayLabel(date, isSelected, isToday, numEvents) {
const {
formats
} = getSettings();
const localizedDate = dateI18n(formats.date, date, -date.getTimezoneOffset());
const parts = [localizedDate];
if (isSelected) {
parts.push(__("Selected"));
}
if (isToday) {
parts.push(__("Today"));
}
if (numEvents > 0) {
parts.push(sprintf(
// translators: %d: Number of events on the calendar date.
_n("There is %d event", "There are %d events", numEvents),
numEvents
));
}
return parts.join(". ");
}
var date_default = DatePicker;
export {
DatePicker,
date_default as default
};
//# sourceMappingURL=index.mjs.map