Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(datetime): setting max/min does not increase number of nodes rendered #26065

Merged
merged 8 commits into from
Oct 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 15 additions & 13 deletions core/src/components/datetime/datetime.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { isRTL } from '../../utils/rtl';
import { createColorClasses } from '../../utils/theme';
import type { PickerColumnItem } from '../picker-column-internal/picker-column-internal-interfaces';

import { isSameDay, warnIfValueOutOfBounds } from './utils/comparison';
import { isSameDay, warnIfValueOutOfBounds, isBefore, isAfter } from './utils/comparison';
import {
generateMonths,
getDaysOfMonth,
Expand All @@ -32,7 +32,7 @@ import {
getCombinedDateColumnData,
} from './utils/data';
import { formatValue, getLocalizedTime, getMonthAndDay, getMonthAndYear } from './utils/format';
import { is24Hour, isLocaleDayPeriodRTL, isMonthFirstLocale } from './utils/helpers';
import { is24Hour, isLocaleDayPeriodRTL, isMonthFirstLocale, getNumDaysInMonth } from './utils/helpers';
import {
calculateHourFromAMPM,
convertDataToISO,
Expand Down Expand Up @@ -1400,23 +1400,24 @@ export class Datetime implements ComponentInterface {
* Previous month, current month, and next month
*/
const monthsToRender = generateMonths(workingParts);
const lastMonth = monthsToRender[monthsToRender.length - 1];

/**
* generateMonths returns the day data as well,
* but we do not want the day value to act as a max/min
* on the data we are going to generate.
* Ensure that users can select the entire window of dates.
*/
for (let i = 0; i <= monthsToRender.length - 1; i++) {
monthsToRender[i].day = null;
}
monthsToRender[0].day = 1;
lastMonth.day = getNumDaysInMonth(lastMonth.month, lastMonth.year);

/**
* If developers have provided their own
* min/max values, use that instead. Otherwise,
* fallback to the default range of 3 months.
* Narrow the dates rendered based on min/max dates (if any).
* The `min` date is used if the min is after the generated min month.
* The `max` date is used if the max is before the generated max month.
* This ensures that the sliding window always stays at 3 months
* but still allows future dates to be lazily rendered based on any min/max
* constraints.
*/
const min = minParts || monthsToRender[0];
const max = maxParts || monthsToRender[monthsToRender.length - 1];
const min = minParts !== undefined && isAfter(minParts, monthsToRender[0]) ? minParts : monthsToRender[0];
const max = maxParts !== undefined && isBefore(maxParts, lastMonth) ? maxParts : lastMonth;

const result = getCombinedDateColumnData(
locale,
Expand All @@ -1426,6 +1427,7 @@ export class Datetime implements ComponentInterface {
this.parsedDayValues,
this.parsedMonthValues
);

let items = result.items;
const parts = result.parts;

Expand Down
143 changes: 121 additions & 22 deletions core/src/components/datetime/test/prefer-wheel/datetime.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,37 @@ test.describe('datetime: prefer wheel', () => {
* are rendering quirks on Linux
* if the datetime is too small.
*/
test.describe('datetime: date wheel rendering', () => {
test('should not have visual regressions', async ({ page }) => {
test.describe('datetime: wheel rendering', () => {
test('should not have visual regressions for date wheel', async ({ page }) => {
await page.setContent(`
<ion-datetime size="cover" presentation="date" prefer-wheel="true" value="2019-05-30"></ion-datetime>
`);

expect(await page.screenshot()).toMatchSnapshot(`datetime-wheel-date-diff-${page.getSnapshotSettings()}.png`);
});
test('should not have visual regressions for date-time wheel', async ({ page }) => {
await page.setContent(`
<ion-datetime size="cover" presentation="date-time" prefer-wheel="true" value="2019-05-30T16:30:00"></ion-datetime>
`);

expect(await page.screenshot()).toMatchSnapshot(
`datetime-wheel-date-time-diff-${page.getSnapshotSettings()}.png`
);
});
test('should not have visual regressions for time-date wheel', async ({ page }) => {
await page.setContent(`
<ion-datetime size="cover" presentation="time-date" prefer-wheel="true" value="2019-05-30T16:30:00"></ion-datetime>
`);

expect(await page.screenshot()).toMatchSnapshot(
`datetime-wheel-time-date-diff-${page.getSnapshotSettings()}.png`
);
});
});
test.describe('datetime: date wheel', () => {
test.beforeEach(({ skip }) => {
skip.rtl();
});
test('should respect the min bounds', async ({ page }) => {
await page.setContent(`
<ion-datetime presentation="date" prefer-wheel="true" min="2019-05-05" max="2023-10-01" value="2019-05-30"></ion-datetime>
Expand Down Expand Up @@ -149,15 +172,9 @@ test.describe('datetime: prefer wheel', () => {
});
});
});
test.describe('datetime: date-time wheel rendering', () => {
test('should not have visual regressions', async ({ page }) => {
await page.setContent(`
<ion-datetime size="cover" presentation="date-time" prefer-wheel="true" value="2019-05-30T16:30:00"></ion-datetime>
`);

expect(await page.screenshot()).toMatchSnapshot(
`datetime-wheel-date-time-diff-${page.getSnapshotSettings()}.png`
);
test.describe('datetime: date-time wheel', () => {
test.beforeEach(({ skip }) => {
skip.rtl();
});
test('should respect the min bounds', async ({ page }) => {
await page.setContent(`
Expand Down Expand Up @@ -249,20 +266,58 @@ test.describe('datetime: prefer wheel', () => {

await page.waitForSelector('.datetime-ready');

const dateValues = page.locator('.date-column .picker-item:not(.picker-item-empty)');
const dateColumn = page.locator('.date-column');
const dateValues = dateColumn.locator('.picker-item:not(.picker-item-empty)');

expect(await dateValues.count()).toBe(397);
expect(await dateValues.count()).toBe(90);

/**
* Select 1st item to change the dates rendered
*/
await expect(dateValues.nth(0)).toHaveAttribute('data-value', '2022-1-1');
await dateColumn.evaluate((el: HTMLElement) => (el.scrollTop = 0));
await page.waitForChanges();

await expect(dateValues.nth(0)).toHaveAttribute('data-value', '2021-12-1');
});
});
test.describe('datetime: time-date wheel rendering', () => {
test('should not have visual regressions', async ({ page }) => {
test('should keep sliding window if default window is within min and max constraints', async ({ page }) => {
await page.setContent(`
<ion-datetime size="cover" presentation="time-date" prefer-wheel="true" value="2019-05-30T16:30:00"></ion-datetime>
<ion-datetime
presentation="date-time"
prefer-wheel="true"
value="2022-06-01"
max="2030-01-01"
min="2010-01-01"
></ion-datetime>
`);

expect(await page.screenshot()).toMatchSnapshot(
`datetime-wheel-time-date-diff-${page.getSnapshotSettings()}.png`
);
await page.waitForSelector('.datetime-ready');

const dayValues = page.locator('.date-column .picker-item:not(.picker-item-empty)');

expect(await dayValues.count()).toBe(92);
});
test('should narrow sliding window if default window is not within min and max constraints', async ({ page }) => {
await page.setContent(`
<ion-datetime
presentation="date-time"
prefer-wheel="true"
value="2022-06-01"
max="2022-05-15"
min="2022-05-01"
></ion-datetime>
`);

await page.waitForSelector('.datetime-ready');

const dayValues = page.locator('.date-column .picker-item:not(.picker-item-empty)');

expect(await dayValues.count()).toBe(15);
});
});
test.describe('datetime: time-date wheel', () => {
test.beforeEach(({ skip }) => {
skip.rtl();
});
test('should respect the min bounds', async ({ page }) => {
await page.setContent(`
Expand Down Expand Up @@ -354,9 +409,53 @@ test.describe('datetime: prefer wheel', () => {

await page.waitForSelector('.datetime-ready');

const dateValues = page.locator('.date-column .picker-item:not(.picker-item-empty)');
const dateColumn = page.locator('.date-column');
const dateValues = dateColumn.locator('.picker-item:not(.picker-item-empty)');

expect(await dateValues.count()).toBe(90);

/**
* Select 1st item to change the dates rendered
*/
await expect(dateValues.nth(0)).toHaveAttribute('data-value', '2022-1-1');
await dateColumn.evaluate((el: HTMLElement) => (el.scrollTop = 0));
await page.waitForChanges();

await expect(dateValues.nth(0)).toHaveAttribute('data-value', '2021-12-1');
});
test('should keep sliding window if default window is within min and max constraints', async ({ page }) => {
await page.setContent(`
<ion-datetime
presentation="time-date"
prefer-wheel="true"
value="2022-06-01"
max="2030-01-01"
min="2010-01-01"
></ion-datetime>
`);

await page.waitForSelector('.datetime-ready');

const dayValues = page.locator('.date-column .picker-item:not(.picker-item-empty)');

expect(await dayValues.count()).toBe(92);
});
test('should narrow sliding window if default window is not within min and max constraints', async ({ page }) => {
await page.setContent(`
<ion-datetime
presentation="time-date"
prefer-wheel="true"
value="2022-06-01"
max="2022-05-15"
min="2022-05-01"
></ion-datetime>
`);

await page.waitForSelector('.datetime-ready');

const dayValues = page.locator('.date-column .picker-item:not(.picker-item-empty)');

expect(await dateValues.count()).toBe(397);
expect(await dayValues.count()).toBe(15);
});
});
});