MUIのDate Range Calendarを自力実装する

技術備忘録

MUIはさまざまなリッチなコンポーネントを提供してくれるライブラリです。MUIでは、日付も扱うパッケージもあり、@mui/x-date-pickersは日付の入力用コンポーネントを提供しています。

しかしながら、日付を範囲選択するコンポーネント(Date Range Calendar)は、proプランに加入しないと利用できないため、泣く泣く別ライブラリで代用するということもあるかもしれません。

今回は、@mui/x-date-pickers(MITライセンスの方)のみを使って、Date Range Calendar(もどき)を実現したいと思います。

スポンサーリンク

ソースコード

naoki-tateyama/MUI-date-range-calendar
Contribute to naoki-tateyama/MUI-date-range-calendar development by creating an account on GitHub.
スポンサーリンク

DateCalendar

DateCalendarには、slots propsがあり、これによってDateCalendar内の各要素を描画することができます。slotsで指定したコンポーネントには、slotPropsによってpropsを渡すことが可能です。本記事では、各日のコンポーネントである、dayをカスタマイズします。

<LocalizationProvider dateAdapter={AdapterDayjs}>
  <DateCalendar
    onChange={onClickDay}
    slots={{
      day: SelectedDay,
    }}
    slotProps={{
      day: {
        dates,
      } as object,
    }}
  />
</LocalizationProvider>;

SelectedDayでは、自身が選択状態かなどによって、背景色を変えるスタイルを当てています。

export const SelectedDay: React.FC<Props> = (props: Props) => {
  const theme = useTheme();
  const { dates = [], day } = props;
  const isSelected =
    (dates.length === 0
      ? false
      : dates.length === 1
      ? day.isSame(dates[0], 'date')
      : day.isSameOrAfter(dates[0], 'date') &&
        day.isSameOrBefore(dates[1], 'date'));
  return (
    <PickersDay
      {...props}
      selected={isSelected}
      aria-selected={isSelected}
      day={day}
      sx={{
        backgroundColor: isSelected ? theme.palette.primary.main : 'inherit',
        color: isSelected ? theme.palette.primary.contrastText : 'inherit',
        '&:hover': {
          backgroundColor: alpha(theme.palette.primary.light, 0.4),
          color: theme.palette.primary.contrastText,
        },
        '&.Mui-selected': isSelected
          ? {
              backgroundColor: theme.palette.primary.main,
              color: theme.palette.primary.contrastText,
            }
          : {
              backgroundColor: 'inherit',
              color: 'inherit',
            },
        '&.Mui-selected:hover': isSelected
          ? {
              backgroundColor: theme.palette.primary.light,
              color: theme.palette.primary.contrastText,
            }
          : {
              backgroundColor: 'inherit',
              color: 'inherit',
            },
      }}
    />
  );
};

aria-selectedを指定しているのは、PickersDayの挙動として、最後にクリックされた日付しかaria-selected=trueが指定できないためです。

コメント

タイトルとURLをコピーしました