이슈 해결/Frontend

[shadcn] calendar build error - React DayPicker 9.4.3 migration

씨씨상 2024. 12. 12. 16:17

 

 

shadcn calendar를 사용할 일이 있었는데 github bugfix가 19시간 전이라 신기해서 찍어두었습니다.

기술이 바뀌고 마이그레이션하는 건 늘 있는 일이지만 작업 중 겪고 있는 이슈가 현재진행형으로 해결된 건 처음입니다.

 

방금 막 UI 적용을 마쳤지만 update가 있다면 적용해주는 것이 인지상정

 

 

 

어떤 이슈인가요?

 

 

shadcn에서 calendar를 사용하면 빌드할 때 사용하지 않는 props로 인해 lint 에러가 발생합니다.

하단은 calendar의 기본 코드입니다.

 

...
components={{
  IconLeft: ({ ...props }) => <ChevronLeft className="h-12 w-12" />,
  IconRight: ({ ...props }) => <ChevronRight className="h-12 w-12" />,
}}
...

 

 

이전 프로젝트를 했을 때는 { ...props } 를 아예 지워 버려 해결했던 기억이 있는데요.

같은 이슈로 불편함을 겪은 사람들이 shadcn github에 bug issue 등록을 해두었고, 그에 대한 답변이 달린 상태입니다. 

 

 

[bug]: Building production package fails due to Calendar component · Issue #5600 · shadcn-ui/ui

Describe the bug Running bun run build (or npm run build) produces this error, and fails to build: Type error: Object literal may only specify known properties, and 'IconLeft' does not exist in typ...

github.com

 

 

 

어떤 것들이 바뀌었나요?

 


함께 마이그레이션 문서를 확인하며 적용해 보겠습니다. 코드는 shadcn calendar가 기준입니다.

 

 

Upgrading to v9 | React DayPicker

This release includes important updates related to accessibility, styles, internationalization and performance. See the changelog for the full list of changes.

daypicker.dev

 

가장 먼저 사용하는 React DayPicker를 최신 버전으로 받아줍시다.

 

npm install react-day-picker@latest

 

props로 인해 에러가 발생했던 만큼, 컴포넌트 chevron을 불러오는 방식에 변화가 생겼습니다. calendar의 components 코드를 변경해 줍시다.

 

...
components={{
  Chevron: (props) => {
    if (props.orientation === 'left') {
      return <ChevronLeftIcon className="h-4 w-4" {...props} />;
    }
    return <ChevronRightIcon className="h-4 w-4" {...props} />;
  },
}}
...

 

다음으로 마이그레이션 문서에 나와있는 대로 ClassNames를 변경해야 하는데요. 주된 변경사항은 다음과 같습니다.

 

Old Name New Name
button button_previous, button_next
button_reset button_previous, button_next
caption month_caption
caption_between Removed
caption_dropdowns dropdowns
caption_end Removed
caption_start Removed
cell day - ⚠️ The previous day element is now day_button.
day_disabled disabled
day_hidden hidden
day_outside outside
day_range_end range_end
day_range_middle range_middle
day_range_start range_start
day_selected selected
day_today today
dropdown_icon chevron
dropdown_month months_dropdown
dropdown_year years_dropdown
head Removed
head_cell weekday
head_row weekdays
multiple_months Removed. Use data-multiple-months data attribute.
nav_button button_previous, button_next
nav_button_next button_next
nav_button_previous button_previous
nav_icon chevron, button_next, button_previous
row week
table month_grid
tbody weeks
tfoot footer
vhidden Removed
weeknumber week_number
with_weeknumber Removed. Use data-week-numbers data attribute.

 

이대로 Calendar의 ClassNames를 변경하면...

 

...

.....

.........

 

 

UI가 조금 틀어집니다. (제 프로젝트 기준)

 

복사 붙여넣기를 선호하실 분들을 위해 제 코드를 첨부합니다.

하단 코드는 tailwind의 :has rounded 코드가 작동하지 않는 중인데, 일정이 급한 프로젝트를 하는 중이라 그대로 놔두었으니 그 부분은 감안해주시면 감사하겠습니다.
뭐 곧 shadcn이 calendar를 업데이트 해주겠죠 🤗

 

'use client';

import * as React from 'react';
import { ChevronLeftIcon, ChevronRightIcon } from 'lucide-react';
import { DayPicker } from 'react-day-picker';

import { cn } from '@/lib/utils';
import { buttonVariants } from '@/components/ui/button';

export type CalendarProps = React.ComponentProps<typeof DayPicker>;

function Calendar({ className, classNames, showOutsideDays = true, ...props }: CalendarProps) {
  return (
    <DayPicker
      showOutsideDays={showOutsideDays}
      className={cn('p-3', className)}
      classNames={{
        months: 'relative flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0',
        month: 'space-y-4',
        month_caption: 'flex justify-center pt-1 relative items-center',
        caption_label: 'text-sm font-semibold',
        nav: 'z-50 absolute top-1 right-0',
        nav_button: cn(
          buttonVariants({ variant: 'outline' }),
          'h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100'
        ),
        nav_button_previous: 'absolute left-1',
        nav_button_next: 'absolute right-1',
        month_grid: 'w-full border-collapse space-y-1',
        weekdays: 'flex',
        weekday: 'text-muted-foreground w-9 font-normal text-[0.8rem]',
        week: 'flex w-full mt-2',
        day: 'day-cell h-9 w-9 text-center text-sm p-0 relative [&:has([aria-selected].day-range-end)]:rounded-r-md [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected])]:bg-accent first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md focus-within:relative focus-within:z-20',
        day_button: 'day-button h-9 w-9 p-0 font-normal aria-selected:opacity-100',
        range_end: 'day-range-end',
        selected:
          'bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground',
        today: 'bg-accent text-accent-foreground',
        outside: 'day-outside text-muted-foreground aria-selected:bg-accent/50 aria-selected:text-muted-foreground',
        disabled: 'text-muted-foreground opacity-50',
        range_middle: 'aria-selected:bg-accent aria-selected:text-accent-foreground',
        hidden: 'invisible',
        ...classNames,
      }}
      components={{
        Chevron: (props) => {
          if (props.orientation === 'left') {
            return <ChevronLeftIcon className="h-4 w-4" {...props} />;
          }
          return <ChevronRightIcon className="h-4 w-4" {...props} />;
        },
      }}
      {...props}
    />
  );
}
Calendar.displayName = 'Calendar';

export { Calendar };

 

완성한 캘린더

 

짜잔~ 여기까지 하면 완성입니다.

 

 

 

 

 

[출처]

Shadcn Calendar

 

Calendar

A date field component that allows users to enter and edit date.

ui.shadcn.com

React DayPicker

 

Styling | React DayPicker

DayPicker comes with a minimal style inspired by MacOS date pickers, designed to be extended and customized.

daypicker.dev