Skip to content

Commit 5dfaf63

Browse files
fix(datetime): add dev warnings when setting out of bounds value (#25513)
1 parent 48fdba3 commit 5dfaf63

File tree

3 files changed

+50
-1
lines changed

3 files changed

+50
-1
lines changed

core/src/components/datetime/datetime.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { isRTL } from '../../utils/rtl';
1111
import { createColorClasses } from '../../utils/theme';
1212
import type { PickerColumnItem } from '../picker-column-internal/picker-column-internal-interfaces';
1313

14+
import { warnIfValueOutOfBounds } from './utils/comparison';
1415
import {
1516
generateMonths,
1617
generateTime,
@@ -326,6 +327,8 @@ export class Datetime implements ComponentInterface {
326327
*/
327328
const valueDateParts = parseDate(this.value);
328329
if (valueDateParts) {
330+
warnIfValueOutOfBounds(valueDateParts, this.minParts, this.maxParts);
331+
329332
const { month, day, year, hour, minute } = valueDateParts;
330333
const ampm = hour >= 12 ? 'pm' : 'am';
331334

@@ -1084,7 +1087,11 @@ export class Datetime implements ComponentInterface {
10841087
private processValue = (value?: string | null) => {
10851088
this.highlightActiveParts = !!value;
10861089
const valueToProcess = parseDate(value || getToday());
1087-
const { month, day, year, hour, minute, tzOffset } = clampDate(valueToProcess, this.minParts, this.maxParts);
1090+
1091+
const { minParts, maxParts } = this;
1092+
warnIfValueOutOfBounds(valueToProcess, minParts, maxParts);
1093+
1094+
const { month, day, year, hour, minute, tzOffset } = clampDate(valueToProcess, minParts, maxParts);
10881095

10891096
this.setWorkingParts({
10901097
month,

core/src/components/datetime/test/minmax/datetime.e2e.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { expect } from '@playwright/test';
2+
import type { E2EPage } from '@utils/test/playwright';
23
import { test } from '@utils/test/playwright';
34

45
test.describe('datetime: minmax', () => {
@@ -47,6 +48,7 @@ test.describe('datetime: minmax', () => {
4748
expect(nextButton).toBeDisabled();
4849
expect(prevButton).toBeEnabled();
4950
});
51+
5052
test('datetime: minmax months disabled', async ({ page }) => {
5153
await page.goto('/src/components/datetime/test/minmax');
5254
const calendarMonths = page.locator('ion-datetime#inside .calendar-month');
@@ -67,6 +69,7 @@ test.describe('datetime: minmax', () => {
6769
expect(navButtons.nth(0)).toHaveAttribute('disabled', '');
6870
expect(navButtons.nth(1)).toHaveAttribute('disabled', '');
6971
});
72+
7073
test('datetime: min including day should not disable month', async ({ page }) => {
7174
await page.goto('/src/components/datetime/test/minmax');
7275
await page.waitForSelector('.datetime-ready');
@@ -77,6 +80,7 @@ test.describe('datetime: minmax', () => {
7780
expect(calendarMonths.nth(1)).not.toHaveClass(/calendar-month-disabled/);
7881
expect(calendarMonths.nth(2)).not.toHaveClass(/calendar-month-disabled/);
7982
});
83+
8084
test.describe('when the datetime does not have a value', () => {
8185
test('all time values should be available for selection', async ({ page }) => {
8286
/**
@@ -105,4 +109,29 @@ test.describe('datetime: minmax', () => {
105109
expect(await minutes.count()).toBe(60);
106110
});
107111
});
112+
113+
test.describe('setting value outside bounds should show in-bounds month', () => {
114+
const testDisplayedMonth = async (page: E2EPage, content: string) => {
115+
await page.setContent(content);
116+
await page.waitForSelector('.datetime-ready');
117+
118+
const calendarMonthYear = page.locator('ion-datetime .calendar-month-year');
119+
expect(calendarMonthYear).toHaveText('June 2021');
120+
};
121+
122+
test('when min is defined', async ({ page }) => {
123+
await testDisplayedMonth(page, `<ion-datetime min="2021-06-01" value="2021-05-01"></ion-datetime>`);
124+
});
125+
126+
test('when max is defined', async ({ page }) => {
127+
await testDisplayedMonth(page, `<ion-datetime max="2021-06-30" value="2021-07-01"></ion-datetime>`);
128+
});
129+
130+
test('when both min and max are defined', async ({ page }) => {
131+
await testDisplayedMonth(
132+
page,
133+
`<ion-datetime min="2021-06-01" max="2021-06-30" value="2021-05-01"></ion-datetime>`
134+
);
135+
});
136+
});
108137
});

core/src/components/datetime/utils/comparison.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { printIonWarning } from '@utils/logging';
2+
13
import type { DatetimeParts } from '../datetime-interface';
24

35
/**
@@ -36,3 +38,14 @@ export const isAfter = (baseParts: DatetimeParts, compareParts: DatetimeParts) =
3638
baseParts.day > compareParts.day!)
3739
);
3840
};
41+
42+
export const warnIfValueOutOfBounds = (value: DatetimeParts, min: DatetimeParts, max: DatetimeParts) => {
43+
if ((min && isBefore(value, min)) || (max && isAfter(value, max))) {
44+
printIonWarning(
45+
'The value provided to ion-datetime is out of bounds.\n\n' +
46+
`Min: ${JSON.stringify(min)}\n` +
47+
`Max: ${JSON.stringify(max)}\n` +
48+
`Value: ${JSON.stringify(value)}`
49+
);
50+
}
51+
};

0 commit comments

Comments
 (0)