From 0385c0862c98c9387b38d3a4416d74a2cc132ddd Mon Sep 17 00:00:00 2001 From: Amanda Johnston <90629384+amandaejohnston@users.noreply.github.com> Date: Tue, 18 Apr 2023 12:31:47 -0500 Subject: [PATCH] fix(datetime): clamp date between min and max when using month picker (#27185) ## What is the current behavior? When using the dropdown month picker, the value is updated when the month is changed, to follow native behavior. However, because only the month is updated (the day remains the same), it's possible for the newly chosen date to fall outside the min/max bounds of the datetime. For example, if you have a datetime with `min="2021-01-15" value="2021-02-01"`, then use the month picker to switch to January, the new value will be `2021-01-01` which is earlier than the `min`. Issue URL: Resolves #27027 ## What is the new behavior? When updating the `activeParts` in any scenario, the date to set is now clamped between the max and min. ## Does this introduce a breaking change? - [ ] Yes - [x] No ## Other information --- .../datetime/test/minmax/datetime.e2e.ts | 24 +++++++++++++++++++ .../components/datetime/utils/manipulation.ts | 7 +++--- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/core/src/components/datetime/test/minmax/datetime.e2e.ts b/core/src/components/datetime/test/minmax/datetime.e2e.ts index c1133df091..ac05871ed8 100644 --- a/core/src/components/datetime/test/minmax/datetime.e2e.ts +++ b/core/src/components/datetime/test/minmax/datetime.e2e.ts @@ -240,6 +240,7 @@ test.describe('datetime: minmax', () => { skip.rtl(); skip.mode('ios', 'This implementation is the same across modes.'); }); + test('should reset to min time if out of bounds', async ({ page }) => { await page.setContent(` { await expect(datetime).toHaveJSProperty('value', '2022-10-10T08:00:00'); }); + test('should reset to max time if out of bounds', async ({ page }) => { await page.setContent(` { await expect(datetime).toHaveJSProperty('value', '2022-10-10T08:00:00'); }); + + test('should adjust to in-bounds when using month picker', async ({ page }) => { + await page.setContent(` + + `); + + const datetime = page.locator('ion-datetime'); + const monthYearToggle = page.locator('ion-datetime .calendar-month-year'); + const monthColumnItems = page.locator('ion-datetime .month-column .picker-item:not(.picker-item-empty)'); + + await monthYearToggle.click(); + await page.waitForChanges(); + + await monthColumnItems.nth(0).click(); // switch to January + await page.waitForChanges(); + + await expect(datetime).toHaveJSProperty('value', '2022-01-15T00:00:00'); + }); }); test.describe('datetime: confirm button', () => { diff --git a/core/src/components/datetime/utils/manipulation.ts b/core/src/components/datetime/utils/manipulation.ts index 301a28fcaa..0846182f1e 100644 --- a/core/src/components/datetime/utils/manipulation.ts +++ b/core/src/components/datetime/utils/manipulation.ts @@ -2,7 +2,7 @@ import type { DatetimeParts } from '../datetime-interface'; import { isSameDay } from './comparison'; import { getNumDaysInMonth } from './helpers'; -import { parseAmPm } from './parse'; +import { clampDate, parseAmPm } from './parse'; const twoDigit = (val: number | undefined): string => { return ('0' + (val !== undefined ? Math.abs(val) : '0')).slice(-2); @@ -333,7 +333,8 @@ export const calculateHourFromAMPM = (currentParts: DatetimeParts, newAMPM: 'am' /** * Updates parts to ensure that month and day * values are valid. For days that do not exist, - * the closest valid day is used. + * or are outside the min/max bounds, the closest + * valid day is used. */ export const validateParts = ( parts: DatetimeParts, @@ -341,7 +342,7 @@ export const validateParts = ( maxParts?: DatetimeParts ): DatetimeParts => { const { month, day, year } = parts; - const partsCopy = { ...parts }; + const partsCopy = clampDate({ ...parts }, minParts, maxParts); const numDays = getNumDaysInMonth(month, year);