UNPKG

@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
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)))); });