@adaptabletools/adaptable
Version:
Powerful data-agnostic HTML5 AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements
105 lines (104 loc) • 6.21 kB
JavaScript
import * as React from 'react';
import OverlayTrigger from '../OverlayTrigger';
import { useEffect, useState } from 'react';
import useProperty from '../utils/useProperty';
import FieldWrap from '../FieldWrap';
import SimpleButton from '../SimpleButton';
import { Flex } from 'rebass';
import { DateFormatter } from '../../Utilities/Helpers/FormatHelper';
import { useDatepickerContext } from './DatepickerContext';
import { DayPicker } from 'react-day-picker';
import { AdaptableDateInlineInput } from '../../View/Components/AdaptableInput/AdaptableDateInlineInput';
import { isValid, addYears, endOfYear, startOfYear, addDays, addBusinessDays, } from 'date-fns';
const DatepickerOverlay = ({ onHide, children, onKeyDown, onMouseDown, }) => {
const domRef = React.useRef(null);
return (React.createElement("div", { className: "ab-Datepicker-Overlay", ref: domRef, onKeyDown: onKeyDown, onMouseDown: onMouseDown, onBlur: (e) => {
const { relatedTarget } = e;
const node = domRef.current;
// relatedTarget is the newly focused element as a result of this blur event
// so we close the overlay when the newly focused element is outside the overlay
if (relatedTarget == null || !node.contains?.(relatedTarget)) {
onHide();
}
} }, children));
};
const END_MONTH = endOfYear(addYears(new Date(), 10));
const START_MONTH = startOfYear(addYears(new Date(), -50));
export const Datepicker = React.forwardRef((props, ref) => {
const { dateProps, required, disabled, style, placeholder, showWeekNumber, showOutsideDays, value: _, defaultValue: __, onChange: ___, datepickerButtons, showClearButton, autoFocus, ...boxProps } = props;
const datepickerContext = useDatepickerContext();
let [value, setValue] = useProperty(props, 'value', undefined, {
onChange: props.onChange,
});
useEffect(() => {
// when value is reset, also reset the month to the current month
if (!value) {
setMonth(new Date());
}
}, [!!value]);
const [month, setMonth] = useState(value ?? new Date());
const updateValue = (value) => {
setValue(value);
setMonth(value ?? new Date());
};
const inputValue = DateFormatter(value, { Pattern: dateProps.format }) ?? '';
const [visible, doSetVisible] = useState(false);
const setVisible = (visible, keyboardEventKey) => {
doSetVisible(visible);
if (!visible) {
datepickerContext?.onHide?.(keyboardEventKey);
}
else {
datepickerContext?.onShow?.();
}
};
const clearValue = () => {
updateValue(undefined);
};
const renderButton = (label, onClick) => (React.createElement(SimpleButton, { onClick: onClick, margin: '2px' }, label));
const todayDate = new Date();
const footerButtonsMap = {
clear: renderButton('Clear', () => clearValue()),
close: renderButton('Close', () => setVisible(false)),
today: renderButton('Today', () => updateValue(todayDate)),
tomorrow: renderButton('Tomorrow', () => updateValue(addDays(todayDate, 1))),
yesterday: renderButton('Yesterday', () => updateValue(addDays(todayDate, -1))),
nextWorkday: renderButton('Next Workday', () => updateValue(addBusinessDays(todayDate, 1))),
prevWorkday: renderButton('Prev Workday', () => updateValue(addBusinessDays(todayDate, -1))),
'-': React.createElement("div", { style: { flex: '1 1 1%' } }),
'|': React.createElement("hr", { style: { width: '100%', height: 0, margin: 0, border: 'none' } }),
};
const footerButtons = datepickerButtons.map((buttonKey, index) => React.cloneElement(footerButtonsMap[buttonKey], { key: index }));
const clearButton = showClearButton !== false ? (React.createElement(SimpleButton, { "data-name": "clear", variant: "text", tooltip: "Clear", iconSize: 20, padding: 0, icon: "close", onMouseDown: (e) => {
e.preventDefault();
clearValue();
}, accessLevel: 'Full' })) : null;
const calendarButton = (React.createElement(SimpleButton, { disabled: disabled, variant: "text", icon: "calendar", tooltip: "Date", iconSize: 20, px: 0, py: 0, onClick: () => setVisible(true) }));
return (React.createElement(Flex, null,
React.createElement(OverlayTrigger, { visible: visible, render: () => (React.createElement(DatepickerOverlay, { onMouseDown: props.onMouseDown, onHide: () => setVisible(false), onKeyDown: (e) => {
if (e.key === 'Escape' || e.key === 'Enter') {
setVisible(false, e.key);
}
} },
React.createElement(DayPicker, { fixedWeeks: true, autoFocus: autoFocus ?? true, showWeekNumber: showWeekNumber, showOutsideDays: showOutsideDays, mode: "single", captionLayout: "dropdown", month: isNaN(+month) ? new Date() : month, selected: value, onMonthChange: setMonth, onSelect: updateValue, startMonth: START_MONTH, endMonth: END_MONTH, footer: React.createElement(Flex, { justifyContent: "space-between", mt: 2, flexWrap: 'wrap' }, footerButtons) }))) },
React.createElement(FieldWrap, { ...boxProps, style: {
borderRadius: style?.borderRadius,
width: style?.width,
maxWidth: style?.maxWidth,
border: style?.border,
}, className: "ab-Datepicker", onFocus: () => {
if (!visible) {
setVisible(true);
}
} },
React.createElement(AdaptableDateInlineInput, { ref: ref, value: inputValue,
// We do not want to show the format when the date-picker is visible
placeholder: placeholder ?? '', onChange: (value) => {
const date = new Date(value);
if (isValid(date)) {
updateValue(date);
}
}, style: style, disabled: disabled }),
!!inputValue ? clearButton : null,
calendarButton))));
});