fix(datetime): clamp date between min and max when using month picker (#27185)

<!-- Please refer to our contributing documentation for any questions on
submitting a pull request, or let us know here if you need any help:
https://ionicframework.com/docs/building/contributing -->

<!-- Some docs updates need to be made in the `ionic-docs` repo, in a
separate PR. See
https://github.com/ionic-team/ionic-framework/blob/main/.github/CONTRIBUTING.md#modifying-documentation
for details. -->

<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->

<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->

## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->

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`.

<!-- Issues are required for both bug fixes and features. -->
Issue URL: Resolves #27027


## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

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

<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->


## Other information

<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->
This commit is contained in:
Amanda Johnston
2023-04-18 12:31:47 -05:00
committed by GitHub
parent 76c8b94e2a
commit 0385c0862c
2 changed files with 28 additions and 3 deletions

View File

@ -240,6 +240,7 @@ test.describe('datetime: minmax', () => {
skip.rtl(); skip.rtl();
skip.mode('ios', 'This implementation is the same across modes.'); skip.mode('ios', 'This implementation is the same across modes.');
}); });
test('should reset to min time if out of bounds', async ({ page }) => { test('should reset to min time if out of bounds', async ({ page }) => {
await page.setContent(` await page.setContent(`
<ion-datetime <ion-datetime
@ -259,6 +260,7 @@ test.describe('datetime: minmax', () => {
await expect(datetime).toHaveJSProperty('value', '2022-10-10T08:00:00'); await expect(datetime).toHaveJSProperty('value', '2022-10-10T08:00:00');
}); });
test('should reset to max time if out of bounds', async ({ page }) => { test('should reset to max time if out of bounds', async ({ page }) => {
await page.setContent(` await page.setContent(`
<ion-datetime <ion-datetime
@ -278,6 +280,28 @@ test.describe('datetime: minmax', () => {
await expect(datetime).toHaveJSProperty('value', '2022-10-10T08:00:00'); 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(`
<ion-datetime
min="2022-01-15"
value="2022-02-01"
presentation="date"
></ion-datetime>
`);
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', () => { test.describe('datetime: confirm button', () => {

View File

@ -2,7 +2,7 @@ import type { DatetimeParts } from '../datetime-interface';
import { isSameDay } from './comparison'; import { isSameDay } from './comparison';
import { getNumDaysInMonth } from './helpers'; import { getNumDaysInMonth } from './helpers';
import { parseAmPm } from './parse'; import { clampDate, parseAmPm } from './parse';
const twoDigit = (val: number | undefined): string => { const twoDigit = (val: number | undefined): string => {
return ('0' + (val !== undefined ? Math.abs(val) : '0')).slice(-2); 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 * Updates parts to ensure that month and day
* values are valid. For days that do not exist, * 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 = ( export const validateParts = (
parts: DatetimeParts, parts: DatetimeParts,
@ -341,7 +342,7 @@ export const validateParts = (
maxParts?: DatetimeParts maxParts?: DatetimeParts
): DatetimeParts => { ): DatetimeParts => {
const { month, day, year } = parts; const { month, day, year } = parts;
const partsCopy = { ...parts }; const partsCopy = clampDate({ ...parts }, minParts, maxParts);
const numDays = getNumDaysInMonth(month, year); const numDays = getNumDaysInMonth(month, year);