hypeserver / react-date-range

A React component for choosing dates and date ranges.
MIT License
2.58k stars 669 forks source link

Disable Months in Drop-Down outside the minDate/maxDate range #269

Open ltond opened 5 years ago

ltond commented 5 years ago

Subject of the issue

If I set the minDate option to yyyy-mm-dd, then years before yyyy are not shown in the drop-down, but months before mm are shown. The scroll arrows prevent you from going any earlier than the minimum month. Clicking one of the earlier months in the drop-down will go to the minimum month.

The same applies to maxDate, for months after mm.

[BUG] Bug Reproduce Steps

For example, set minDate to 2018-06-01, then years before 2018 are not shown, but months Jan-May are shown: image

[BUG] Expected behaviour

Either do not show those months in the picker, show them but render them disabled, or allow them to be clicked but display that month with all days disabled.

To be consistent with the scroll arrows, either do not show or show as disabled.

Environment

Package Version:1.0.0-beta React version:16.2.0 Node version: Browser: Chrome 71

scriptex commented 1 month ago

I know this issue is pretty old but it seems there is no built-in API to manipulate the month picker. While you can play with minDate and maxDate to show/hide years in the year picker, this is not possible for the month picker. However... We can just fallback to using regular DOM and dirty HTML elements manipulation. Here is how I solved this:

// ... imports and stuff

const today = new Date()

/**
 * React Date Range does not expose an API which
 * allows for disabling of months in the month picker.
 * So we just do it the dirty way using DOM 🤷
 */
const disableNextMonths = (container: HTMLDivElement | null) => {
  if (!container) {
    return
  }

  const currentYear = getYear(today) // Using date-fns but can be done using any library or just JS Date
  const selectedYear = container.querySelector<HTMLOptionElement>('.rdrYearPicker select')?.value

  const months = container.querySelectorAll<HTMLOptionElement>('.rdrMonthPicker option')

  if (currentYear !== Number(selectedYear)) {
    months.forEach((month) => {
      month.disabled = false
    })

    return
  }

  const currentMonth = getMonth(today)

  months.forEach((month, index) => {
    month.disabled = index > currentMonth
  })
}

export const DateRangePicker: FC<Props> = (props) => {
  // ... hooks, logic and stuff

  const dateRangePickerContainer = useRef<HTMLDivElement | null>(null)

  disableNextMonths(dateRangePickerContainer.current)

  return (
    <div ref={dateRangePickerContainer}>
      <DateRange {...props} />
    </div>
  )
}
scriptex commented 1 month ago

There is also a similar (if not the same) issue in #567