결과물은 이렇다 !
달력 컴포넌트외부를 어둡게 처리하고, 어두운 부분 클릭시 달력이 닫히게 구현하고 싶었다.
🎂 install
$ yarn add react-date-range
🎂 code
export const DatePicker = ({
calendarCloseHandler,
dateRange,
setDateRange,
}: {
calendarCloseHandler: (range: Range) => void;
dateRange: Range;
setDateRange: (range: Range) => void;
}) => {
const ref = useRef<HTMLDivElement>(null);
const [isShowCalendar, setIsShowCalendar] = useState<boolean>(false);
const [focusedDateRange, setFocusedDateRange] = useState<[number, number]>([0, 0]);
const IsShowCalendarHandler = (range: Range) => {
if (focusedDateRange[1] === 1) {
calendarCloseHandler(range);
setIsShowCalendar(false);
}
};
const checkIfClickedOutside = (e: MouseEvent) => {
if (ref.current && !ref.current.contains(e.target as Node)) {
setIsShowCalendar(false);
}
};
useEffect(() => {
if (!i18n.isInitialized) return;
}, [i18n.isInitialized]);
useEffect(() => {
document.addEventListener("mousedown", checkIfClickedOutside);
return () => {
// Cleanup the event listener
document.removeEventListener("mousedown", checkIfClickedOutside);
};
}, [isShowCalendar]);
return (
<div className="mState typeDate">
<div style={{ position: "relative" }}>
<div className="mDateRangePicker" onClick={() => setIsShowCalendar(true)}>
{dayjs(dateRange.startDate).format("YYYY-MM-DD")} ~ {dayjs(dateRange.endDate).format("YYYY-MM-DD")}
</div>
</div>
<div className={isShowCalendar ? "mDateRangeModal" : ""}>
{isShowCalendar && (
<div ref={ref} className="mDateRangeModal2">
<DateRange
// @ts-ignore
locale={i18n.language.substr(0, 2) in dateFnsLocales ? dateFnsLocales[i18n.language.substr(0, 2)] : dateFnsLocales["enUS"]}
months={1}
onChange={async (range) => {
setDateRange(range.selection);
IsShowCalendarHandler(range.selection);
}}
focusedRange={focusedDateRange}
onRangeFocusChange={setFocusedDateRange}
showDateDisplay={false}
ranges={[dateRange]}
minDate={subDays(new Date(), 365)}
maxDate={subDays(new Date(), 1)}
/>
</div>
)}
</div>
</div>
);
};
setIsShowCalendar
state를 통해 달력 컴포넌트를 출력할 지 결정한다.
상위 props인 dateRange
, setDateRange
를 통해 달력 컴포넌트에서 클릭 이벤트가 발생할 시, 상위 컴포넌트로 선택한 날짜를 전달한다.
🎂 뒷 부분 어둡게 하기
이건 css 로 처리했음 !react-date-range
에서 제공하는 DateRange
컴포넌트 상위 > 상위 div 에(나의 경우 mDateRangeModal) background
값으로 rgba(0, 0, 0, 0.7)
를 적용했다.
그 밖에 가운데 정렬 등등은 다음으로 처리 !
.mDateRangeModal {
display: flex;
position: fixed;
top: 0px;
left: 0px;
right: 0px;
z-index: 102;
height: 100%;
align-items: center;
background: rgba(0, 0, 0, 0.7);
}
.mDateRangeModal2 {
max-width: calc(100% - 32px);
margin: 0 auto;
}
🎂 close when outside onClick
const ref = useRef<HTMLDivElement>(null);
const checkIfClickedOutside = (e: MouseEvent) => {
if (ref.current && !ref.current.contains(e.target as Node)) {
setIsShowCalendar(false);
}
};
useEffect(() => {
document.addEventListener("mousedown", checkIfClickedOutside);
return () => {
// Cleanup the event listener
document.removeEventListener("mousedown", checkIfClickedOutside);
};
}, [isShowCalendar]);
DateRange
컴포넌트에 ref를 줘도 되는데, 큰 이유 없이 한단계 상위 div를 dif 로 잡았다. (ts 때문이였나 ?)
checkIfClickedOutside
를 통해 ref 이외의 곳을 클릭할 경우 캘린더를 닫으며, useEffect 를 통해 해당 이벤트를 주입시킨다.
반응형
'react' 카테고리의 다른 글
emotion in next.js + typescript (1) | 2022.05.06 |
---|---|
nextjs deployment with 644 permission (0) | 2022.01.01 |
react-i18next in next.js (0) | 2021.10.11 |
useContext in navigation bar (0) | 2021.10.09 |
jsx switch (0) | 2021.09.06 |