mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-19 19:57:22 +08:00
fix(datetime): prevent navigating to disabled months (#24421)
Resolves #24208, #24482
This commit is contained in:
@ -241,6 +241,13 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:host .calendar-body .calendar-month-disabled {
|
||||||
|
/**
|
||||||
|
* Disables swipe gesture snapping for scroll-snap containers
|
||||||
|
*/
|
||||||
|
scroll-snap-align: none;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hide scrollbars on Chrome and Safari
|
* Hide scrollbars on Chrome and Safari
|
||||||
*/
|
*/
|
||||||
|
@ -56,7 +56,10 @@ import {
|
|||||||
} from './utils/parse';
|
} from './utils/parse';
|
||||||
import {
|
import {
|
||||||
getCalendarDayState,
|
getCalendarDayState,
|
||||||
isDayDisabled
|
isDayDisabled,
|
||||||
|
isMonthDisabled,
|
||||||
|
isNextMonthDisabled,
|
||||||
|
isPrevMonthDisabled
|
||||||
} from './utils/state';
|
} from './utils/state';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -714,6 +717,15 @@ export class Datetime implements ComponentInterface {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { month, year, day } = refMonthFn(this.workingParts);
|
||||||
|
|
||||||
|
if (isMonthDisabled({ month, year, day: null }, {
|
||||||
|
minParts: this.minParts,
|
||||||
|
maxParts: this.maxParts
|
||||||
|
})) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On iOS, we need to set pointer-events: none
|
* On iOS, we need to set pointer-events: none
|
||||||
* when the user is almost done with the gesture
|
* when the user is almost done with the gesture
|
||||||
@ -724,7 +736,8 @@ export class Datetime implements ComponentInterface {
|
|||||||
*/
|
*/
|
||||||
if (mode === 'ios') {
|
if (mode === 'ios') {
|
||||||
const ratio = ev.intersectionRatio;
|
const ratio = ev.intersectionRatio;
|
||||||
const shouldDisable = Math.abs(ratio - 0.7) <= 0.1;
|
// `maxTouchPoints` will be 1 in device preview, but > 1 on device
|
||||||
|
const shouldDisable = Math.abs(ratio - 0.7) <= 0.1 && navigator.maxTouchPoints > 1;
|
||||||
|
|
||||||
if (shouldDisable) {
|
if (shouldDisable) {
|
||||||
calendarBodyRef.style.setProperty('pointer-events', 'none');
|
calendarBodyRef.style.setProperty('pointer-events', 'none');
|
||||||
@ -757,7 +770,6 @@ export class Datetime implements ComponentInterface {
|
|||||||
* if we did not do this.
|
* if we did not do this.
|
||||||
*/
|
*/
|
||||||
writeTask(() => {
|
writeTask(() => {
|
||||||
const { month, year, day } = refMonthFn(this.workingParts);
|
|
||||||
|
|
||||||
this.setWorkingParts({
|
this.setWorkingParts({
|
||||||
...this.workingParts,
|
...this.workingParts,
|
||||||
@ -766,9 +778,11 @@ export class Datetime implements ComponentInterface {
|
|||||||
year
|
year
|
||||||
});
|
});
|
||||||
|
|
||||||
calendarBodyRef.scrollLeft = workingMonth.clientWidth * (isRTL(this.el) ? -1 : 1);
|
raf(() => {
|
||||||
calendarBodyRef.style.removeProperty('overflow');
|
calendarBodyRef.scrollLeft = workingMonth.clientWidth * (isRTL(this.el) ? -1 : 1);
|
||||||
calendarBodyRef.style.removeProperty('pointer-events');
|
calendarBodyRef.style.removeProperty('overflow');
|
||||||
|
calendarBodyRef.style.removeProperty('pointer-events');
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Now that state has been updated
|
* Now that state has been updated
|
||||||
@ -781,6 +795,12 @@ export class Datetime implements ComponentInterface {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const threshold = mode === 'ios' &&
|
||||||
|
// tslint:disable-next-line
|
||||||
|
typeof navigator !== 'undefined' &&
|
||||||
|
navigator.maxTouchPoints > 1 ?
|
||||||
|
[0.7, 1] : 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listen on the first month to
|
* Listen on the first month to
|
||||||
* prepend a new month and on the last
|
* prepend a new month and on the last
|
||||||
@ -800,13 +820,13 @@ export class Datetime implements ComponentInterface {
|
|||||||
* something WebKit does.
|
* something WebKit does.
|
||||||
*/
|
*/
|
||||||
endIO = new IntersectionObserver(ev => ioCallback('end', ev), {
|
endIO = new IntersectionObserver(ev => ioCallback('end', ev), {
|
||||||
threshold: mode === 'ios' ? [0.7, 1] : 1,
|
threshold,
|
||||||
root: calendarBodyRef
|
root: calendarBodyRef
|
||||||
});
|
});
|
||||||
endIO.observe(endMonth);
|
endIO.observe(endMonth);
|
||||||
|
|
||||||
startIO = new IntersectionObserver(ev => ioCallback('start', ev), {
|
startIO = new IntersectionObserver(ev => ioCallback('start', ev), {
|
||||||
threshold: mode === 'ios' ? [0.7, 1] : 1,
|
threshold,
|
||||||
root: calendarBodyRef
|
root: calendarBodyRef
|
||||||
});
|
});
|
||||||
startIO.observe(startMonth);
|
startIO.observe(startMonth);
|
||||||
@ -963,9 +983,9 @@ export class Datetime implements ComponentInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentWillLoad() {
|
componentWillLoad() {
|
||||||
this.processValue(this.value);
|
|
||||||
this.processMinParts();
|
this.processMinParts();
|
||||||
this.processMaxParts();
|
this.processMaxParts();
|
||||||
|
this.processValue(this.value);
|
||||||
this.parsedHourValues = convertToArrayOfNumbers(this.hourValues);
|
this.parsedHourValues = convertToArrayOfNumbers(this.hourValues);
|
||||||
this.parsedMinuteValues = convertToArrayOfNumbers(this.minuteValues);
|
this.parsedMinuteValues = convertToArrayOfNumbers(this.minuteValues);
|
||||||
this.parsedMonthValues = convertToArrayOfNumbers(this.monthValues);
|
this.parsedMonthValues = convertToArrayOfNumbers(this.monthValues);
|
||||||
@ -1091,6 +1111,13 @@ export class Datetime implements ComponentInterface {
|
|||||||
items={months}
|
items={months}
|
||||||
value={workingParts.month}
|
value={workingParts.month}
|
||||||
onIonChange={(ev: CustomEvent) => {
|
onIonChange={(ev: CustomEvent) => {
|
||||||
|
// Due to a Safari 14 issue we need to destroy
|
||||||
|
// the intersection observer before we update state
|
||||||
|
// and trigger a re-render.
|
||||||
|
if (this.destroyCalendarIO) {
|
||||||
|
this.destroyCalendarIO();
|
||||||
|
}
|
||||||
|
|
||||||
this.setWorkingParts({
|
this.setWorkingParts({
|
||||||
...this.workingParts,
|
...this.workingParts,
|
||||||
month: ev.detail.value
|
month: ev.detail.value
|
||||||
@ -1103,6 +1130,10 @@ export class Datetime implements ComponentInterface {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We can re-attach the intersection observer after
|
||||||
|
// the working parts have been updated.
|
||||||
|
this.initializeCalendarIOListeners();
|
||||||
|
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
}}
|
}}
|
||||||
></ion-picker-column-internal>
|
></ion-picker-column-internal>
|
||||||
@ -1114,6 +1145,13 @@ export class Datetime implements ComponentInterface {
|
|||||||
items={years}
|
items={years}
|
||||||
value={workingParts.year}
|
value={workingParts.year}
|
||||||
onIonChange={(ev: CustomEvent) => {
|
onIonChange={(ev: CustomEvent) => {
|
||||||
|
// Due to a Safari 14 issue we need to destroy
|
||||||
|
// the intersection observer before we update state
|
||||||
|
// and trigger a re-render.
|
||||||
|
if (this.destroyCalendarIO) {
|
||||||
|
this.destroyCalendarIO();
|
||||||
|
}
|
||||||
|
|
||||||
this.setWorkingParts({
|
this.setWorkingParts({
|
||||||
...this.workingParts,
|
...this.workingParts,
|
||||||
year: ev.detail.value
|
year: ev.detail.value
|
||||||
@ -1126,6 +1164,10 @@ export class Datetime implements ComponentInterface {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We can re-attach the intersection observer after
|
||||||
|
// the working parts have been updated.
|
||||||
|
this.initializeCalendarIOListeners();
|
||||||
|
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
}}
|
}}
|
||||||
></ion-picker-column-internal>
|
></ion-picker-column-internal>
|
||||||
@ -1139,6 +1181,10 @@ export class Datetime implements ComponentInterface {
|
|||||||
private renderCalendarHeader(mode: Mode) {
|
private renderCalendarHeader(mode: Mode) {
|
||||||
const expandedIcon = mode === 'ios' ? chevronDown : caretUpSharp;
|
const expandedIcon = mode === 'ios' ? chevronDown : caretUpSharp;
|
||||||
const collapsedIcon = mode === 'ios' ? chevronForward : caretDownSharp;
|
const collapsedIcon = mode === 'ios' ? chevronForward : caretDownSharp;
|
||||||
|
|
||||||
|
const prevMonthDisabled = isPrevMonthDisabled(this.workingParts, this.minParts, this.maxParts);
|
||||||
|
const nextMonthDisabled = isNextMonthDisabled(this.workingParts, this.maxParts);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="calendar-header">
|
<div class="calendar-header">
|
||||||
<div class="calendar-action-buttons">
|
<div class="calendar-action-buttons">
|
||||||
@ -1152,10 +1198,14 @@ export class Datetime implements ComponentInterface {
|
|||||||
|
|
||||||
<div class="calendar-next-prev">
|
<div class="calendar-next-prev">
|
||||||
<ion-buttons>
|
<ion-buttons>
|
||||||
<ion-button onClick={() => this.prevMonth()}>
|
<ion-button
|
||||||
|
disabled={prevMonthDisabled}
|
||||||
|
onClick={() => this.prevMonth()}>
|
||||||
<ion-icon slot="icon-only" icon={chevronBack} lazy={false} flipRtl></ion-icon>
|
<ion-icon slot="icon-only" icon={chevronBack} lazy={false} flipRtl></ion-icon>
|
||||||
</ion-button>
|
</ion-button>
|
||||||
<ion-button onClick={() => this.nextMonth()}>
|
<ion-button
|
||||||
|
disabled={nextMonthDisabled}
|
||||||
|
onClick={() => this.nextMonth()}>
|
||||||
<ion-icon slot="icon-only" icon={chevronForward} lazy={false} flipRtl></ion-icon>
|
<ion-icon slot="icon-only" icon={chevronForward} lazy={false} flipRtl></ion-icon>
|
||||||
</ion-button>
|
</ion-button>
|
||||||
</ion-buttons>
|
</ion-buttons>
|
||||||
@ -1173,9 +1223,26 @@ export class Datetime implements ComponentInterface {
|
|||||||
private renderMonth(month: number, year: number) {
|
private renderMonth(month: number, year: number) {
|
||||||
const yearAllowed = this.parsedYearValues === undefined || this.parsedYearValues.includes(year);
|
const yearAllowed = this.parsedYearValues === undefined || this.parsedYearValues.includes(year);
|
||||||
const monthAllowed = this.parsedMonthValues === undefined || this.parsedMonthValues.includes(month);
|
const monthAllowed = this.parsedMonthValues === undefined || this.parsedMonthValues.includes(month);
|
||||||
const isMonthDisabled = !yearAllowed || !monthAllowed;
|
const isCalMonthDisabled = !yearAllowed || !monthAllowed;
|
||||||
|
const swipeDisabled = isMonthDisabled({
|
||||||
|
month,
|
||||||
|
year,
|
||||||
|
day: null
|
||||||
|
}, {
|
||||||
|
minParts: this.minParts,
|
||||||
|
maxParts: this.maxParts
|
||||||
|
});
|
||||||
|
// The working month should never have swipe disabled.
|
||||||
|
// Otherwise the CSS scroll snap will not work and the user
|
||||||
|
// can free-scroll the calendar.
|
||||||
|
const isWorkingMonth = this.workingParts.month === month && this.workingParts.year === year;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="calendar-month">
|
<div class={{
|
||||||
|
'calendar-month': true,
|
||||||
|
// Prevents scroll snap swipe gestures for months outside of the min/max bounds
|
||||||
|
'calendar-month-disabled': !isWorkingMonth && swipeDisabled
|
||||||
|
}}>
|
||||||
<div class="calendar-month-grid">
|
<div class="calendar-month-grid">
|
||||||
{getDaysOfMonth(month, year, this.firstDayOfWeek % 7).map((dateObject, index) => {
|
{getDaysOfMonth(month, year, this.firstDayOfWeek % 7).map((dateObject, index) => {
|
||||||
const { day, dayOfWeek } = dateObject;
|
const { day, dayOfWeek } = dateObject;
|
||||||
@ -1190,7 +1257,7 @@ export class Datetime implements ComponentInterface {
|
|||||||
data-year={year}
|
data-year={year}
|
||||||
data-index={index}
|
data-index={index}
|
||||||
data-day-of-week={dayOfWeek}
|
data-day-of-week={dayOfWeek}
|
||||||
disabled={isMonthDisabled || disabled}
|
disabled={isCalMonthDisabled || disabled}
|
||||||
class={{
|
class={{
|
||||||
'calendar-day-padding': day === null,
|
'calendar-day-padding': day === null,
|
||||||
'calendar-day': true,
|
'calendar-day': true,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { newE2EPage } from '@stencil/core/testing';
|
import { newE2EPage } from '@stencil/core/testing';
|
||||||
|
|
||||||
test('minmax', async () => {
|
test('datetime: minmax', async () => {
|
||||||
const page = await newE2EPage({
|
const page = await newE2EPage({
|
||||||
url: '/src/components/datetime/test/minmax?ionic:_testing=true'
|
url: '/src/components/datetime/test/minmax?ionic:_testing=true'
|
||||||
});
|
});
|
||||||
@ -20,3 +20,30 @@ test('minmax', async () => {
|
|||||||
expect(screenshotCompare).toMatchScreenshot();
|
expect(screenshotCompare).toMatchScreenshot();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('datetime: minmax months disabled', async () => {
|
||||||
|
const page = await newE2EPage({
|
||||||
|
url: '/src/components/datetime/test/minmax?ionic:_testing=true'
|
||||||
|
});
|
||||||
|
|
||||||
|
const calendarMonths = await page.findAll('ion-datetime#inside >>> .calendar-month');
|
||||||
|
|
||||||
|
await page.waitForChanges();
|
||||||
|
|
||||||
|
expect(calendarMonths[0]).not.toHaveClass('calendar-month-disabled');
|
||||||
|
expect(calendarMonths[1]).not.toHaveClass('calendar-month-disabled');
|
||||||
|
expect(calendarMonths[2]).toHaveClass('calendar-month-disabled');
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
test('datetime: minmax navigation disabled', async () => {
|
||||||
|
const page = await newE2EPage({
|
||||||
|
url: '/src/components/datetime/test/minmax?ionic:_testing=true'
|
||||||
|
});
|
||||||
|
|
||||||
|
const navButtons = await page.findAll('ion-datetime#outside >>> .calendar-next-prev ion-button');
|
||||||
|
|
||||||
|
expect(navButtons[0]).toHaveAttribute('disabled');
|
||||||
|
expect(navButtons[1]).toHaveAttribute('disabled');
|
||||||
|
|
||||||
|
});
|
||||||
|
@ -44,7 +44,7 @@
|
|||||||
<div class="grid">
|
<div class="grid">
|
||||||
<div class="grid-item">
|
<div class="grid-item">
|
||||||
<h2>Value inside Bounds</h2>
|
<h2>Value inside Bounds</h2>
|
||||||
<ion-datetime id="inside" min="2021-09" max="2021-10"></ion-datetime>
|
<ion-datetime id="inside" min="2021-09" max="2021-10" value="2021-10-01"></ion-datetime>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-item">
|
<div class="grid-item">
|
||||||
<h2>Value Outside Bounds</h2>
|
<h2>Value Outside Bounds</h2>
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import {
|
import {
|
||||||
getCalendarDayState,
|
getCalendarDayState,
|
||||||
isDayDisabled
|
isDayDisabled,
|
||||||
|
isNextMonthDisabled,
|
||||||
|
isPrevMonthDisabled
|
||||||
} from '../utils/state';
|
} from '../utils/state';
|
||||||
|
|
||||||
describe('getCalendarDayState()', () => {
|
describe('getCalendarDayState()', () => {
|
||||||
@ -73,3 +75,58 @@ describe('isDayDisabled()', () => {
|
|||||||
expect(isDayDisabled(refDate, undefined, { month: 5, day: 11, year: 2021 })).toEqual(true);
|
expect(isDayDisabled(refDate, undefined, { month: 5, day: 11, year: 2021 })).toEqual(true);
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('isPrevMonthDisabled()', () => {
|
||||||
|
|
||||||
|
it('should return true', () => {
|
||||||
|
// Date month is before min month, in the same year
|
||||||
|
expect(isPrevMonthDisabled({ month: 5, year: 2021, day: null }, { month: 6, year: 2021, day: null })).toEqual(true);
|
||||||
|
// Date month and year is the same as min month and year
|
||||||
|
expect(isPrevMonthDisabled({ month: 1, year: 2021, day: null }, { month: 1, year: 2021, day: null })).toEqual(true);
|
||||||
|
// Date year is the same as min year (month not provided)
|
||||||
|
expect(isPrevMonthDisabled({ month: 1, year: 2021, day: null }, { year: 2021, month: null, day: null })).toEqual(true);
|
||||||
|
// Date year is less than the min year (month not provided)
|
||||||
|
expect(isPrevMonthDisabled({ month: 5, year: 2021, day: null }, { year: 2022, month: null, day: null })).toEqual(true);
|
||||||
|
|
||||||
|
// Date is above the maximum bounds and the previous month does not does not fall within the
|
||||||
|
// min-max range.
|
||||||
|
expect(isPrevMonthDisabled({ month: 12, year: 2021, day: null }, { month: 9, year: 2021, day: null }, { month: 10, year: 2021, day: null })).toEqual(true);
|
||||||
|
|
||||||
|
// Date is above the maximum bounds and a year ahead of the max range. The previous month/year
|
||||||
|
// does not fall within the min-max range.
|
||||||
|
expect(isPrevMonthDisabled({ month: 1, year: 2022, day: null }, { month: 9, year: 2021, day: null }, { month: 10, year: 2021, day: null })).toEqual(true);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false', () => {
|
||||||
|
// No min range provided
|
||||||
|
expect(isPrevMonthDisabled({ month: 12, year: 2021, day: null })).toEqual(false);
|
||||||
|
// Date year is the same as min year,
|
||||||
|
// but can navigate to a previous month without reducing the year.
|
||||||
|
expect(isPrevMonthDisabled({ month: 12, year: 2021, day: null }, { year: 2021, month: null, day: null })).toEqual(false);
|
||||||
|
expect(isPrevMonthDisabled({ month: 2, year: 2021, day: null }, { year: 2021, month: null, day: null })).toEqual(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('isNextMonthDisabled()', () => {
|
||||||
|
|
||||||
|
it('should return true', () => {
|
||||||
|
// Date month is the same as max month (in the same year)
|
||||||
|
expect(isNextMonthDisabled({ month: 10, year: 2021, day: null }, { month: 10, year: 2021, day: null })).toEqual(true);
|
||||||
|
// Date month is after the max month (in the same year)
|
||||||
|
expect(isNextMonthDisabled({ month: 10, year: 2021, day: null }, { month: 9, year: 2021, day: null })).toEqual(true);
|
||||||
|
// Date year is after the max month and year
|
||||||
|
expect(isNextMonthDisabled({ month: 10, year: 2022, day: null }, { month: 12, year: 2021, day: null })).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false', () => {
|
||||||
|
// No max range provided
|
||||||
|
expect(isNextMonthDisabled({ month: 10, year: 2021, day: null })).toBe(false);
|
||||||
|
// Date month is before max month and is the previous month,
|
||||||
|
// so that navigating the next month would re-enter the max range
|
||||||
|
expect(isNextMonthDisabled({ month: 10, year: 2021, day: null }, { month: 11, year: 2021, day: null })).toEqual(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ import { DatetimeParts } from '../datetime-interface';
|
|||||||
|
|
||||||
import { isAfter, isBefore, isSameDay } from './comparison';
|
import { isAfter, isBefore, isSameDay } from './comparison';
|
||||||
import { generateDayAriaLabel } from './format';
|
import { generateDayAriaLabel } from './format';
|
||||||
|
import { getNextMonth, getPreviousMonth } from './manipulation';
|
||||||
|
|
||||||
export const isYearDisabled = (refYear: number, minParts?: DatetimeParts, maxParts?: DatetimeParts) => {
|
export const isYearDisabled = (refYear: number, minParts?: DatetimeParts, maxParts?: DatetimeParts) => {
|
||||||
if (minParts && minParts.year > refYear) {
|
if (minParts && minParts.year > refYear) {
|
||||||
@ -102,3 +103,52 @@ export const getCalendarDayState = (
|
|||||||
ariaLabel: generateDayAriaLabel(locale, isToday, refParts)
|
ariaLabel: generateDayAriaLabel(locale, isToday, refParts)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns `true` if the month is disabled given the
|
||||||
|
* current date value and min/max date constraints.
|
||||||
|
*/
|
||||||
|
export const isMonthDisabled = (refParts: DatetimeParts, { minParts, maxParts }: {
|
||||||
|
minParts?: DatetimeParts,
|
||||||
|
maxParts?: DatetimeParts
|
||||||
|
}) => {
|
||||||
|
// If the year is disabled then the month is disabled.
|
||||||
|
if (isYearDisabled(refParts.year, minParts, maxParts)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// If the date value is before the min date, then the month is disabled.
|
||||||
|
// If the date value is after the max date, then the month is disabled.
|
||||||
|
if (minParts && isBefore(refParts, minParts) || maxParts && isAfter(refParts, maxParts)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a working date, an optional minimum date range,
|
||||||
|
* and an optional maximum date range; determine if the
|
||||||
|
* previous navigation button is disabled.
|
||||||
|
*/
|
||||||
|
export const isPrevMonthDisabled = (
|
||||||
|
refParts: DatetimeParts,
|
||||||
|
minParts?: DatetimeParts,
|
||||||
|
maxParts?: DatetimeParts) => {
|
||||||
|
const prevMonth = getPreviousMonth(refParts);
|
||||||
|
return isMonthDisabled(prevMonth, {
|
||||||
|
minParts,
|
||||||
|
maxParts
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a working date and a maximum date range,
|
||||||
|
* determine if the next navigation button is disabled.
|
||||||
|
*/
|
||||||
|
export const isNextMonthDisabled = (
|
||||||
|
refParts: DatetimeParts,
|
||||||
|
maxParts?: DatetimeParts) => {
|
||||||
|
const nextMonth = getNextMonth(refParts);
|
||||||
|
return isMonthDisabled(nextMonth, {
|
||||||
|
maxParts
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user