mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-19 19:57:22 +08:00
fix(datetime): add dev warnings when setting out of bounds value (#25513)
This commit is contained in:
@ -11,6 +11,7 @@ import { isRTL } from '../../utils/rtl';
|
|||||||
import { createColorClasses } from '../../utils/theme';
|
import { createColorClasses } from '../../utils/theme';
|
||||||
import type { PickerColumnItem } from '../picker-column-internal/picker-column-internal-interfaces';
|
import type { PickerColumnItem } from '../picker-column-internal/picker-column-internal-interfaces';
|
||||||
|
|
||||||
|
import { warnIfValueOutOfBounds } from './utils/comparison';
|
||||||
import {
|
import {
|
||||||
generateMonths,
|
generateMonths,
|
||||||
generateTime,
|
generateTime,
|
||||||
@ -326,6 +327,8 @@ export class Datetime implements ComponentInterface {
|
|||||||
*/
|
*/
|
||||||
const valueDateParts = parseDate(this.value);
|
const valueDateParts = parseDate(this.value);
|
||||||
if (valueDateParts) {
|
if (valueDateParts) {
|
||||||
|
warnIfValueOutOfBounds(valueDateParts, this.minParts, this.maxParts);
|
||||||
|
|
||||||
const { month, day, year, hour, minute } = valueDateParts;
|
const { month, day, year, hour, minute } = valueDateParts;
|
||||||
const ampm = hour >= 12 ? 'pm' : 'am';
|
const ampm = hour >= 12 ? 'pm' : 'am';
|
||||||
|
|
||||||
@ -1084,7 +1087,11 @@ export class Datetime implements ComponentInterface {
|
|||||||
private processValue = (value?: string | null) => {
|
private processValue = (value?: string | null) => {
|
||||||
this.highlightActiveParts = !!value;
|
this.highlightActiveParts = !!value;
|
||||||
const valueToProcess = parseDate(value || getToday());
|
const valueToProcess = parseDate(value || getToday());
|
||||||
const { month, day, year, hour, minute, tzOffset } = clampDate(valueToProcess, this.minParts, this.maxParts);
|
|
||||||
|
const { minParts, maxParts } = this;
|
||||||
|
warnIfValueOutOfBounds(valueToProcess, minParts, maxParts);
|
||||||
|
|
||||||
|
const { month, day, year, hour, minute, tzOffset } = clampDate(valueToProcess, minParts, maxParts);
|
||||||
|
|
||||||
this.setWorkingParts({
|
this.setWorkingParts({
|
||||||
month,
|
month,
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { expect } from '@playwright/test';
|
import { expect } from '@playwright/test';
|
||||||
|
import type { E2EPage } from '@utils/test/playwright';
|
||||||
import { test } from '@utils/test/playwright';
|
import { test } from '@utils/test/playwright';
|
||||||
|
|
||||||
test.describe('datetime: minmax', () => {
|
test.describe('datetime: minmax', () => {
|
||||||
@ -47,6 +48,7 @@ test.describe('datetime: minmax', () => {
|
|||||||
expect(nextButton).toBeDisabled();
|
expect(nextButton).toBeDisabled();
|
||||||
expect(prevButton).toBeEnabled();
|
expect(prevButton).toBeEnabled();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('datetime: minmax months disabled', async ({ page }) => {
|
test('datetime: minmax months disabled', async ({ page }) => {
|
||||||
await page.goto('/src/components/datetime/test/minmax');
|
await page.goto('/src/components/datetime/test/minmax');
|
||||||
const calendarMonths = page.locator('ion-datetime#inside .calendar-month');
|
const calendarMonths = page.locator('ion-datetime#inside .calendar-month');
|
||||||
@ -67,6 +69,7 @@ test.describe('datetime: minmax', () => {
|
|||||||
expect(navButtons.nth(0)).toHaveAttribute('disabled', '');
|
expect(navButtons.nth(0)).toHaveAttribute('disabled', '');
|
||||||
expect(navButtons.nth(1)).toHaveAttribute('disabled', '');
|
expect(navButtons.nth(1)).toHaveAttribute('disabled', '');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('datetime: min including day should not disable month', async ({ page }) => {
|
test('datetime: min including day should not disable month', async ({ page }) => {
|
||||||
await page.goto('/src/components/datetime/test/minmax');
|
await page.goto('/src/components/datetime/test/minmax');
|
||||||
await page.waitForSelector('.datetime-ready');
|
await page.waitForSelector('.datetime-ready');
|
||||||
@ -77,6 +80,7 @@ test.describe('datetime: minmax', () => {
|
|||||||
expect(calendarMonths.nth(1)).not.toHaveClass(/calendar-month-disabled/);
|
expect(calendarMonths.nth(1)).not.toHaveClass(/calendar-month-disabled/);
|
||||||
expect(calendarMonths.nth(2)).not.toHaveClass(/calendar-month-disabled/);
|
expect(calendarMonths.nth(2)).not.toHaveClass(/calendar-month-disabled/);
|
||||||
});
|
});
|
||||||
|
|
||||||
test.describe('when the datetime does not have a value', () => {
|
test.describe('when the datetime does not have a value', () => {
|
||||||
test('all time values should be available for selection', async ({ page }) => {
|
test('all time values should be available for selection', async ({ page }) => {
|
||||||
/**
|
/**
|
||||||
@ -105,4 +109,29 @@ test.describe('datetime: minmax', () => {
|
|||||||
expect(await minutes.count()).toBe(60);
|
expect(await minutes.count()).toBe(60);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test.describe('setting value outside bounds should show in-bounds month', () => {
|
||||||
|
const testDisplayedMonth = async (page: E2EPage, content: string) => {
|
||||||
|
await page.setContent(content);
|
||||||
|
await page.waitForSelector('.datetime-ready');
|
||||||
|
|
||||||
|
const calendarMonthYear = page.locator('ion-datetime .calendar-month-year');
|
||||||
|
expect(calendarMonthYear).toHaveText('June 2021');
|
||||||
|
};
|
||||||
|
|
||||||
|
test('when min is defined', async ({ page }) => {
|
||||||
|
await testDisplayedMonth(page, `<ion-datetime min="2021-06-01" value="2021-05-01"></ion-datetime>`);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('when max is defined', async ({ page }) => {
|
||||||
|
await testDisplayedMonth(page, `<ion-datetime max="2021-06-30" value="2021-07-01"></ion-datetime>`);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('when both min and max are defined', async ({ page }) => {
|
||||||
|
await testDisplayedMonth(
|
||||||
|
page,
|
||||||
|
`<ion-datetime min="2021-06-01" max="2021-06-30" value="2021-05-01"></ion-datetime>`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { printIonWarning } from '@utils/logging';
|
||||||
|
|
||||||
import type { DatetimeParts } from '../datetime-interface';
|
import type { DatetimeParts } from '../datetime-interface';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -36,3 +38,14 @@ export const isAfter = (baseParts: DatetimeParts, compareParts: DatetimeParts) =
|
|||||||
baseParts.day > compareParts.day!)
|
baseParts.day > compareParts.day!)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const warnIfValueOutOfBounds = (value: DatetimeParts, min: DatetimeParts, max: DatetimeParts) => {
|
||||||
|
if ((min && isBefore(value, min)) || (max && isAfter(value, max))) {
|
||||||
|
printIonWarning(
|
||||||
|
'The value provided to ion-datetime is out of bounds.\n\n' +
|
||||||
|
`Min: ${JSON.stringify(min)}\n` +
|
||||||
|
`Max: ${JSON.stringify(max)}\n` +
|
||||||
|
`Value: ${JSON.stringify(value)}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Reference in New Issue
Block a user