"react": "^18.2.0",
"typescript": "^4.9.5",
"date-fns": "^2.30.0",
"react-big-calendar": "^1.8.1",
"@types/react-big-calendar": "^1.6.4",
"react-datepicker": "^4.14.1",
"@types/react-datepicker": "^4.11.2"
React에서 활용 가능한 DatePicker Library 정리
위 글을 참고하여 react-datepicker라는 캘린더 라이브러리를 사용하기로 결정하였다!
그리고 구글캘린더 왼쪽 작은 달력을 커스텀하게 CSS를 작업하고 나서
큰 달력 부분에 CSS를 적용하려고 했는데 문제가 발생했다.
react-datepicker라는 라이브러리의 CSS를 커스텀하게 변경하려면 기존 class를 찾아 그 스타일을 덮어씌우는 형태로 작성하게 된다.
즉, 작은 달력, 큰 달력 상관없이 같은 CSS가 적용되게 되었고
React-CSS-적용하기
위 글에 따라 모듈 형식으로 CSS를 분리하려고 했으나
CSS Module이 클래스 이름 중복 방지를 위해 클래스명 뒤에 랜덤한 값을 추가하여 커스텀한 스타일이 적용되지 않는 이슈가 있었다.
따라서 달력 라이브러리를 두개로 나누어 사용하고자한다.
두 달력 라이브러리 모두 타입스크립트를 지원하며,
큰 달력의 경우 일마다 커스텀하게 event를 등록하는 기능이 있으면 좋은데 react-big-calendar가 지원하기 때문에 선택하게 되었다.
import React, { useState } from 'react';
import DatePicker, { registerLocale } from 'react-datepicker';
import ko from 'date-fns/locale/ko';
import 'react-datepicker/dist/react-datepicker.css';
registerLocale("ko", ko);
function MiniCalendar () {
const [selectedDate, setSelectedDate] = useState<Date | null>(new Date());
return (
<div className='flex justify-center items-center py-2'>
<DatePicker
dateFormat='yyyy.MM.dd' // 날짜 형태
locale="ko" // 달력 표시 언어
shouldCloseOnSelect={false} // 날짜를 선택하면 datepicker가 자동으로 닫히게 할지 여부
selected={selectedDate} // 선택된 날짜 type: Date
onChange={(date) => setSelectedDate(date)} // 다른 날짜 클릭 시 날짜 변하게 하는 이벤트 핸들러
inline // input을 클릭하여 달력을 띄우는 것이 아닌 달력만 보이도록 하는 속성
/>
</div>
);
}
export default MiniCalendar;
DatePicker는 renderCustomHeader를 지원한다.
import React, { useState } from 'react';
import DatePicker, { registerLocale } from 'react-datepicker';
import ko from 'date-fns/locale/ko';
import { getMonth, getYear } from 'date-fns';
import 'react-datepicker/dist/react-datepicker.css';
import '@styles/Main/customMiniCalendar.css';
import { BiChevronRight, BiChevronLeft } from 'react-icons/bi';
import Spacing from '@component/common/Spacing';
registerLocale("ko", ko);
interface ICustomHeader {
date: Date;
decreaseMonth: () => void;
increaseMonth: () => void;
}
function MiniCalendar () {
const [selectedDate, setSelectedDate] = useState<Date | null>(new Date());
const CustomHeader = ({date, decreaseMonth, increaseMonth}: ICustomHeader) => {
return (
<div className='flex justify-between px-2 font-sans'>
<div className='flex'>
<span>{`${getYear(date)}년`}</span>
<Spacing space='mr-1'/>
<span>{`${getMonth(date)}월`}</span>
</div>
<div>
<button type='button' onClick={decreaseMonth}>
<BiChevronLeft size="1.2rem" color='#53535a' />
</button>
<button type='button' onClick={increaseMonth}>
<BiChevronRight size="1.2rem" color='#53535a' />
</button>
</div>
</div>
)
}
return (
<div className='flex justify-center items-center py-2'>
<DatePicker
dateFormat='yyyy.MM.dd' // 날짜 형태
locale="ko" // 달력 표시 언어
shouldCloseOnSelect={false} // 날짜를 선택하면 datepicker가 자동으로 닫히게 할지 여부
selected={selectedDate} // 선택된 날짜 type: Date
onChange={(date) => setSelectedDate(date)} // 다른 날짜 클릭 시 날짜 변하게 하는 이벤트 핸들러
inline // input을 클릭하여 달력을 띄우는 것이 아닌 달력만 보이도록 하는 속성
renderCustomHeader={({ date, decreaseMonth, increaseMonth }) => ( // *년 *월 부분의 Header를 커스텀하게
<CustomHeader
date={date}
decreaseMonth={decreaseMonth}
increaseMonth={increaseMonth}
/>
)}
/>
</div>
);
}
@styles/Main/customMiniCalendar.css
.react-datepicker {
font-family: 'Roboto', 'Noto Sans KR', serif;
border: none;
border-radius: 0;
.react-datepicker__header {
background-color: #ffffff;
border-bottom: none;
border-radius: 0;
.react-datepicker__day-names {
display: flex;
justify-content: center;
align-items: center;
height: 1.4rem;
.react-datepicker__day-name {
width: 1.4rem;
height: 1.4rem;
line-height: 1.4rem;
font-size: 10px;
color: #5b5b5b;
}
}
}
.react-datepicker__triangle {
display: none;
}
.react-datepicker__month {
margin: 0;
.react-datepicker__day {
width: 1.4rem;
height: 1.4rem;
line-height: 1.4rem;
font-size: 10px;
color: #454545;
}
.react-datepicker__day--outside-month {
color: #686868;
}
.react-datepicker__day--selected {
border-radius: 50px;
background-color: #1D73E8;
color: #ffffff;
font-weight: 400;
}
}
}
import React, { useState, useCallback, useEffect } from 'react';
import { Calendar, momentLocalizer, EventProps } from 'react-big-calendar'
import moment from 'moment';
import 'react-big-calendar/lib/css/react-big-calendar.css';
import '@styles/Main/customMainCalendar.css';
moment.locale('ko-KR');
const localizer = momentLocalizer(moment);
function MainCalendar() {
return (
<div className='h-full'>
<Calendar
localizer={localizer}
startAccessor="start"
endAccessor="end"
/>
</div>
)
}
export default MainCalendar;
components 속성을 사용해서 컴포넌트를 추가할 수 있다!
react-big-calendar의 공식문서에서 components에 대해 자세히 볼 수 있다!
vsc에서 command를 누른채 components를 타고 들어가면
타입들도 자세히 확인할 수 있다!
예시)
전체코드는 github 링크를 참고해주세요!
<Calendar
localizer={localizer}
startAccessor="start"
endAccessor="end"
components={{
toolbar: StyleNone,
dateCellWrapper: StyleNone,
month: {
header: MonthHeader,
dateHeader: DateHeader,
event: EventElement,
}
}}
/>
커스텀 엘리먼트로만으로는 모든 CSS를 커스텀할 수는 없었다.
예를 들어 month의 event에 컴포넌트를 추가하면 다음 화면이 나온다
기본 CSS를 없애기 위해서 다음과 같이 CSS를 덮어씌우는 과정도 필요했다.
전체 코드는 github를 참고해주세요!
.rbc-row-segment {
.rbc-event {
padding: 0;
background-color: transparent;
}
}