date-fns#subMonths JavaScript Examples
The following examples show how to use
date-fns#subMonths.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: CalendarNavigation.js From react-nice-dates with MIT License | 6 votes |
export default function CalendarNavigation({ locale, month, minimumDate, maximumDate, onMonthChange }) {
const handlePrevious = event => {
onMonthChange(startOfMonth(subMonths(month, 1)))
event.preventDefault()
}
const handleNext = event => {
onMonthChange(startOfMonth(addMonths(month, 1)))
event.preventDefault()
}
return (
<div className='nice-dates-navigation'>
<a
className={classNames('nice-dates-navigation_previous', {
'-disabled': isSameMonth(month, minimumDate)
})}
onClick={handlePrevious}
onTouchEnd={handlePrevious}
/>
<span className='nice-dates-navigation_current'>
{format(month, getYear(month) === getYear(new Date()) ? 'LLLL' : 'LLLL yyyy', { locale })}
</span>
<a
className={classNames('nice-dates-navigation_next', {
'-disabled': isSameMonth(month, maximumDate)
})}
onClick={handleNext}
onTouchEnd={handleNext}
/>
</div>
)
}
Example #2
Source File: DatePicker.test.js From react-nice-dates with MIT License | 5 votes |
describe('DatePicker', () => {
it('should render', () => {
const { getAllByText } = render(
<DatePicker onDateChange={() => {}} locale={locale}>
{({ inputProps, focused }) => (
<input aria-label='input' className={classNames({ '-focused': focused })} {...inputProps} />
)}
</DatePicker>
)
expect(getAllByText('1').length).toBeGreaterThan(0)
})
it('should open and close', () => {
const { container, getAllByText, getByLabelText } = render(
<DatePicker onDateChange={() => {}} locale={locale}>
{({ inputProps, focused }) => (
<input aria-label='input' {...inputProps} className={focused ? '-focused' : undefined} />
)}
</DatePicker>
)
const input = getByLabelText('input')
const popover = container.querySelector('.nice-dates-popover')
expect(popover).not.toHaveClass('-open')
expect(input).not.toHaveClass('-focused')
// Should open on focus
fireEvent.focus(input)
expect(popover).toHaveClass('-open')
expect(input).toHaveClass('-focused')
// Should close on outside click
fireEvent.click(document)
expect(popover).not.toHaveClass('-open')
expect(input).not.toHaveClass('-focused')
// Should close on date selection
fireEvent.focus(input)
expect(popover).toHaveClass('-open')
fireEvent.click(getAllByText('1')[0])
expect(popover).not.toHaveClass('-open')
})
it('should display pre-selected date’s month on initial render', () => {
const pastDate = subMonths(new Date(), 1)
const monthName = format(pastDate, 'LLLL', { locale })
const { getByText } = render(
<DatePicker locale={locale} date={pastDate}>
{() => {}}
</DatePicker>
)
expect(getByText(monthName, { exact: false })).toBeInTheDocument()
})
})
Example #3
Source File: DatePickerCalendar.test.js From react-nice-dates with MIT License | 5 votes |
describe('DatePickerCalendar', () => {
it('should render', () => {
const { getAllByText } = render(<DatePickerCalendar locale={locale} />)
expect(getAllByText('1').length).toBeGreaterThan(0)
})
it('should call onDateChange on date selection', () => {
const handleDateChange = jest.fn()
const { getAllByText } = render(<DatePickerCalendar locale={locale} onDateChange={handleDateChange} />)
fireEvent.click(getAllByText('1')[0])
expect(handleDateChange).toHaveBeenCalledTimes(1)
})
it('should display selected date', () => {
const { getAllByText } = render(<DatePickerCalendar locale={locale} date={startOfMonth(new Date())} />)
expect(getAllByText('1')[0].parentElement).toHaveClass('-selected')
})
it('should display pre-selected date’s month on initial render', () => {
const pastDate = subMonths(new Date(), 1)
const monthName = format(pastDate, 'LLLL', { locale })
const { getByText } = render(<DatePickerCalendar locale={locale} date={pastDate} />)
expect(getByText(monthName, { exact: false })).toBeInTheDocument()
})
it('should maintain the selected date’s time when selecting a new date', () => {
const handleDateChange = jest.fn()
const date = new Date(2020, 1, 24, 18, 30)
const { getByText } = render(<DatePickerCalendar locale={locale} date={date} onDateChange={handleDateChange} />)
fireEvent.click(getByText('25'))
expect(handleDateChange).toHaveBeenCalledWith(new Date(2020, 1, 25, 18, 30))
})
})
Example #4
Source File: useGrid.js From react-nice-dates with MIT License | 4 votes |
export default function useGrid({ locale, month: currentMonth, onMonthChange, transitionDuration, touchDragEnabled }) {
const timeoutRef = useRef()
const containerElementRef = useRef()
const initialDragPositionRef = useRef(0)
const [state, dispatch] = useReducer(reducer, createInitialState(currentMonth, locale))
const { startDate, endDate, cellHeight, lastCurrentMonth, offset, origin, transition, isWide } = state
useLayoutEffect(() => {
const notDragging = !initialDragPositionRef.current
if (!isSameMonth(lastCurrentMonth, currentMonth) && notDragging) {
const containerElement = containerElementRef.current
containerElement.classList.add('-transition')
clearTimeout(timeoutRef.current)
if (Math.abs(differenceInCalendarMonths(currentMonth, lastCurrentMonth)) <= 3) {
dispatch({ type: 'transitionToCurrentMonth', currentMonth })
timeoutRef.current = setTimeout(() => {
dispatch({ type: 'reset', currentMonth })
}, transitionDuration)
} else {
dispatch({ type: 'reset', currentMonth })
}
}
}, [currentMonth]) // eslint-disable-line react-hooks/exhaustive-deps
useLayoutEffect(() => {
if (!touchDragEnabled) {
return
}
const containerElement = containerElementRef.current
const gridHeight = cellHeight * 6
const halfGridHeight = gridHeight / 2
if (containerElement) {
const handleDragStart = event => {
clearTimeout(timeoutRef.current)
const computedOffset = Number(window.getComputedStyle(containerElement).transform.match(/([-+]?[\d.]+)/g)[5])
let currentMonthPosition = 0
if (!initialDragPositionRef.current) {
const newStartDate = getStartDate(subMonths(currentMonth, 1), locale)
currentMonthPosition = (rowsBetweenDates(newStartDate, currentMonth, locale) - 1) * cellHeight
dispatch({ type: 'setRange', startDate: newStartDate, endDate: getEndDate(addMonths(currentMonth, 1), locale) })
}
containerElement.style.transform = `translate3d(0, ${computedOffset || -currentMonthPosition}px, 0)`
containerElement.classList.remove('-transition')
containerElement.classList.add('-moving')
initialDragPositionRef.current = event.touches[0].clientY + (-computedOffset || currentMonthPosition)
}
const handleDrag = event => {
const initialDragPosition = initialDragPositionRef.current
const dragOffset = event.touches[0].clientY - initialDragPosition
const previousMonth = subMonths(currentMonth, 1)
const previousMonthPosition = (rowsBetweenDates(startDate, previousMonth, locale) - 1) * cellHeight
const currentMonthPosition = (rowsBetweenDates(startDate, currentMonth, locale) - 1) * cellHeight
const nextMonth = addMonths(currentMonth, 1)
const nextMonthPosition = (rowsBetweenDates(startDate, nextMonth, locale) - 1) * cellHeight
if (dragOffset < 0) {
if (Math.abs(dragOffset) > currentMonthPosition && isBefore(endDate, addMonths(currentMonth, 2))) {
dispatch({ type: 'setEndDate', value: getEndDate(nextMonth, locale) })
}
} else if (dragOffset > 0) {
const newStartDate = getStartDate(previousMonth, locale)
const newCurrentMonthPosition = (rowsBetweenDates(newStartDate, currentMonth, locale) - 1) * cellHeight
initialDragPositionRef.current += newCurrentMonthPosition
dispatch({ type: 'setStartDate', value: newStartDate })
}
const shouldChangeToNextMonth = Math.abs(dragOffset) > nextMonthPosition - halfGridHeight
const shouldChangeToPreviousMonth =
Math.abs(dragOffset) > previousMonthPosition - halfGridHeight &&
Math.abs(dragOffset) < currentMonthPosition - halfGridHeight
if (shouldChangeToNextMonth) {
onMonthChange(nextMonth)
} else if (shouldChangeToPreviousMonth) {
onMonthChange(previousMonth)
}
containerElement.style.transform = `translate3d(0, ${dragOffset}px, 0)`
event.preventDefault()
}
const handleDragEnd = event => {
const currentMonthPosition = (rowsBetweenDates(startDate, currentMonth, locale) - 1) * cellHeight
containerElement.style.transform = `translate3d(0, ${-currentMonthPosition}px, 0)`
containerElement.classList.add('-transition')
containerElement.classList.remove('-moving')
timeoutRef.current = setTimeout(() => {
initialDragPositionRef.current = 0
containerElement.style.transform = 'translate3d(0, 0, 0)'
containerElement.classList.remove('-transition')
dispatch({ type: 'reset', currentMonth: currentMonth })
}, transitionDuration)
if (Math.abs(initialDragPositionRef.current - currentMonthPosition - event.changedTouches[0].clientY) > 10) {
event.preventDefault()
event.stopPropagation()
}
}
containerElement.addEventListener('touchstart', handleDragStart)
containerElement.addEventListener('touchmove', handleDrag)
containerElement.addEventListener('touchend', handleDragEnd)
return () => {
containerElement.removeEventListener('touchstart', handleDragStart)
containerElement.removeEventListener('touchmove', handleDrag)
containerElement.removeEventListener('touchend', handleDragEnd)
}
}
})
useEffect(() => {
const handleResize = () => {
const containerElement = containerElementRef.current
const containerWidth = containerElement.offsetWidth
const cellWidth = containerWidth / 7
let newCellHeight = 1
let wide = false
if (cellWidth > 60) {
newCellHeight += Math.round(cellWidth * 0.75)
wide = true
} else {
newCellHeight += Math.round(cellWidth)
}
dispatch({ type: 'setIsWide', value: wide })
dispatch({ type: 'setCellHeight', value: newCellHeight })
}
window.addEventListener('resize', handleResize)
handleResize()
return () => {
window.removeEventListener('resize', handleResize)
}
}, [])
return {
startDate,
endDate,
cellHeight,
containerElementRef,
offset,
origin,
transition,
isWide
}
}
Example #5
Source File: DateRangePicker.test.js From react-nice-dates with MIT License | 4 votes |
describe('DateRangePicker', () => {
it('should render', () => {
const { getAllByText } = render(
<DateRangePicker locale={locale}>
{({ startDateInputProps, endDateInputProps, focus }) => (
<div className='date-range'>
<input
aria-label={START_DATE}
className={classNames({ '-focused': focus === START_DATE })}
{...startDateInputProps}
/>
<input
aria-label={END_DATE}
className={classNames({ '-focused': focus === END_DATE })}
{...endDateInputProps}
/>
</div>
)}
</DateRangePicker>
)
expect(getAllByText('1').length).toBeGreaterThan(0)
})
it('should open and close popup', () => {
const { container, getByLabelText } = render(
<DateRangePicker locale={locale}>
{({ startDateInputProps, endDateInputProps, focus }) => (
<div className='date-range'>
<input
aria-label={START_DATE}
className={classNames({ '-focused': focus === START_DATE })}
{...startDateInputProps}
/>
<input className={classNames({ '-focused': focus === END_DATE })} {...endDateInputProps} />
</div>
)}
</DateRangePicker>
)
const startDateInput = getByLabelText(START_DATE)
const popover = container.querySelector('.nice-dates-popover')
expect(popover).not.toHaveClass('-open')
expect(startDateInput).not.toHaveClass('-focused')
// Should open on focus
fireEvent.focus(startDateInput)
expect(popover).toHaveClass('-open')
expect(startDateInput).toHaveClass('-focused')
// Should close on outside click
fireEvent.click(document)
expect(popover).not.toHaveClass('-open')
expect(startDateInput).not.toHaveClass('-focused')
})
it('should display pre-selected start date’s month on initial render', () => {
const today = new Date()
const pastDate = subMonths(today, 1)
const monthName = format(pastDate, 'LLLL', { locale })
const { getByText } = render(
<DateRangePicker locale={locale} startDate={pastDate} endDate={today}>
{() => {}}
</DateRangePicker>
)
expect(getByText(monthName, { exact: false })).toBeInTheDocument()
})
it('should display pre-selected end date’s month on initial render', () => {
const pastDate = subMonths(new Date(), 1)
const monthName = format(pastDate, 'LLLL', { locale })
const { getByText } = render(
<DateRangePicker locale={locale} endDate={pastDate}>
{() => {}}
</DateRangePicker>
)
expect(getByText(monthName, { exact: false })).toBeInTheDocument()
})
})
Example #6
Source File: DateRangePickerCalendar.test.js From react-nice-dates with MIT License | 4 votes |
describe('DateRangePickerCalendar', () => {
it('should render', () => {
const { getAllByText } = render(
<DateRangePickerCalendar
locale={locale}
onStartDateChange={() => {}}
onEndDateChange={() => {}}
onFocusChange={() => {}}
/>
)
expect(getAllByText('1').length).toBeGreaterThan(0)
})
it('should call callbacks on date selection', () => {
const handleStartDateChange = jest.fn()
const handleEndDateChange = jest.fn()
const handleFocusChange = jest.fn()
const { getAllByText, rerender } = render(
<DateRangePickerCalendar
locale={locale}
focus={START_DATE}
onStartDateChange={handleStartDateChange}
onEndDateChange={handleEndDateChange}
onFocusChange={handleFocusChange}
/>
)
fireEvent.click(getAllByText('1')[0])
expect(handleStartDateChange).toHaveBeenCalledTimes(1)
expect(handleEndDateChange).toHaveBeenCalledTimes(0)
expect(handleFocusChange).toHaveBeenCalledWith(END_DATE)
rerender(
<DateRangePickerCalendar
locale={locale}
focus={END_DATE}
startDate={startOfMonth(new Date())}
onStartDateChange={handleStartDateChange}
onEndDateChange={handleEndDateChange}
onFocusChange={handleFocusChange}
/>
)
fireEvent.click(getAllByText('2')[0])
expect(handleStartDateChange).toHaveBeenCalledTimes(1)
expect(handleEndDateChange).toHaveBeenCalledTimes(1)
expect(handleFocusChange).toHaveBeenCalledWith(null)
})
it('should display selected date range', () => {
const startDate = startOfMonth(new Date())
const endDate = addDays(startDate, 2)
const { container, getAllByText, rerender } = render(
<DateRangePickerCalendar locale={locale} startDate={startDate} />
)
expect(getAllByText('1')[0].parentElement).toHaveClass('-selected')
expect(container.querySelectorAll('.-selected').length).toBe(1)
rerender(<DateRangePickerCalendar locale={locale} startDate={startDate} endDate={endDate} />)
expect(getAllByText('1')[0].parentElement).toHaveClass('-selected -selected-start')
expect(getAllByText('2')[0].parentElement).toHaveClass('-selected -selected-middle')
expect(getAllByText('3')[0].parentElement).toHaveClass('-selected -selected-end')
expect(container.querySelectorAll('.-selected').length).toBe(3)
})
it('should display pre-selected start date’s month on initial render', () => {
const today = new Date()
const pastDate = subMonths(today, 1)
const monthName = format(pastDate, 'LLLL', { locale })
const { getByText } = render(<DateRangePickerCalendar locale={locale} startDate={pastDate} endDate={today} />)
expect(getByText(monthName, { exact: false })).toBeInTheDocument()
})
it('should display pre-selected end date’s month on initial render', () => {
const pastDate = subMonths(new Date(), 1)
const monthName = format(pastDate, 'LLLL', { locale })
const { getByText } = render(<DateRangePickerCalendar locale={locale} endDate={pastDate} />)
expect(getByText(monthName, { exact: false })).toBeInTheDocument()
})
it('should maintain the selected start date’s time when selecting a new date', () => {
const handleStartDateChange = jest.fn()
const { getByText } = render(
<DateRangePickerCalendar
locale={locale}
focus={START_DATE}
startDate={new Date(2020, 1, 24, 18, 30)}
onStartDateChange={handleStartDateChange}
/>
)
fireEvent.click(getByText('25'))
expect(handleStartDateChange).toHaveBeenCalledWith(new Date(2020, 1, 25, 18, 30))
})
it('should maintain the selected end date’s time when selecting a new date', () => {
const handleEndDateChange = jest.fn()
const { getByText } = render(
<DateRangePickerCalendar
locale={locale}
focus={END_DATE}
endDate={new Date(2020, 1, 24, 18, 30)}
onEndDateChange={handleEndDateChange}
/>
)
fireEvent.click(getByText('25'))
expect(handleEndDateChange).toHaveBeenCalledWith(new Date(2020, 1, 25, 18, 30))
})
it('should allow same day selection by default (when minimumLength is 0)', () => {
const startDate = startOfDay(set(new Date(), { date: 13 }))
const { getByText } = render(<DateRangePickerCalendar locale={locale} focus={END_DATE} startDate={startDate} />)
expect(getByText('13').parentElement).not.toHaveClass('-disabled')
})
it('should disable dates before the start date when selecting an end date with no existing end date selected', () => {
const startDate = startOfDay(set(new Date(), { date: 18 }))
const { getByText } = render(<DateRangePickerCalendar locale={locale} focus={END_DATE} startDate={startDate} />)
expect(getByText('16').parentElement).toHaveClass('-disabled')
expect(getByText('17').parentElement).toHaveClass('-disabled')
expect(getByText('18').parentElement).not.toHaveClass('-disabled')
})
it('should disable dates after the end date when selecting a start date with no existing start date selected', () => {
const endDate = startOfDay(set(new Date(), { date: 13 }))
const { getByText } = render(<DateRangePickerCalendar locale={locale} focus={START_DATE} endDate={endDate} />)
expect(getByText('13').parentElement).not.toHaveClass('-disabled')
expect(getByText('14').parentElement).toHaveClass('-disabled')
expect(getByText('15').parentElement).toHaveClass('-disabled')
})
it('should disable in-between dates when minimumLength is set', () => {
const startDate = startOfDay(set(new Date(), { date: 18 }))
const { getByText } = render(
<DateRangePickerCalendar locale={locale} focus={END_DATE} startDate={startDate} minimumLength={3} />
)
expect(getByText('18').parentElement).toHaveClass('-disabled')
expect(getByText('19').parentElement).toHaveClass('-disabled')
expect(getByText('20').parentElement).toHaveClass('-disabled')
expect(getByText('21').parentElement).not.toHaveClass('-disabled')
})
it('should disable in-between dates when selecting start date and minimumLength is set', () => {
const endDate = startOfDay(set(new Date(), { date: 18 }))
const { getByText } = render(
<DateRangePickerCalendar locale={locale} focus={START_DATE} endDate={endDate} minimumLength={3} />
)
expect(getByText('18').parentElement).toHaveClass('-disabled')
expect(getByText('17').parentElement).toHaveClass('-disabled')
expect(getByText('16').parentElement).toHaveClass('-disabled')
expect(getByText('15').parentElement).not.toHaveClass('-disabled')
})
it('should disable later dates when maximumLength is set', () => {
const startDate = startOfDay(set(new Date(), { date: 13 }))
const { getByText } = render(
<DateRangePickerCalendar locale={locale} focus={END_DATE} startDate={startDate} maximumLength={3} />
)
expect(getByText('13').parentElement).not.toHaveClass('-disabled')
expect(getByText('14').parentElement).not.toHaveClass('-disabled')
expect(getByText('15').parentElement).not.toHaveClass('-disabled')
expect(getByText('16').parentElement).not.toHaveClass('-disabled')
expect(getByText('17').parentElement).toHaveClass('-disabled')
})
it('should disable earlier dates when selecting start date and maximumLength is set', () => {
const endDate = startOfDay(set(new Date(), { date: 18 }))
const { getByText } = render(
<DateRangePickerCalendar locale={locale} focus={START_DATE} endDate={endDate} maximumLength={3} />
)
expect(getByText('18').parentElement).not.toHaveClass('-disabled')
expect(getByText('17').parentElement).not.toHaveClass('-disabled')
expect(getByText('16').parentElement).not.toHaveClass('-disabled')
expect(getByText('15').parentElement).not.toHaveClass('-disabled')
expect(getByText('14').parentElement).toHaveClass('-disabled')
})
})