fix(datetime): changing months work if partially visible (#27917)

Issue number: resolves #27913

---------

<!-- 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 determining what the changed month is, we grab the element at the
center of the datetime and then grab the nearest calendar month. This
works fine if the datetime is fully in view, but if the center point is
out of the viewport then this will return `null`. As a result, scrolling
in the datetime will break.

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

- We now check scroll position instead of querying for DOM elements at
coordinates. This allows the view to continue to update even if the
entire calendar body is outside the viewport.

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

Dev build: `7.2.2-dev.11690996559.1019674a`
This commit is contained in:
Liam DeBeasi
2023-08-04 14:41:25 -04:00
committed by GitHub
parent a0e6ac6013
commit eb19c289d6
3 changed files with 17 additions and 22 deletions

View File

@ -883,21 +883,18 @@ export class Datetime implements ComponentInterface {
const getChangedMonth = (parts: DatetimeParts): DatetimeParts | undefined => {
const box = calendarBodyRef.getBoundingClientRect();
const root = this.el!.shadowRoot!;
/**
* Get the element that is in the center of the calendar body.
* This will be an element inside of the active month.
* If the current scroll position is all the way to the left
* then we have scrolled to the previous month.
* Otherwise, assume that we have scrolled to the next
* month. We have a tolerance of 2px to account for
* sub pixel rendering.
*
* Check below the next line ensures that we did not
* swipe and abort (i.e. we swiped but we are still on the current month).
*/
const elementAtCenter = root.elementFromPoint(box.x + box.width / 2, box.y + box.height / 2);
/**
* If there is no element then the
* component may be re-rendering on a slow device.
*/
if (!elementAtCenter) return;
const month = elementAtCenter.closest('.calendar-month');
if (!month) return;
const month = calendarBodyRef.scrollLeft <= 2 ? startMonth : endMonth;
/**
* The edge of the month must be lined up with

View File

@ -301,21 +301,20 @@ configs({ directions: ['ltr'], modes: ['ios'] }).forEach(({ title, config }) =>
<ion-datetime
min="2022-01-15"
value="2022-02-01"
presentation="date"
presentation="month-year"
></ion-datetime>
`,
config
);
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)');
const ionChange = await page.spyOnEvent('ionChange');
await monthYearToggle.click();
await page.waitForChanges();
await page.waitForSelector('.datetime-ready');
await monthColumnItems.nth(0).click(); // switch to January
await page.waitForChanges();
await ionChange.next();
await expect(datetime).toHaveJSProperty('value', '2022-01-15T00:00:00');
});

View File

@ -34,13 +34,14 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
`,
config
);
await page.waitForSelector('.datetime-ready');
const datetime = page.locator('ion-datetime');
const activeDayButton = page.locator('.calendar-day-active');
const monthYearButton = page.locator('.calendar-month-year');
const monthColumn = page.locator('.month-column');
const yearColumn = page.locator('.year-column');
const ionChange = await page.spyOnEvent('ionChange');
await datetime.evaluate((el: HTMLIonDatetimeElement) => (el.value = '2021-10-05'));
@ -49,11 +50,9 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
await page.waitForChanges();
// Select October 2021
// The year will automatically switch to 2021 when selecting 10
await monthColumn.locator('.picker-item[data-value="10"]').click();
await page.waitForChanges();
await yearColumn.locator('.picker-item[data-value="2021"]').click();
await page.waitForChanges();
await ionChange.next();
// Close month/year picker
await monthYearButton.click();