diff --git a/frontend/package.json b/frontend/package.json index 742c47ff5f..5bef82954a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -69,6 +69,7 @@ "react-i18next": "^12.2.0", "react-list": "^0.8.16", "react-markdown": "^8.0.0", + "react-merge-refs": "^2.0.2", "react-number-format": "^5.1.4", "react-redux": "^8.0.5", "react-router-dom": "^6.9.0", diff --git a/frontend/src/js/ui-components/InputDate/CustomHeader.tsx b/frontend/src/js/ui-components/InputDate/CustomHeader.tsx index 83b0b594c0..310df8480b 100644 --- a/frontend/src/js/ui-components/InputDate/CustomHeader.tsx +++ b/frontend/src/js/ui-components/InputDate/CustomHeader.tsx @@ -102,7 +102,7 @@ const YearMonthSelect = ({ value: i, })); - const [yearSelectOpen, setYearSelectOpen] = useState(false); + const [yearSelectOpen, setYearSelectOpen] = useState(true); const [monthSelectOpen, setMonthSelectOpen] = useState(false); const handleClick = () => { if (yearSelectOpen || monthSelectOpen) { diff --git a/frontend/src/js/ui-components/InputDate/InputDate.tsx b/frontend/src/js/ui-components/InputDate/InputDate.tsx index 00e57bc56b..6d035fc919 100644 --- a/frontend/src/js/ui-components/InputDate/InputDate.tsx +++ b/frontend/src/js/ui-components/InputDate/InputDate.tsx @@ -1,8 +1,11 @@ import styled from "@emotion/styled"; -import { createElement, forwardRef, useRef, useState } from "react"; +import { faCalendar } from "@fortawesome/free-regular-svg-icons"; +import { createElement, forwardRef, useRef } from "react"; import ReactDatePicker from "react-datepicker"; import "react-datepicker/dist/react-datepicker.css"; +import { mergeRefs } from "react-merge-refs"; +import IconButton from "../../button/IconButton"; import { formatDate, parseDate } from "../../common/helpers/dateHelper"; import BaseInput, { Props as BaseInputProps } from "../BaseInput"; @@ -19,11 +22,22 @@ const Root = styled("div")` } .react-datepicker-popper[data-placement^="bottom"] { padding-top: 4px; - transform: translate3d(0, 32px, 0) !important; } .react-datepicker-popper[data-placement^="top"] { padding-bottom: 0; - transform: translate3d(0, 32px, 0) !important; + } +`; + +const CalendarButton = styled(IconButton)` + position: absolute; + left: 0; + top: 0; + padding: 8px 10px; +`; + +const StyledBaseInput = styled(BaseInput)` + input { + padding-left: 28px; } `; @@ -45,28 +59,12 @@ type Props = Omit & { onCalendarSelect?: (val: string) => void; }; -// TODO: Remove this once we have solved -// - that the date picker overlays other fields in forms -const TEMPORARILY_DISABLED_DATE_PICKER = true; - -const InputDate = forwardRef( +const InputDate = forwardRef( ( - { - className, - value, - dateFormat, - onChange, - onCalendarSelect, - onFocus, - onBlur, - onClick, - ...props - }, + { className, value, dateFormat, onChange, onCalendarSelect, ...props }, ref, ) => { const datePickerRef = useRef(null); - const [hasFocus, setHasFocus] = useState(false); - const [focusBlocked, setFocusBlocked] = useState(false); return ( ( if (e.key === "Escape") datePickerRef.current?.setOpen(false); }} > - { onChange(val as string); }} - onFocus={(e) => { - if (focusBlocked) { - e.currentTarget.blur(); - setFocusBlocked(false); - } else { - onFocus?.(e); - setHasFocus(true); - datePickerRef.current?.setOpen(true); - } - }} - onBlur={(e) => { - onBlur?.(e); - setHasFocus(false); - }} - onClick={(e) => { - onClick?.(e); - if (hasFocus) { - datePickerRef.current?.setOpen(true); - } - }} inputProps={{ ...props?.inputProps, onKeyPress: (e) => { @@ -111,8 +88,12 @@ const InputDate = forwardRef( }, }} /> + datePickerRef.current?.setOpen(true)} + /> { if (!val) { @@ -122,7 +103,6 @@ const InputDate = forwardRef( const selectedDate = formatDate(val, dateFormat); onChange(selectedDate); onCalendarSelect?.(selectedDate); - setFocusBlocked(true); datePickerRef.current?.setOpen(false); }} onClickOutside={() => datePickerRef.current?.setOpen(false)} @@ -130,7 +110,16 @@ const InputDate = forwardRef( customInput={createElement(HiddenInput)} calendarContainer={StyledCalendar} calendarStartDay={1} - disabled={TEMPORARILY_DISABLED_DATE_PICKER} + popperProps={{ + modifiers: [ + { + name: "preventOverflow", + options: { + mainAxis: false, + }, + }, + ], + }} /> ); diff --git a/frontend/src/js/ui-components/InputDateRange.tsx b/frontend/src/js/ui-components/InputDateRange.tsx index e58a00745e..33d2bdb747 100644 --- a/frontend/src/js/ui-components/InputDateRange.tsx +++ b/frontend/src/js/ui-components/InputDateRange.tsx @@ -2,6 +2,7 @@ import { css } from "@emotion/react"; import styled from "@emotion/styled"; import { faCalendar } from "@fortawesome/free-regular-svg-icons"; import { FC, ReactNode, createRef, useMemo } from "react"; +import ReactDatePicker from "react-datepicker"; import { useTranslation } from "react-i18next"; import { IndexPrefix } from "../common/components/IndexPrefix"; @@ -166,7 +167,7 @@ const InputDateRange: FC = ({ const min = getDisplayDate("min", value, displayDateFormat); const max = getDisplayDate("max", value, displayDateFormat); - const maxRef = createRef(); + const maxRef = createRef(); const isMinValid = exists(value.min && parseDate(min, displayDateFormat)); const isMaxValid = exists(value.max && parseDate(max, displayDateFormat)); @@ -213,7 +214,7 @@ const InputDateRange: FC = ({ onChange={(val) => onChangeRaw("min", val as string, displayDateFormat) } - onCalendarSelect={() => maxRef.current?.focus()} + onCalendarSelect={() => maxRef.current?.setOpen(true)} onBlur={(e) => applyDate("min", e.target.value, displayDateFormat)} inputProps={{ autoFocus, diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 10880d182f..d65beaf493 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -8622,6 +8622,11 @@ react-markdown@^8.0.0: unist-util-visit "^4.0.0" vfile "^5.0.0" +react-merge-refs@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/react-merge-refs/-/react-merge-refs-2.0.2.tgz#73f576111124897dec4ea56035a97e199e8cb377" + integrity sha512-V5BGTwGa2r+/t0A/BZMS6L7VPXY0CU8xtAhkT3XUoI1WJJhhtvulvoiZkJ5Jt9YAW23m4xFWmhQ+C5HwjtTFhQ== + react-number-format@^5.1.4: version "5.1.4" resolved "https://registry.yarnpkg.com/react-number-format/-/react-number-format-5.1.4.tgz#23057d94a4f1b08e12ee41328e86be929b60a791"