@veracity/vui
Version:
Veracity UI is a React component library crafted for use within Veracity applications and pages. Based on Styled Components and @xstyled.
168 lines (166 loc) • 6.32 kB
JavaScript
import { cs } from "../utils/styles.js";
import { omitThemingProps, useStyleConfig } from "../core/theme.js";
import vui from "../core/vui.js";
import { Box } from "../box/box.js";
import { Button } from "../button/button.js";
import { LineButton } from "../button/buttons.js";
import { maxDateTimestamp, minDateTimestamp } from "../calendar/consts.js";
import { Calendar } from "../calendar/calendar.js";
import Popover from "../popover/popover.js";
import { DateInput } from "./dateInput.js";
import { useCallback, useEffect, useRef, useState } from "react";
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
//#region src/datePicker/datePicker.tsx
/** Select or input a date. */
const DatePicker = vui((props, ref) => {
const { autoOpened, boundaries, popupPosition, placement, selectedDate: selectedDateProps, showClearButton, slotBottom, slotTop, onSelected, children, className, ...rest } = omitThemingProps(props);
const styles = useStyleConfig("DatePicker", props);
const [selectedDate, setSelectedDate] = useState(selectedDateProps);
const [isOpen, setIsOpen] = useState(!selectedDateProps && !!autoOpened);
const [isInvalidInputDate, setIsInvalidInputDate] = useState(true);
const [isInvalidSelectedDate, setIsInvalidSelectedDate] = useState(!selectedDate);
const [isClearButtonVisible, setIsClearButtonVisible] = useState(!!(showClearButton && selectedDateProps));
const initialDateRef = useRef(selectedDateProps);
const isStartDateInRange = (date) => !!boundaries?.startDate && !!date ? date.getTime() - boundaries.startDate.getTime() >= 0 : true;
const isEndDateInRange = (date) => !!boundaries?.endDate && !!date ? date.getTime() - boundaries.endDate.getTime() <= 0 : true;
const isValidDateRange = (date) => {
const minDateTime = new Date(minDateTimestamp);
const maxDateTime = new Date(maxDateTimestamp);
return date >= minDateTime && date <= maxDateTime;
};
useEffect(() => {
if (!isOpen) {
setSelectedDate(selectedDateProps);
setIsClearButtonVisible(!!(showClearButton && selectedDateProps));
initialDateRef.current = selectedDateProps;
}
}, [
isOpen,
selectedDateProps,
showClearButton
]);
useEffect(() => {
setIsInvalidSelectedDate(selectedDate && !isStartDateInRange(selectedDate) || selectedDate && !isEndDateInRange(selectedDate) || selectedDate && !isValidDateRange(selectedDate) || !selectedDate);
}, [selectedDate]);
const onApplyDates = useCallback((date, close) => {
onSelected?.(date);
initialDateRef.current = date;
setIsClearButtonVisible(!!(showClearButton && date));
close?.();
}, [onSelected, showClearButton]);
const onClear = useCallback((close) => {
setSelectedDate(void 0);
onSelected?.(void 0);
close?.();
}, [onSelected]);
const handlePopoverOpen = useCallback(() => setIsOpen(true), []);
const handlePopoverClose = useCallback(() => setIsOpen(false), []);
const selectDate = (range) => setSelectedDate(range?.startDate);
const onDateInputValidate = useCallback((date) => {
const minDateTime = new Date(minDateTimestamp);
const maxDateTime = new Date(maxDateTimestamp);
if (date) {
const [validateErrorPair] = [
[isNaN(date.getTime()), "Supported format is YYYY-MM-DD"],
[date < minDateTime, "Invalid date, the minimum date time is 1753-01-02"],
[date > maxDateTime, "Invalid date, the maximum date time is 9000-12-31"],
[!!boundaries?.startDate && date.getTime() - boundaries.startDate.getTime() < 0, "Invalid date"],
[!!boundaries?.endDate && date.getTime() - boundaries.endDate.getTime() > 0, "Invalid date"]
].filter(([result]) => result);
if (validateErrorPair) {
const [_, message] = validateErrorPair;
setIsInvalidInputDate(true);
return message;
}
}
return "";
}, [boundaries]);
const onDateInputChange = useCallback((date) => setSelectedDate(date), []);
const onDateInputValidateStatus = useCallback((inValid) => setIsInvalidInputDate(!inValid), []);
return /* @__PURE__ */ jsx(Box, {
className: cs("vui-datePicker", className),
position: "relative",
ref,
...styles,
...rest,
children: /* @__PURE__ */ jsx(Popover, {
defaultIsOpen: !selectedDateProps && autoOpened,
onClose: handlePopoverClose,
onOpen: handlePopoverOpen,
placement: placement ? placement : popupPosition === "right" ? "bottom-end" : void 0,
children: ({ close }) => /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Popover.Trigger, {
as: Box,
children
}), /* @__PURE__ */ jsxs(Popover.Content, {
column: true,
children: [
!!slotTop && /* @__PURE__ */ jsx(Box, {
px: 2,
children: slotTop
}),
/* @__PURE__ */ jsx(Box, {
display: "block",
mt: 2,
mx: 2,
children: /* @__PURE__ */ jsx(DateInput, {
autoFocus: true,
initialDate: selectedDate,
onChange: onDateInputChange,
onValidate: onDateInputValidate,
setValidateStatus: onDateInputValidateStatus
})
}),
/* @__PURE__ */ jsx(Box, {
mx: 2,
my: 1,
children: /* @__PURE__ */ jsx(Calendar, {
boundaries: boundaries ?? {
startDate: void 0,
endDate: void 0
},
fixedNumberOfWeeks: true,
fontWeight: 500,
minH: 200,
mode: "exact",
onSelectDates: (range) => selectDate(range),
selectedDates: {
startDate: selectedDate,
endDate: void 0
},
w: "100%"
})
}),
/* @__PURE__ */ jsxs(Box, {
alignItems: "center",
flex: 1,
ml: "auto",
pb: 2,
px: 2,
children: [isClearButtonVisible && /* @__PURE__ */ jsx(LineButton, {
flex: 1,
onClick: () => onClear(close),
size: "md",
children: "Clear"
}), /* @__PURE__ */ jsx(Button, {
disabled: isInvalidSelectedDate || isInvalidInputDate,
flex: 1,
ml: isClearButtonVisible ? 1 : 0,
onClick: () => onApplyDates(selectedDate, close),
size: "md",
children: "Apply"
})]
}),
!!slotBottom && /* @__PURE__ */ jsx(Box, {
px: 2,
children: slotBottom
})
]
})] })
})
});
});
DatePicker.displayName = "DatePicker";
//#endregion
export { DatePicker, DatePicker as default };
globalThis.__vuiVersion__ = "5.3.1"
//# sourceMappingURL=datePicker.js.map