pouncejs
Version:
A collection of UI components from Panther labs
223 lines (209 loc) • 7.66 kB
JavaScript
import _extends from "@babel/runtime/helpers/extends";
import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/objectWithoutPropertiesLoose";
import React, { useState, useCallback } from 'react';
import dayjs from 'dayjs';
import Box from '../Box';
import Flex from '../Flex';
import Button from '../Button';
import Month from './Month';
import { IconButton } from '../../index';
import DateWrapper from './DateWrapper';
import Heading from '../Heading';
import TextInput from '../TextInput';
import TimePicker from './TimePicker';
import ClearButton from './ClearButton';
import { noop, dateToDayjs, now } from '../../utils/helpers';
import useDisclosure from '../../utils/useDisclosure';
import useEscapeKey from '../../utils/useEscapeKey';
import usePrevious from '../../utils/usePrevious';
import useOutsideClick from '../../utils/useOutsideClick';
/**
* A component to help selecting dates in forms
*
* Apart from the props specified down below, you can pass any valid prop from the
* <a href="/#/TextInput">TextInput</a> component (i.e. placeholder, etc.)
*
* */
var DateInput = function DateInput(_ref) {
var value = _ref.value,
_ref$format = _ref.format,
format = _ref$format === void 0 ? 'MM/DD/YYYY' : _ref$format,
alignment = _ref.alignment,
withTime = _ref.withTime,
_ref$mode = _ref.mode,
mode = _ref$mode === void 0 ? '24h' : _ref$mode,
_ref$disableReset = _ref.disableReset,
disableReset = _ref$disableReset === void 0 ? false : _ref$disableReset,
_ref$variant = _ref.variant,
variant = _ref$variant === void 0 ? 'outline' : _ref$variant,
_ref$onChange = _ref.onChange,
onChange = _ref$onChange === void 0 ? noop : _ref$onChange,
_ref$timezone = _ref.timezone,
timezone = _ref$timezone === void 0 ? 'local' : _ref$timezone,
rest = _objectWithoutPropertiesLoose(_ref, ["value", "format", "alignment", "withTime", "mode", "disableReset", "variant", "onChange", "timezone"]);
var ref = React.useRef(null);
var targetRef = React.useRef(null);
var _useState = useState(dateToDayjs(value, timezone)),
currentDate = _useState[0],
setCurrentDate = _useState[1];
var _useState2 = useState(currentDate || now(timezone)),
currentMonth = _useState2[0],
setCurrentMonth = _useState2[1];
var resetLabel = React.useMemo(function () {
return withTime ? 'Clear Date & Time' : 'Clear Date';
}, [withTime]);
var _useDisclosure = useDisclosure(),
isOpen = _useDisclosure.isOpen,
open = _useDisclosure.open,
close = _useDisclosure.close;
var previousDate = usePrevious(dateToDayjs(value, timezone)); // Handles value & timezone updates outside of the component (i.e. a form has re-initialized or
// has updated its values as a result of an API call)
React.useEffect(function () {
setCurrentDate(dateToDayjs(value, timezone));
}, [value, timezone]);
var isDisabled = React.useMemo(function () {
if (dayjs.isDayjs(currentDate) && dayjs.isDayjs(previousDate)) {
return currentDate.isSame(previousDate, withTime ? 'minute' : 'day');
}
return currentDate === previousDate;
}, [currentDate, previousDate]);
var onNextMonth = useCallback(function (e) {
e.preventDefault();
var next = currentMonth.add(1, 'month');
setCurrentMonth(next);
}, [currentMonth, setCurrentMonth]);
var onPreviousMonth = useCallback(function (e) {
e.preventDefault();
var next = currentMonth.subtract(1, 'month');
setCurrentMonth(next);
}, [currentMonth, setCurrentMonth]);
var onCancel = useCallback(function () {
setCurrentDate(dateToDayjs(value, timezone));
close();
}, [close, value, timezone, setCurrentDate]);
var onClear = useCallback(function () {
return setCurrentDate(dateToDayjs(undefined));
}, [setCurrentDate]);
var onApply = useCallback(function (e) {
e.preventDefault();
onChange(currentDate == null ? void 0 : currentDate.startOf(withTime ? 'minute' : 'day').toDate());
close();
}, [close, onChange, currentDate, disableReset]);
var onDaySelect = useCallback(function (dateChanged) {
var updated = dateChanged;
if (currentDate) {
updated = dayjs(currentDate).year(dateChanged.year()).month(dateChanged.month()).date(dateChanged.date());
}
setCurrentDate(updated);
}, [currentDate, setCurrentDate]);
var onTimeUpdate = useCallback(function (timeUpdated) {
setCurrentDate(timeUpdated);
}, []); // Close on ESC key presses
useEscapeKey({
ref: ref,
callback: onCancel,
disabled: !isOpen
}); // Close popover on clicks outside
useOutsideClick({
refs: [ref, targetRef],
callback: onCancel,
disabled: !isOpen
});
return /*#__PURE__*/React.createElement(Box, {
position: "relative",
ref: targetRef
}, /*#__PURE__*/React.createElement(TextInput, _extends({}, rest, {
variant: variant,
value: currentDate ? currentDate.format(format) : '',
onClick: open,
autoComplete: "off",
"aria-autocomplete": "none",
tabIndex: -1,
readOnly: true
})), /*#__PURE__*/React.createElement(Box, {
position: "absolute",
top: 2,
right: 3,
zIndex: 2
}, /*#__PURE__*/React.createElement(IconButton, {
variant: "unstyled",
"aria-label": "Toggle picker",
size: "medium",
icon: "calendar",
onClick: isOpen ? onCancel : open
})), /*#__PURE__*/React.createElement(DateWrapper, {
ref: ref,
targetRef: targetRef,
alignment: alignment,
isExpanded: isOpen
}, /*#__PURE__*/React.createElement(Flex, {
align: "center",
justify: "space-between",
p: 4
}, /*#__PURE__*/React.createElement(IconButton, {
onClick: onPreviousMonth,
size: "medium",
icon: "arrow-back",
"aria-label": "Go to previous month"
}), /*#__PURE__*/React.createElement(Box, {
as: Heading,
fontSize: "medium",
fontWeight: "bold",
tabIndex: "-1"
}, currentMonth.format('MMMM YYYY')), /*#__PURE__*/React.createElement(IconButton, {
onClick: onNextMonth,
size: "medium",
icon: "arrow-forward",
"aria-label": "Go to next month"
})), /*#__PURE__*/React.createElement(Box, {
px: 4,
pb: 4
}, /*#__PURE__*/React.createElement(Month, {
onDaySelect: onDaySelect,
daysSelected: currentDate && [currentDate],
year: currentMonth.year(),
month: currentMonth.month(),
timezone: timezone
})), withTime && /*#__PURE__*/React.createElement(Flex, {
align: "center",
justify: "center",
borderTop: "1px solid",
borderColor: "navyblue-300",
p: 4
}, /*#__PURE__*/React.createElement(Flex, {
align: "center",
justify: "center",
spacing: 3
}, /*#__PURE__*/React.createElement(TimePicker, {
label: "Time",
mode: mode,
onTimeUpdate: onTimeUpdate,
timezone: timezone,
date: currentDate
}))), /*#__PURE__*/React.createElement(Flex, {
align: "center",
justify: "center",
borderTop: "1px solid",
borderColor: "navyblue-300"
}, /*#__PURE__*/React.createElement(Flex, {
align: "center",
justify: "center",
p: 3,
spacing: 3
}, /*#__PURE__*/React.createElement(Button, {
onClick: onCancel,
size: "medium",
variantColor: "gray-500"
}, "Cancel"), /*#__PURE__*/React.createElement(Button, {
disabled: isDisabled,
onClick: onApply,
size: "medium"
}, "Apply"))), !disableReset && /*#__PURE__*/React.createElement(Flex, {
align: "center",
justify: "center",
pb: 3
}, /*#__PURE__*/React.createElement(ClearButton, {
onClick: onClear
}, resetLabel))));
};
export default /*#__PURE__*/React.memo(DateInput);