@activecollab/components
Version:
ActiveCollab Components
325 lines (324 loc) • 12.2 kB
JavaScript
import _extends from "@babel/runtime/helpers/esm/extends";
import React, { useState, useCallback, useMemo, useEffect } from "react";
import { SwitchTransition } from "react-transition-group";
import { addMonths, isAfter } from "date-fns";
import moment from "moment";
import { customClassNames, modifiersClassNames } from "./ClassNames";
import { CustomNavBarElement } from "./CustomNavBarElement";
import { StyledDatePicker, StyledDatePickerCSSTransition, StyledDayPicker } from "./Styles";
import { YearMonthPicker } from "../Pickers/YearMonthPicker";
const formatWeekdayName = str => moment(str).format("ddd").charAt(0);
export const DatePicker = _ref => {
let {
className,
onChange,
onDayClick,
selectedDays,
disabledDays,
selectionMode = "daily",
month = new Date(),
onMonthChange = () => null,
dateRequired = false,
firstDayOfWeek = 0,
fixedWeeks = true,
modifiers: defaultModifiers,
renderDay,
...rest
} = _ref;
const [enteredTo, setEnteredTo] = useState();
const [enteredFrom, setEnteredFrom] = useState();
const [stopScroll, setStopScroll] = useState();
const [direction, setDirection] = useState(true);
const [isPreselected, setIsPreselected] = useState(() => {
return (selectedDays == null ? void 0 : selectedDays.from) instanceof Date && (selectedDays == null ? void 0 : selectedDays.to) instanceof Date;
});
const [showMonthPicker, setShowMonthPicker] = useState(selectionMode === "quarterly" || selectionMode === "monthly");
const [modifiers, setModifiers] = useState(defaultModifiers);
const week = firstDayOfWeek === 0 ? "week" : "isoWeek";
useEffect(() => {
if (enteredFrom instanceof Date && enteredTo instanceof Date) {
setModifiers(prev => {
return {
...prev,
hovered: {
from: enteredFrom,
to: enteredTo
}
};
});
} else {
setModifiers(defaultModifiers);
}
}, [enteredTo, enteredFrom, defaultModifiers]);
const handleDayClick = useCallback((day, modifiers) => {
if (onDayClick) {
onDayClick(day, modifiers);
}
if (!onChange) {
return;
}
if (month.getMonth() !== day.getMonth()) {
onMonthChange(day);
}
if (modifiers["day_disabled"] || selectionMode === "none") {
return;
}
// reset the selectedDays if the user clicks on the same day
if (!dateRequired && (selectedDays != null && selectedDays.from && moment(day).isSame(moment(selectedDays.from), "day") || selectedDays != null && selectedDays.to && moment(day).isSame(moment(selectedDays.to), "day"))) {
setEnteredTo(undefined);
setEnteredFrom(undefined);
return onChange(undefined);
}
if (selectionMode === "daily") {
return onChange({
from: day,
to: day
});
}
if (selectionMode === "weekly") {
if (!dateRequired && selectedDays != null && selectedDays.from && moment(day).isSame(moment(selectedDays.from), week)) {
return onChange(undefined);
}
return onChange({
from: moment(day).startOf(week).toDate(),
to: moment(day).endOf(week).toDate()
});
}
if (selectionMode === "custom") {
if (isPreselected) {
setIsPreselected(false);
return onChange({
from: day,
to: day
});
}
if (!selectedDays || selectedDays != null && selectedDays.from && selectedDays != null && selectedDays.to && !moment(selectedDays.from).isSame(moment(selectedDays.to))) {
if (!dateRequired && selectedDays != null && selectedDays.from && selectedDays != null && selectedDays.to && moment(day).isBetween(moment(selectedDays.from), moment(selectedDays.to))) {
setEnteredTo(day);
setEnteredFrom(day);
return onChange(undefined);
}
setEnteredFrom(day);
return onChange({
from: day,
to: day
});
}
if (selectedDays != null && selectedDays.from && isAfter(day, selectedDays.from)) {
setEnteredTo(undefined);
setEnteredFrom(undefined);
return onChange({
from: selectedDays.from,
to: day
});
}
if (selectedDays != null && selectedDays.to) {
setEnteredTo(undefined);
setEnteredFrom(undefined);
return onChange({
from: day,
to: selectedDays.to
});
}
return onChange({
from: day,
to: day
});
}
}, [onDayClick, onChange, month, selectionMode, dateRequired, selectedDays, onMonthChange, week, isPreselected]);
const isSelectedFirstDay = useCallback(() => {
if (selectionMode !== "custom") {
return false;
}
if (selectedDays != null && selectedDays.from && selectedDays != null && selectedDays.to) {
return moment(selectedDays.from).isSame(selectedDays.to);
}
}, [selectionMode, selectedDays]);
const handleDayMouseEnter = useCallback(day => {
if (isPreselected && selectionMode !== "weekly") {
setEnteredTo(day);
setEnteredFrom(day);
return;
}
if (selectionMode === "daily") {
setEnteredTo(day);
setEnteredFrom(day);
}
if (selectionMode === "weekly") {
setEnteredFrom(moment(day).startOf(week).toDate());
setEnteredTo(moment(day).endOf(week).toDate());
}
if (selectionMode !== "weekly" && (!selectedDays || selectedDays != null && selectedDays.from && selectedDays != null && selectedDays.to && !moment(selectedDays.from).isSame(moment(selectedDays.to)))) {
setEnteredTo(day);
setEnteredFrom(day);
}
if (isSelectedFirstDay() && selectedDays != null && selectedDays.from) {
setEnteredFrom(selectedDays.from);
setEnteredTo(day);
}
}, [selectionMode, isSelectedFirstDay, selectedDays, week, isPreselected]);
const onDayMouseLeave = useCallback(() => {
if (selectionMode === "weekly" || selectionMode === "daily" || selectionMode === "custom") {
setEnteredFrom(undefined);
setEnteredTo(undefined);
}
}, [setEnteredFrom, setEnteredTo, selectionMode]);
const onWheel = useCallback(e => {
if (stopScroll && (new Date().getTime() - stopScroll.getTime()) / 1000 < 0.9) {
return;
}
const nextMonth = showMonthPicker ? addMonths(month, 12) : addMonths(month, 1);
const previousMonth = showMonthPicker ? addMonths(month, -12) : addMonths(month, -1);
if (e.deltaY > 0.9) {
setDirection(true);
onMonthChange(nextMonth);
setStopScroll(new Date());
}
if (e.deltaY < -0.9) {
setDirection(false);
onMonthChange(previousMonth);
setStopScroll(new Date());
}
}, [stopScroll, showMonthPicker, month, onMonthChange]);
const togglePicker = useCallback(() => {
if (selectionMode !== "monthly" && selectionMode !== "quarterly") {
return setShowMonthPicker(!showMonthPicker);
}
setShowMonthPicker(true);
}, [showMonthPicker, selectionMode]);
const handleYearMonthChange = useCallback(m => {
if (onChange) {
if (selectionMode === "monthly") {
if (!dateRequired && selectedDays != null && selectedDays.from && moment(m).isSame(moment(selectedDays.from), "month")) {
return onChange(undefined);
}
onChange({
from: moment(m).startOf("month").toDate(),
to: moment(m).endOf("month").toDate()
});
}
if (selectionMode === "quarterly") {
if (!dateRequired && selectedDays != null && selectedDays.from && moment(m).isSame(moment(selectedDays.from).startOf("quarter"), "quarter")) {
return onChange(undefined);
}
onChange({
from: moment(m).startOf("quarter").toDate(),
to: moment(m).endOf("quarter").toDate()
});
}
}
onMonthChange(m);
}, [onMonthChange, onChange, selectedDays, selectionMode, dateRequired]);
const text = useMemo(() => {
if (showMonthPicker) {
return "" + month.getFullYear();
}
return moment(month).format("MMMM") + " " + (moment(month).isSame(moment(), "year") ? "" : month.getFullYear());
}, [showMonthPicker, month]);
const customNavBarElement = useCallback(props => {
return /*#__PURE__*/React.createElement("div", {
className: "c-DayPicker-wrapper"
}, /*#__PURE__*/React.createElement(CustomNavBarElement, _extends({}, props, {
showMonthPicker: showMonthPicker,
month: month,
onChangeDirection: setDirection,
onMonthChange: onMonthChange,
onClick: togglePicker
})), /*#__PURE__*/React.createElement(YearMonthPicker, _extends({}, props, {
text: text,
onClick: togglePicker,
month: month,
selectedDays: selectedDays,
onChange: handleYearMonthChange,
isShown: showMonthPicker,
selectionMode: selectionMode
})));
}, [showMonthPicker, month, onMonthChange, togglePicker, text, selectedDays, handleYearMonthChange, selectionMode]);
const onKeyDownCallback = useCallback(e => {
// Right Arrow
if (e.key === "ArrowRight") {
setDirection(true);
if (showMonthPicker) {
onMonthChange(new Date(month.getFullYear() + 1, month.getMonth()));
} else {
onMonthChange(new Date(month.getFullYear(), month.getMonth() + 1));
}
}
// Left Arrow
if (e.key === "ArrowLeft") {
setDirection(false);
if (showMonthPicker) {
onMonthChange(new Date(month.getFullYear() - 1, month.getMonth()));
} else {
onMonthChange(new Date(month.getFullYear(), month.getMonth() - 1));
}
}
// Up Arrow
if (e.key === "ArrowUp") {
setDirection(true);
onMonthChange(new Date(month.getFullYear() + 1, month.getMonth()));
}
// Down Arrow
if (e.key === "ArrowDown") {
setDirection(false);
onMonthChange(new Date(month.getFullYear() - 1, month.getMonth()));
}
}, [showMonthPicker, onMonthChange, month]);
useEffect(() => {
document.addEventListener("keydown", onKeyDownCallback);
return () => {
document.removeEventListener("keydown", onKeyDownCallback);
};
}, [month, onMonthChange, showMonthPicker, onKeyDownCallback]);
const selected = useMemo(() => {
const dates = [];
if (!(selectedDays != null && selectedDays.from)) return [];
// If from and to dates are the same, return an array with one item
if (moment(selectedDays == null ? void 0 : selectedDays.from).isSame(selectedDays == null ? void 0 : selectedDays.to, "day")) {
dates.push(selectedDays == null ? void 0 : selectedDays.from);
return dates;
}
let currentDate = moment(selectedDays == null ? void 0 : selectedDays.from);
while (currentDate.isSameOrBefore(selectedDays == null ? void 0 : selectedDays.to, "day")) {
dates.push(currentDate.toDate());
currentDate = currentDate.add(1, "days");
}
return dates;
}, [selectedDays == null ? void 0 : selectedDays.from, selectedDays == null ? void 0 : selectedDays.to]);
return /*#__PURE__*/React.createElement(StyledDatePicker, {
className: "c-date-picker-wrapper",
onWheel: onWheel
}, /*#__PURE__*/React.createElement(SwitchTransition, {
mode: "out-in"
}, /*#__PURE__*/React.createElement(StyledDatePickerCSSTransition, {
key: showMonthPicker ? month.getFullYear() : month.getMonth(),
timeout: 300,
classNames: "c-date-picker__animation",
$direction: direction
}, /*#__PURE__*/React.createElement(StyledDayPicker, _extends({}, rest, {
mode: "multiple",
showOutsideDays: true,
disabled: disabledDays,
selected: selected,
onDayClick: handleDayClick,
modifiers: modifiers,
onDayMouseEnter: handleDayMouseEnter,
onDayMouseLeave: onDayMouseLeave,
className: className,
$isYearlyView: showMonthPicker,
month: month,
components: {
Caption: customNavBarElement,
DayContent: renderDay
},
classNames: customClassNames,
modifiersClassNames: modifiersClassNames,
fixedWeeks: fixedWeeks,
weekStartsOn: firstDayOfWeek,
formatters: {
formatWeekdayName: formatWeekdayName
}
})))));
};
DatePicker.displayName = "DatePicker";
//# sourceMappingURL=DatePicker.js.map