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);
});
});
});