next.js 로 사이드 프로젝트 시작 하면서 달력 자체를 만드는 것보다는 달력을 활용한 것을 만들어보고 싶었다. 그래서 기존 캘린더 라이브러리를 검토하게 되었다.
마지막까지 고민했던 대상은 nhn 에서 만든 tui calendar와 react-big-calendar이다.
초기 선택의 기준은 모바일 대응이 얼마나 잘되고 있는지 여부였다.
tui-calendar 는 react-big-calendar 에 비해 더 높은 star 수를 확보했지만 mobile 모드로 전환 시 예제가 스크린샷으로만 제공되는 아쉬움이 있었다. 반면 react-big-calendar 는 resposive 한 대응으로 모바일까지 잘 대응되는 모습에 react-big-calendar 를 선택하게 되었다.
tui calendar 도 모바일에서 잘 동작할 것이라는 예상을 하지만 예제에서 모바일에 대한 대응이 되지 않았던 점이 아쉬움으로 작용했던 것 같다.
결론적으로 보면 react-big-calendar 의 선택은 만족스럽다. 그 중 가장 만족스럽게 여기는 부분은 calendar 의 커스터마이징이 용이하다는 점이다.
특히 rendering 할 컴포넌트 대상을 재정의하여 파라미터로 지정할 수 있다는 점이 굉장히 만족스러웠다.
아래 components 옵션을 보면 재정의할 수 있는 컴포넌트가 얼마나 다양한지를 확인할 수 있다.
components: PropTypes.shape({
event: PropTypes.elementType,
eventWrapper: PropTypes.elementType,
eventContainerWrapper: PropTypes.elementType,
dateCellWrapper: PropTypes.elementType, /* 이번 예제에서 재정의한 대상 #1*/
dayColumnWrapper: PropTypes.elementType,
timeSlotWrapper: PropTypes.elementType,
timeGutterHeader: PropTypes.elementType,
timeGutterWrapper: PropTypes.elementType,
resourceHeader: PropTypes.elementType,
toolbar: PropTypes.elementType,
agenda: PropTypes.shape({
date: PropTypes.elementType,
time: PropTypes.elementType,
event: PropTypes.elementType,
}),
day: PropTypes.shape({
header: PropTypes.elementType,
event: PropTypes.elementType,
}),
week: PropTypes.shape({
header: PropTypes.elementType,
event: PropTypes.elementType,
}),
month: PropTypes.shape({
header: PropTypes.elementType,
dateHeader: PropTypes.elementType,/* 이번 예제에서 재정의한 대상 #2*/
event: PropTypes.elementType,
}),
}),
실례로 나는 음력 날짜 표기를 위해 dateHeader
를 재정의했고, 선택된 날짜에 하이라이팅 효과를 주기 위해 dateCellWrapper
를 재정의했다.
<Calendar
components={{
month: {
dateHeader: MyDateHeader,
},
dateCellWrapper: MyDateCellWrapper,
}}
/>
month 의 dateHeader 영역을 재정의한 MyDateHeader
는 다음과 같았다.
(실제는 약간의 최적화가 추가되어 형태는 조금 다르지만 거의 대동소이하다.)
const MyDateHeader = ({lable, date}) => {
return (
<div>
<button className="rbc-button-link" role="cell">
{label}
</button>
/* 음력날짜를 추가로 표기 */
<div className={styles.MyDateHeaderLunarDate}>
{moment(date).lunar().format("MM.DD")}
</div>
</div>)
}
이로 인해 아래와 같이 음력 날짜를 표기할 수 있게 되었다.
dateCellWrapper 을 재정의한 MyDateCellWrapper
부분은 다음과 같다.
현재 선태된 날짜의 경우 isSelected 플래그를 활성화하고 isSelected 인 경우 selected 스타일을 적용하였다.
const MyDateCellWrapper = (props) => {
// 선택상태가 변경되었을 때에만 다시 렌더링 한다.
return (
<div
className={`${styles.wrap} ${isSelected ? styles.selected : ""}`}>
{children}
</div>
);
};
적용 결과는 아래 사이트를 통해 그 결과를 확인해 볼 수 있다.
현재는 음력 달력만 적용해 보았다.
이 외에도 총 20개의 주요 요소에 대한 렌더링 커스터마이징을 통해 달력을 제공할 수 있다는 점이 매력적으로 느껴지는데 달력 서비스를 제공하면서 커스터마이징이 필요한 것을 고려한다면 꽤 괜찮은 달력 라이브러리 같다.