From a5d178f4c03a0ad2501095afe1f75914b0462ae1 Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Mon, 10 Oct 2022 12:43:43 -0500 Subject: [PATCH] fix(datetime): setting max/min does not increase number of nodes rendered (#26065) resolves #26059 --- core/src/components/datetime/datetime.tsx | 28 ++-- .../test/prefer-wheel/datetime.e2e.ts | 143 +++++++++++++++--- 2 files changed, 136 insertions(+), 35 deletions(-) diff --git a/core/src/components/datetime/datetime.tsx b/core/src/components/datetime/datetime.tsx index 23bc63fee8..a78bf569b8 100644 --- a/core/src/components/datetime/datetime.tsx +++ b/core/src/components/datetime/datetime.tsx @@ -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, @@ -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, @@ -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, @@ -1426,6 +1427,7 @@ export class Datetime implements ComponentInterface { this.parsedDayValues, this.parsedMonthValues ); + let items = result.items; const parts = result.parts; diff --git a/core/src/components/datetime/test/prefer-wheel/datetime.e2e.ts b/core/src/components/datetime/test/prefer-wheel/datetime.e2e.ts index a1c5c2aec9..a3c8aacf74 100644 --- a/core/src/components/datetime/test/prefer-wheel/datetime.e2e.ts +++ b/core/src/components/datetime/test/prefer-wheel/datetime.e2e.ts @@ -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(` `); 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(` + + `); + + 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(` + + `); + + 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(` @@ -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(` - - `); - - 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(` @@ -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(` - + `); - 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(` + + `); + + 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(` @@ -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(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('should keep sliding window if default window is within min and max constraints', async ({ page }) => { + await page.setContent(` + + `); + + 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(` + + `); + + await page.waitForSelector('.datetime-ready'); + + const dayValues = page.locator('.date-column .picker-item:not(.picker-item-empty)'); + + expect(await dayValues.count()).toBe(15); }); }); });